edf183bc896b959f35181ff1e2cc32519b7fe17e
configuration/convertELBLogToApacheFormat
| ... | ... | @@ -3,10 +3,11 @@ PREFIX=$1 |
| 3 | 3 | shift |
| 4 | 4 | for i in $*; do |
| 5 | 5 | if [ ${i: -3} == ".gz" ]; then |
| 6 | - gzip -cd $i |
|
| 6 | + gzip -cd $i |
|
| 7 | 7 | else |
| 8 | 8 | cat $i |
| 9 | - fi | sed -e 's/^\([^T]*\)T\([^.]*\)[^ ]* [^ ]* \([^:]*\):[^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* \([^ ]*\) \([^ ]*\) [^ ]* \(\"[^"]*\"\) \(\"[^"]*\"\).*$/'$PREFIX' \3 - - [\1:\2 +0000] \6 \4 \5 "http:\/\/'$PREFIX'" \7/' | |
|
| 9 | + fi | iconv -f ISO-8859-1 -t UTF8 | |
|
| 10 | + sed -e 's/^\([^T]*\)T\([^.]*\)[^ ]* [^ ]* \([^:]*\):[^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* \([^ ]*\) \([^ ]*\) [^ ]* \(\"[^"]*\"\) \(\"[^"]*\"\).*$/'$PREFIX' \3 - - [\1:\2 +0000] \6 \4 \5 "http:\/\/'$PREFIX'" \7/' | |
|
| 10 | 11 | sed -e 's/\[\([0-9]*\)-01-\([0-9]*\):/\[\2\/Jan\/\1:/' | |
| 11 | 12 | sed -e 's/\[\([0-9]*\)-02-\([0-9]*\):/\[\2\/Feb\/\1:/' | |
| 12 | 13 | sed -e 's/\[\([0-9]*\)-03-\([0-9]*\):/\[\2\/Mar\/\1:/' | |
configuration/sailing
| ... | ... | @@ -27,17 +27,20 @@ start_servers() { |
| 27 | 27 | MEMORY_PER_INSTANCE_IN_MB=`cat /proc/meminfo | grep MemTotal | awk '{printf("%i\n", ($2 / 1024 * 0.75 - 1500) / '$NUMBER_OF_INSTANCES' );}'` |
| 28 | 28 | echo "Using ${MEMORY_PER_INSTANCE_IN_MB}MB as default heap size per instance." |
| 29 | 29 | for conf in $JAVA_START_INSTANCES; do |
| 30 | - echo "Checking for amazon update..." |
|
| 30 | + echo "Checking for amazon update..." >>/var/log/sailing.out |
|
| 31 | 31 | echo "MEMORY=\"${MEMORY_PER_INSTANCE_IN_MB}m\"" >>$SERVERS_DIR/$conf/env.sh |
| 32 | 32 | su - sailing -c "cd $SERVERS_DIR/$conf && $GIT_REPOSITORY/java/target/refreshInstance.sh auto-install" 2>>/var/log/sailing.err >>/var/log/sailing.out |
| 33 | 33 | ( |
| 34 | 34 | # execute env.sh in a subshell which now has the same set of variables that the server will see |
| 35 | 35 | source $SERVERS_DIR/$conf/env.sh |
| 36 | - echo "Starting Java server $conf" |
|
| 36 | + echo "Starting Java server \"$conf\"" >>/var/log/sailing.out |
|
| 37 | 37 | su - sailing -c "cd $SERVERS_DIR/$conf && ./start" 2>>/var/log/sailing.err >>/var/log/sailing.out |
| 38 | 38 | server_name="`echo $SERVER_NAME | tr [A-Z] [a-z]`" |
| 39 | - echo "Appending macro invocation to $APACHE_CONFIR_DIR/001-events.conf to map ${server_name}.sapsailing.com to event with ID $EVENT_ID with server running on local port $SERVER_PORT..." >>/var/log/sailing.out |
|
| 40 | - echo "Use Event $server_name.sapsailing.com \"$EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf |
|
| 39 | + echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map ${server_name}.sapsailing.com to event with ID $EVENT_ID with server running on local port $SERVER_PORT..." >>/var/log/sailing.out |
|
| 40 | + echo "Use Event ${server_name}.sapsailing.com \"$EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf |
|
| 41 | + HTTP_LOGROTATE=/etc/logrotate.d/httpd |
|
| 42 | + echo "Patching $HTTP_LOGROTATE so that old logs go to /var/log/old/$SERVER_NAME/$INSTANCE_IP4" >>/var/log/sailing.out |
|
| 43 | + sed -i -e "s/\/var\/log\/old\/\([^/]*\)\/\([^/ ]*\)/\/var\/log\/old\/$SERVER_NAME\/$INSTANCE_IP4/" $HTTP_LOGROTATE |
|
| 41 | 44 | # terminating the subshell will forget all the variable assignments brought in by env.sh, clearing for the next server instance |
| 42 | 45 | ) |
| 43 | 46 | RETVAL=$? |
configuration/syncEC2ElbLogs
| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | +#!/bin/sh |
|
| 2 | +/usr/bin/s3cmd -c /root/.s3cfg sync s3://sapsailing-access-logs/elb-access-logs/ /var/log/old/elb-access-logs/ >/var/log/last-elb-access-logs-sync.out 2>/var/log/last-elb-access-logs-sync.err |
configuration/unique_ips_per_referrer
| ... | ... | @@ -16,17 +16,19 @@ mkdir -p "$STATS" |
| 16 | 16 | # A sample line: |
| 17 | 17 | # 505Worlds2012.sapsailing.com 66.249.73.53 - - [12/Jan/2014:03:33:11 +0000] "GET /robots.txt HTTP/1.1" 404 238 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" |
| 18 | 18 | |
| 19 | +echo Starting "$0" at `date` on file set "$*" |
|
| 20 | + |
|
| 19 | 21 | for i in $*; do |
| 20 | 22 | grep -q "^$i\$" $VISITED_FILES |
| 21 | 23 | if [ "$?" = "0" ]; then |
| 22 | - echo "Already visited $i; ignoring (edit $VISITED_FILES to change this)." >&2 |
|
| 24 | + echo "Already visited $i; ignoring (edit $VISITED_FILES to change this)." |
|
| 23 | 25 | else |
| 24 | - echo "Analyzing log file $i" >&2 |
|
| 26 | + echo "Analyzing log file $i" |
|
| 25 | 27 | if [ ${i: -3} == ".gz" ]; then |
| 26 | 28 | gzip -cd $i |
| 27 | 29 | else |
| 28 | 30 | cat $i |
| 29 | - fi | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^"]*\" [^ ]* [^ ]* \"[^"]*\" \"\([^"]*\)\"/\1 \2 \5 \7/' | while read referrer hit; do |
|
| 31 | + fi | iconv -f ISO-8859-1 -t UTF8 | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^"]*\" [^ ]* [^ ]* \"[^"]*\" \"\([^"]*\)\"/\1 \2 \5 \7/' | while read referrer hit; do |
|
| 30 | 32 | echo "$hit" >>${STATS}/${referrer}.ips |
| 31 | 33 | done |
| 32 | 34 | echo "$i" >>$VISITED_FILES |
| ... | ... | @@ -37,7 +39,7 @@ for i in ${STATS}/*.ips; do |
| 37 | 39 | cat $i | sort -u | wc | awk '{ print $1; }' |
| 38 | 40 | # TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files |
| 39 | 41 | done | tee $STATS/unique-ips-days-useragents-per-event |
| 40 | -echo "Done. Wrote results to $STATS/unique-ips-days-useragents-per-event" |
|
| 42 | +echo "Wrote total results to $STATS/unique-ips-days-useragents-per-event" |
|
| 41 | 43 | |
| 42 | 44 | |
| 43 | 45 | # Now filter and group by month |
| ... | ... | @@ -48,5 +50,6 @@ for month in `cat $MONTHS`; do |
| 48 | 50 | cat $i | grep "^[^ ]* [0-9]*/$month .*" | sort -u | wc | awk '{ print $1; }' |
| 49 | 51 | # TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files |
| 50 | 52 | done | tee $STATS/unique-ips-days-useragents-per-event-$month |
| 51 | - echo "Done. Wrote results to $STATS/unique-ips-days-useragents-per-event-$month" |
|
| 53 | + echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-$month" |
|
| 52 | 54 | done |
| 55 | +echo "Done at `date`." |
configuration/unique_ips_per_referrer_generate_month_results_only
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +#!/bin/bash |
|
| 2 | + |
|
| 3 | +CACHE=/var/log/old/cache/unique-ips-per-referrer |
|
| 4 | +VISITED_FILES=$CACHE/visited |
|
| 5 | +STATS=$CACHE/stats |
|
| 6 | +MONTHS=$STATS/months |
|
| 7 | + |
|
| 8 | +for month in `cat $MONTHS`; do |
|
| 9 | + for i in ${STATS}/*.ips; do |
|
| 10 | + echo -n "`basename $i .ips` " |
|
| 11 | + cat $i | grep "^[^ ]* [0-9]*/$month .*" | sort -u | wc | awk '{ print $1; }' |
|
| 12 | + # TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files |
|
| 13 | + done | tee $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -` |
|
| 14 | + echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-$month" |
|
| 15 | +done |
|
| 16 | +echo "Done." |
configuration/unique_ips_per_referrer_generate_results_only
| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | +#!/bin/bash |
|
| 2 | + |
|
| 3 | +CACHE=/var/log/old/cache/unique-ips-per-referrer |
|
| 4 | +VISITED_FILES=$CACHE/visited |
|
| 5 | +STATS=$CACHE/stats |
|
| 6 | +MONTHS=$STATS/months |
|
| 7 | + |
|
| 8 | +for i in ${STATS}/*.ips; do |
|
| 9 | + echo -n "`basename $i .ips` " |
|
| 10 | + cat $i | sort -u | wc | awk '{ print $1; }' |
|
| 11 | + # TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files |
|
| 12 | +done | tee $STATS/unique-ips-days-useragents-per-event |
|
| 13 | +echo "Wrote total results to $STATS/unique-ips-days-useragents-per-event" |
|
| 14 | + |
|
| 15 | + |
|
| 16 | +# Now filter and group by month |
|
| 17 | +cat ${STATS}/*.ips | awk '{ print $2; }' | sed -e 's/^[0-9]*\///' | sort -u >$MONTHS |
|
| 18 | +for month in `cat $MONTHS`; do |
|
| 19 | + for i in ${STATS}/*.ips; do |
|
| 20 | + echo -n "`basename $i .ips` " |
|
| 21 | + cat $i | grep "^[^ ]* [0-9]*/$month .*" | sort -u | wc | awk '{ print $1; }' |
|
| 22 | + # TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files |
|
| 23 | + done | tee $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -` |
|
| 24 | + echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-$month" |
|
| 25 | +done |
|
| 26 | +echo "Done." |
home.md
| ... | ... | @@ -32,6 +32,7 @@ SAP is at the center of today’s technology revolution, developing innovations |
| 32 | 32 | * [[Operating Igtimi WindBots/windbot-operations]] |
| 33 | 33 | * [[Monitoring Apache and RabbitMQ|wiki/monitoring-apache-and-rabbitmq]] |
| 34 | 34 | * [[JMX Support|wiki/jmx]] |
| 35 | + * [[Log File Analysis|wiki/log-file-analysis]] |
|
| 35 | 36 | * Information for Developers |
| 36 | 37 | * [[OnBoarding Information|wiki/onboarding]] |
| 37 | 38 | * [[Cook Book|wiki/cook-book]] |
java/com.sap.sailing.dashboards.gwt/pom.xml
| ... | ... | @@ -11,19 +11,6 @@ |
| 11 | 11 | <artifactId>com.sap.sailing.dashboards.gwt</artifactId> |
| 12 | 12 | <packaging>eclipse-plugin</packaging> |
| 13 | 13 | |
| 14 | - <repositories> |
|
| 15 | - <repository> |
|
| 16 | - <id>sonatype</id> |
|
| 17 | - <url>http://oss.sonatype.org/content/repositories/snapshots</url> |
|
| 18 | - <snapshots> |
|
| 19 | - <enabled>true</enabled> |
|
| 20 | - </snapshots> |
|
| 21 | - <releases> |
|
| 22 | - <enabled>false</enabled> |
|
| 23 | - </releases> |
|
| 24 | - </repository> |
|
| 25 | - </repositories> |
|
| 26 | - |
|
| 27 | 14 | <dependencies> |
| 28 | 15 | <dependency> |
| 29 | 16 | <groupId>javax.validation</groupId> |
java/com.sap.sailing.domain.common/pom.xml
| ... | ... | @@ -1,40 +1,40 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
| 4 | - <modelVersion>4.0.0</modelVersion>
|
|
| 5 | - <parent>
|
|
| 6 | - <artifactId>root</artifactId>
|
|
| 7 | - <groupId>com.sap.sailing</groupId>
|
|
| 8 | - <version>1.0.0-SNAPSHOT</version>
|
|
| 9 | - </parent>
|
|
| 10 | - <artifactId>com.sap.sailing.domain.common</artifactId>
|
|
| 11 | - <packaging>eclipse-plugin</packaging>
|
|
| 12 | -
|
|
| 13 | - <build>
|
|
| 14 | - <plugins>
|
|
| 15 | - <plugin>
|
|
| 16 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 17 | - <artifactId>tycho-compiler-plugin</artifactId>
|
|
| 18 | - <version>${tycho-version}</version>
|
|
| 19 | - <configuration>
|
|
| 20 | - <source>1.7</source>
|
|
| 21 | - <target>1.7</target>
|
|
| 22 | - </configuration>
|
|
| 23 | - </plugin>
|
|
| 24 | - <plugin>
|
|
| 25 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 26 | - <artifactId>tycho-source-plugin</artifactId>
|
|
| 27 | - <version>${tycho-version}</version>
|
|
| 28 | - <executions>
|
|
| 29 | - <execution>
|
|
| 30 | - <id>plugin-source</id>
|
|
| 31 | - <phase>generate-sources</phase>
|
|
| 32 | - <goals>
|
|
| 33 | - <goal>plugin-source</goal>
|
|
| 34 | - </goals>
|
|
| 35 | - </execution>
|
|
| 36 | - </executions>
|
|
| 37 | - </plugin>
|
|
| 38 | - </plugins>
|
|
| 39 | - </build>
|
|
| 40 | -</project>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>com.sap.sailing.domain.common</artifactId> |
|
| 11 | + <packaging>eclipse-plugin</packaging> |
|
| 12 | + |
|
| 13 | + <build> |
|
| 14 | + <plugins> |
|
| 15 | + <plugin> |
|
| 16 | + <groupId>org.eclipse.tycho</groupId> |
|
| 17 | + <artifactId>tycho-compiler-plugin</artifactId> |
|
| 18 | + <version>${tycho-version}</version> |
|
| 19 | + <configuration> |
|
| 20 | + <source>1.7</source> |
|
| 21 | + <target>1.7</target> |
|
| 22 | + </configuration> |
|
| 23 | + </plugin> |
|
| 24 | + <plugin> |
|
| 25 | + <groupId>org.eclipse.tycho</groupId> |
|
| 26 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 27 | + <version>${tycho-version}</version> |
|
| 28 | + <executions> |
|
| 29 | + <execution> |
|
| 30 | + <id>plugin-source</id> |
|
| 31 | + <phase>generate-sources</phase> |
|
| 32 | + <goals> |
|
| 33 | + <goal>plugin-source</goal> |
|
| 34 | + </goals> |
|
| 35 | + </execution> |
|
| 36 | + </executions> |
|
| 37 | + </plugin> |
|
| 38 | + </plugins> |
|
| 39 | + </build> |
|
| 40 | +</project> |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/CompetitorDTOImpl.java
| ... | ... | @@ -145,7 +145,7 @@ public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serial |
| 145 | 145 | |
| 146 | 146 | @Override |
| 147 | 147 | public String getSailID() { |
| 148 | - return boat.getSailId(); |
|
| 148 | + return boat==null?null:boat.getSailId(); |
|
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | @Override |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/IncrementalLeaderboardDTO.java
| ... | ... | @@ -9,10 +9,12 @@ import java.util.HashSet; |
| 9 | 9 | import java.util.Iterator; |
| 10 | 10 | import java.util.List; |
| 11 | 11 | import java.util.Map; |
| 12 | +import java.util.Map.Entry; |
|
| 12 | 13 | import java.util.Set; |
| 13 | 14 | |
| 14 | 15 | import com.sap.sse.common.Cloner; |
| 15 | 16 | import com.sap.sse.common.Util; |
| 17 | +import com.sap.sse.common.Util.Pair; |
|
| 16 | 18 | |
| 17 | 19 | /** |
| 18 | 20 | * Reduces the transmission size of a {@link LeaderboardDTO} by comparing this object to a previous version of |
| ... | ... | @@ -174,16 +176,20 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme |
| 174 | 176 | } |
| 175 | 177 | |
| 176 | 178 | /** |
| 177 | - * @param previousVersion needed because after serialization/deserialization, the transient {@link #previousLeaderboard} will be <code>null</code> |
|
| 179 | + * @param previousVersion |
|
| 180 | + * needed because after serialization/deserialization, the transient {@link #previousLeaderboard} |
|
| 181 | + * will be <code>null</code>. |
|
| 182 | + * @return a map whose keys are the {@link CompetitorDTO#getIdAsString()} of the competitors for which the value |
|
| 183 | + * tells the set of keys that are unchanged |
|
| 178 | 184 | */ |
| 179 | - public Set<com.sap.sse.common.Util.Pair<CompetitorDTO, K>> getAllUnchangedCompetitorsAndKeys(LeaderboardDTO previousVersion) { |
|
| 180 | - Set<com.sap.sse.common.Util.Pair<CompetitorDTO, K>> result = new HashSet<com.sap.sse.common.Util.Pair<CompetitorDTO,K>>(); |
|
| 185 | + public Map<String, Set<K>> getAllUnchangedCompetitorIdsAsStringAndKeys(LeaderboardDTO previousVersion) { |
|
| 186 | + Map<String, Set<K>> result = new HashMap<>(); |
|
| 181 | 187 | for (Map.Entry<K, long[]> raceColumnNameAndBitSet : unchanged.entrySet()) { |
| 182 | 188 | final long[] bitset = raceColumnNameAndBitSet.getValue(); |
| 183 | 189 | if (bitset == null) { |
| 184 | 190 | // this means that all entries for the column are unchanged for all competitors |
| 185 | 191 | for (CompetitorDTO competitor : previousVersion.competitors) { |
| 186 | - result.add(new com.sap.sse.common.Util.Pair<CompetitorDTO, K>(competitor, raceColumnNameAndBitSet.getKey())); |
|
| 192 | + Util.add(result, competitor.getIdAsString(), raceColumnNameAndBitSet.getKey()); |
|
| 187 | 193 | } |
| 188 | 194 | } else { |
| 189 | 195 | int competitorNumber = 0; |
| ... | ... | @@ -191,7 +197,7 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme |
| 191 | 197 | long bitValue = 1; |
| 192 | 198 | for (int bit=0; bit<Long.SIZE; bit++) { |
| 193 | 199 | if ((bitset[arrayIndex] & bitValue) != 0) { |
| 194 | - result.add(new com.sap.sse.common.Util.Pair<CompetitorDTO, K>(previousVersion.competitors.get(competitorNumber), raceColumnNameAndBitSet.getKey())); |
|
| 200 | + Util.add(result, previousVersion.competitors.get(competitorNumber).getIdAsString(), raceColumnNameAndBitSet.getKey()); |
|
| 195 | 201 | } |
| 196 | 202 | bitValue <<= 1; |
| 197 | 203 | competitorNumber++; |
| ... | ... | @@ -321,6 +327,14 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme |
| 321 | 327 | } |
| 322 | 328 | |
| 323 | 329 | private void applyThisToPreviousVersionByUpdatingThis(LeaderboardDTO previousVersion) { |
| 330 | + // As a performance improvement for the GWT-compiled version of this class, try to avoid key types |
|
| 331 | + // other than strings when there is a map or set to be implemented that has a lot of strain on the |
|
| 332 | + // put / add / contains methods. For this, we use the competitor's getIdAsString() result that |
|
| 333 | + // identifies them reasonably well. |
|
| 334 | + final Map<String, CompetitorDTO> competitorsOfPreviousVersionByIdAsString = new HashMap<>(); |
|
| 335 | + for (final CompetitorDTO c : previousVersion.competitors) { |
|
| 336 | + competitorsOfPreviousVersionByIdAsString.put(c.getIdAsString(), c); |
|
| 337 | + } |
|
| 324 | 338 | if (this.updatedFromPreviousVersionWithId != null) { |
| 325 | 339 | if (!this.updatedFromPreviousVersionWithId.equals(previousVersion.getId())) { |
| 326 | 340 | throw new IllegalStateException("This incremental leaderboard DTO was already applied to a different previous version. It cannot be applied multiple times."); |
| ... | ... | @@ -410,62 +424,66 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme |
| 410 | 424 | row.competitor = expandedCompetitor; |
| 411 | 425 | rows.put(expandedCompetitor, row); |
| 412 | 426 | } |
| 413 | - final Set<CompetitorDTO> rowsUnchangedForCompetitors = new HashSet<CompetitorDTO>(); |
|
| 427 | + final Set<String> rowsUnchangedForCompetitorsWithIdAsString = new HashSet<>(); |
|
| 414 | 428 | if (rowsUnchanged != null) { |
| 415 | - for (com.sap.sse.common.Util.Pair<CompetitorDTO, Void> rowUnchanged : rowsUnchanged.getAllUnchangedCompetitorsAndKeys(previousVersion)) { |
|
| 416 | - rowsUnchangedForCompetitors.add(rowUnchanged.getA()); |
|
| 417 | - rows.put(rowUnchanged.getA(), previousVersion.rows.get(rowUnchanged.getA())); |
|
| 429 | + for (Entry<String, Set<Void>> rowUnchanged : rowsUnchanged.getAllUnchangedCompetitorIdsAsStringAndKeys(previousVersion).entrySet()) { |
|
| 430 | + rowsUnchangedForCompetitorsWithIdAsString.add(rowUnchanged.getKey()); |
|
| 431 | + final CompetitorDTO previousCompetitor = competitorsOfPreviousVersionByIdAsString.get(rowUnchanged.getKey()); |
|
| 432 | + rows.put(previousCompetitor, previousVersion.rows.get(previousCompetitor)); |
|
| 418 | 433 | } |
| 419 | 434 | } |
| 420 | - final Set<com.sap.sse.common.Util.Pair<CompetitorDTO, String>> allUnchangedLeaderboardEntriesAsCompetitorsAndColumnNames = |
|
| 421 | - unchangedLeaderboardEntries == null ? new HashSet<com.sap.sse.common.Util.Pair<CompetitorDTO,String>>() : |
|
| 422 | - unchangedLeaderboardEntries.getAllUnchangedCompetitorsAndKeys(previousVersion); |
|
| 435 | + final Map<String, Set<String>> allUnchangedLeaderboardEntriesAsCompetitorIdsAsStringAndColumnNames = |
|
| 436 | + unchangedLeaderboardEntries == null ? new HashMap<String, Set<String>>() : |
|
| 437 | + unchangedLeaderboardEntries.getAllUnchangedCompetitorIdsAsStringAndKeys(previousVersion); |
|
| 423 | 438 | if (unchangedLeaderboardEntries != null) { |
| 424 | - for (com.sap.sse.common.Util.Pair<CompetitorDTO, String> competitorAndColumnName : allUnchangedLeaderboardEntriesAsCompetitorsAndColumnNames) { |
|
| 425 | - CompetitorDTO previousCompetitor = competitorAndColumnName.getA(); |
|
| 426 | - if (!rowsUnchangedForCompetitors.contains(previousCompetitor)) { // only care if not the entire row was marked unchanged |
|
| 427 | - LeaderboardEntryDTO previousEntry = previousVersion.rows.get(previousCompetitor).fieldsByRaceColumnName.get( |
|
| 428 | - competitorAndColumnName.getB()); |
|
| 429 | - final LeaderboardRowDTO row = rows.get(previousCompetitor); |
|
| 430 | - if (row != null) { // may be null if the competitor disappeared, e.g., because of suppression |
|
| 431 | - row.fieldsByRaceColumnName.put(competitorAndColumnName.getB(), previousEntry); |
|
| 439 | + for (Entry<String, Set<String>> competitorAndColumnNames : allUnchangedLeaderboardEntriesAsCompetitorIdsAsStringAndColumnNames.entrySet()) { |
|
| 440 | + CompetitorDTO previousCompetitor = competitorsOfPreviousVersionByIdAsString.get(competitorAndColumnNames.getKey()); |
|
| 441 | + for (final String columnName : competitorAndColumnNames.getValue()) { |
|
| 442 | + if (!rowsUnchangedForCompetitorsWithIdAsString.contains(competitorAndColumnNames.getKey())) { // only care if not the entire row was marked unchanged |
|
| 443 | + LeaderboardEntryDTO previousEntry = previousVersion.rows.get(previousCompetitor).fieldsByRaceColumnName.get(columnName); |
|
| 444 | + final LeaderboardRowDTO row = rows.get(previousCompetitor); |
|
| 445 | + if (row != null) { // may be null if the competitor disappeared, e.g., because of suppression |
|
| 446 | + row.fieldsByRaceColumnName.put(columnName, previousEntry); |
|
| 447 | + } |
|
| 432 | 448 | } |
| 433 | 449 | } |
| 434 | 450 | } |
| 435 | 451 | } |
| 436 | 452 | if (legDetailsUnchanged != null) { |
| 437 | - for (com.sap.sse.common.Util.Pair<CompetitorDTO, com.sap.sse.common.Util.Pair<String, Integer>> competitorInPreviosAndColumnNameAndLegDetailsIndex : legDetailsUnchanged |
|
| 438 | - .getAllUnchangedCompetitorsAndKeys(previousVersion)) { |
|
| 439 | - CompetitorDTO previousCompetitor = competitorInPreviosAndColumnNameAndLegDetailsIndex.getA(); |
|
| 440 | - final String raceColumnName = competitorInPreviosAndColumnNameAndLegDetailsIndex.getB().getA(); |
|
| 441 | - // if it's already clear that the entire LeaderboardEntryDTO was unchanged, the entry in legDetailsUnchanged was |
|
| 442 | - // merely a hint for column compression within legDetailsUnchanged and doesn't need to be handled here |
|
| 443 | - if (!allUnchangedLeaderboardEntriesAsCompetitorsAndColumnNames |
|
| 444 | - .contains(new com.sap.sse.common.Util.Pair<CompetitorDTO, String>(previousCompetitor, raceColumnName))) { |
|
| 445 | - final LeaderboardRowDTO leaderboardRowDTO = rows.get(previousCompetitor); |
|
| 446 | - LeaderboardEntryDTO leaderboardEntry = leaderboardRowDTO == null ? null |
|
| 447 | - : leaderboardRowDTO.fieldsByRaceColumnName.get(raceColumnName); |
|
| 448 | - if (leaderboardEntry != null) { |
|
| 449 | - final LeaderboardRowDTO previousLeaderboardRowDTO = previousVersion.rows |
|
| 450 | - .get(previousCompetitor); |
|
| 451 | - final LeaderboardEntryDTO previousLeaderboardEntryDTO = previousLeaderboardRowDTO == null ? null |
|
| 452 | - : previousLeaderboardRowDTO.fieldsByRaceColumnName.get(raceColumnName); |
|
| 453 | - final List<LegEntryDTO> previousLegDetails = previousLeaderboardEntryDTO == null ? null |
|
| 454 | - : previousLeaderboardEntryDTO.legDetails; |
|
| 455 | - if (previousLegDetails == null) { |
|
| 456 | - // the leg index can only be null if the previous leg details are null |
|
| 457 | - leaderboardEntry.legDetails = null; |
|
| 458 | - } else { |
|
| 459 | - // here, the leg index cannot be null |
|
| 460 | - if (leaderboardEntry.legDetails == null) { |
|
| 461 | - leaderboardEntry.legDetails = new ArrayList<LegEntryDTO>(); |
|
| 453 | + for (Entry<String, Set<Pair<String, Integer>>> competitorInPreviosAndColumnNameAndLegDetailsIndex : |
|
| 454 | + legDetailsUnchanged.getAllUnchangedCompetitorIdsAsStringAndKeys(previousVersion).entrySet()) { |
|
| 455 | + CompetitorDTO previousCompetitor = competitorsOfPreviousVersionByIdAsString.get(competitorInPreviosAndColumnNameAndLegDetailsIndex.getKey()); |
|
| 456 | + for (final Pair<String, Integer> columnNameAndLegDetailsIndex : competitorInPreviosAndColumnNameAndLegDetailsIndex.getValue()) { |
|
| 457 | + final String raceColumnName = columnNameAndLegDetailsIndex.getA(); |
|
| 458 | + // if it's already clear that the entire LeaderboardEntryDTO was unchanged, the entry in legDetailsUnchanged was |
|
| 459 | + // merely a hint for column compression within legDetailsUnchanged and doesn't need to be handled here |
|
| 460 | + final Set<String> unchangedRaceColumnNamesForCompetitor; |
|
| 461 | + if ((unchangedRaceColumnNamesForCompetitor=allUnchangedLeaderboardEntriesAsCompetitorIdsAsStringAndColumnNames.get(competitorInPreviosAndColumnNameAndLegDetailsIndex.getKey())) == null |
|
| 462 | + || !unchangedRaceColumnNamesForCompetitor.contains(raceColumnName)) { |
|
| 463 | + final LeaderboardRowDTO leaderboardRowDTO = rows.get(previousCompetitor); |
|
| 464 | + LeaderboardEntryDTO leaderboardEntry = leaderboardRowDTO == null ? null |
|
| 465 | + : leaderboardRowDTO.fieldsByRaceColumnName.get(raceColumnName); |
|
| 466 | + if (leaderboardEntry != null) { |
|
| 467 | + final LeaderboardRowDTO previousLeaderboardRowDTO = previousVersion.rows.get(previousCompetitor); |
|
| 468 | + final LeaderboardEntryDTO previousLeaderboardEntryDTO = previousLeaderboardRowDTO == null ? null |
|
| 469 | + : previousLeaderboardRowDTO.fieldsByRaceColumnName.get(raceColumnName); |
|
| 470 | + final List<LegEntryDTO> previousLegDetails = previousLeaderboardEntryDTO == null ? null |
|
| 471 | + : previousLeaderboardEntryDTO.legDetails; |
|
| 472 | + if (previousLegDetails == null) { |
|
| 473 | + // the leg index can only be null if the previous leg details are null |
|
| 474 | + leaderboardEntry.legDetails = null; |
|
| 475 | + } else { |
|
| 476 | + // here, the leg index cannot be null |
|
| 477 | + if (leaderboardEntry.legDetails == null) { |
|
| 478 | + leaderboardEntry.legDetails = new ArrayList<LegEntryDTO>(); |
|
| 479 | + } |
|
| 480 | + final Integer pos = columnNameAndLegDetailsIndex.getB(); |
|
| 481 | + ensureSize(leaderboardEntry.legDetails, pos + 1); |
|
| 482 | + leaderboardEntry.legDetails.set(pos, previousLegDetails.get(pos)); |
|
| 462 | 483 | } |
| 463 | - final Integer pos = competitorInPreviosAndColumnNameAndLegDetailsIndex.getB().getB(); |
|
| 464 | - ensureSize(leaderboardEntry.legDetails, pos + 1); |
|
| 465 | - leaderboardEntry.legDetails.set(pos, previousLegDetails.get(pos)); |
|
| 466 | 484 | } |
| 467 | 485 | } |
| 468 | - } |
|
| 486 | + } |
|
| 469 | 487 | } |
| 470 | 488 | } |
| 471 | 489 | } |
java/com.sap.sailing.domain.persistence/META-INF/MANIFEST.MF
| ... | ... | @@ -14,7 +14,8 @@ Require-Bundle: com.sap.sse.mongodb, |
| 14 | 14 | com.sap.sailing.server.gateway.serialization, |
| 15 | 15 | com.sap.sse.common, |
| 16 | 16 | com.sap.sse, |
| 17 | - com.sap.sailing.server.gateway.serialization.shared.android |
|
| 17 | + com.sap.sailing.server.gateway.serialization.shared.android, |
|
| 18 | + com.sap.sse.shared.android |
|
| 18 | 19 | Export-Package: com.sap.sailing.domain.persistence, |
| 19 | 20 | com.sap.sailing.domain.persistence.impl; |
| 20 | 21 | x-friends:="com.sap.sailing.domain.persistence.test, |
java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
| ... | ... | @@ -224,11 +224,11 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl; |
| 224 | 224 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 225 | 225 | import com.sap.sse.common.impl.RGBColor; |
| 226 | 226 | import com.sap.sse.common.impl.TimeRangeImpl; |
| 227 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 228 | -import com.sap.sse.common.media.ImageDescriptorImpl; |
|
| 229 | 227 | import com.sap.sse.common.media.MimeType; |
| 230 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 231 | -import com.sap.sse.common.media.VideoDescriptorImpl; |
|
| 228 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 229 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 230 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 231 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 232 | 232 | |
| 233 | 233 | public class DomainObjectFactoryImpl implements DomainObjectFactory { |
| 234 | 234 | private static final Logger logger = Logger.getLogger(DomainObjectFactoryImpl.class.getName()); |
| ... | ... | @@ -638,11 +638,18 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { |
| 638 | 638 | // deprecated style: a DBObject whose keys are the escaped competitor names |
| 639 | 639 | // new style: a BasicDBList whose entries are DBObjects with COMPETITOR_ID and COMPETITOR_DISPLAY_NAME fields |
| 640 | 640 | if (competitorDisplayNames != null) { |
| 641 | - for (Object o : (BasicDBList) competitorDisplayNames) { |
|
| 642 | - DBObject competitorDisplayName = (DBObject) o; |
|
| 643 | - final Serializable competitorId = (Serializable) competitorDisplayName.get(FieldNames.COMPETITOR_ID.name()); |
|
| 644 | - final String displayName = (String) competitorDisplayName.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); |
|
| 645 | - correctionsToUpdate.setDisplayNameByID(competitorId, displayName); |
|
| 641 | + if (competitorDisplayNames instanceof BasicDBList) { |
|
| 642 | + for (Object o : (BasicDBList) competitorDisplayNames) { |
|
| 643 | + DBObject competitorDisplayName = (DBObject) o; |
|
| 644 | + final Serializable competitorId = (Serializable) competitorDisplayName.get(FieldNames.COMPETITOR_ID.name()); |
|
| 645 | + final String displayName = (String) competitorDisplayName.get(FieldNames.COMPETITOR_DISPLAY_NAME.name()); |
|
| 646 | + correctionsToUpdate.setDisplayNameByID(competitorId, displayName); |
|
| 647 | + } |
|
| 648 | + } else { |
|
| 649 | + logger.severe("Deprecated, now unreadable format of the "+FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name() |
|
| 650 | + +" field for leaderboard "+dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name())+ |
|
| 651 | + ". You will have to update the competitor display names manually: "+ |
|
| 652 | + competitorDisplayNames); |
|
| 646 | 653 | } |
| 647 | 654 | } |
| 648 | 655 | } |
java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
| ... | ... | @@ -1,1533 +1,1533 @@ |
| 1 | -package com.sap.sailing.domain.persistence.impl;
|
|
| 2 | -
|
|
| 3 | -import java.io.Serializable;
|
|
| 4 | -import java.net.URL;
|
|
| 5 | -import java.util.List;
|
|
| 6 | -import java.util.Map.Entry;
|
|
| 7 | -import java.util.logging.Level;
|
|
| 8 | -import java.util.logging.Logger;
|
|
| 9 | -
|
|
| 10 | -import org.bson.types.ObjectId;
|
|
| 11 | -import org.json.simple.JSONObject;
|
|
| 12 | -
|
|
| 13 | -import com.mongodb.BasicDBList;
|
|
| 14 | -import com.mongodb.BasicDBObject;
|
|
| 15 | -import com.mongodb.BasicDBObjectBuilder;
|
|
| 16 | -import com.mongodb.DB;
|
|
| 17 | -import com.mongodb.DBCollection;
|
|
| 18 | -import com.mongodb.DBObject;
|
|
| 19 | -import com.mongodb.WriteConcern;
|
|
| 20 | -import com.mongodb.util.JSON;
|
|
| 21 | -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
|
| 22 | -import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
|
|
| 23 | -import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
|
|
| 24 | -import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent;
|
|
| 25 | -import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
|
|
| 26 | -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
|
| 27 | -import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
|
|
| 28 | -import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent;
|
|
| 29 | -import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
|
|
| 30 | -import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
|
|
| 31 | -import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent;
|
|
| 32 | -import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
|
| 33 | -import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
|
| 34 | -import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
|
| 35 | -import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
|
| 36 | -import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
|
| 37 | -import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
|
| 38 | -import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
|
| 39 | -import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
|
| 40 | -import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
|
|
| 41 | -import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
|
|
| 42 | -import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
|
|
| 43 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
|
|
| 44 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
|
|
| 45 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
|
|
| 46 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
|
|
| 47 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
|
|
| 48 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
|
|
| 49 | -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
|
|
| 50 | -import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
|
|
| 51 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
|
|
| 52 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
|
|
| 53 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
|
|
| 54 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
|
|
| 55 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
|
|
| 56 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
|
|
| 57 | -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent;
|
|
| 58 | -import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
|
|
| 59 | -import com.sap.sailing.domain.base.Competitor;
|
|
| 60 | -import com.sap.sailing.domain.base.ControlPoint;
|
|
| 61 | -import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
|
|
| 62 | -import com.sap.sailing.domain.base.CourseArea;
|
|
| 63 | -import com.sap.sailing.domain.base.CourseBase;
|
|
| 64 | -import com.sap.sailing.domain.base.Event;
|
|
| 65 | -import com.sap.sailing.domain.base.Fleet;
|
|
| 66 | -import com.sap.sailing.domain.base.Mark;
|
|
| 67 | -import com.sap.sailing.domain.base.RaceColumn;
|
|
| 68 | -import com.sap.sailing.domain.base.RaceDefinition;
|
|
| 69 | -import com.sap.sailing.domain.base.Regatta;
|
|
| 70 | -import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
|
| 71 | -import com.sap.sailing.domain.base.SailingServerConfiguration;
|
|
| 72 | -import com.sap.sailing.domain.base.Series;
|
|
| 73 | -import com.sap.sailing.domain.base.Venue;
|
|
| 74 | -import com.sap.sailing.domain.base.Waypoint;
|
|
| 75 | -import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
|
|
| 76 | -import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
|
|
| 77 | -import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
|
| 78 | -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti;
|
|
| 79 | -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
|
|
| 80 | -import com.sap.sailing.domain.base.impl.FleetImpl;
|
|
| 81 | -import com.sap.sailing.domain.common.Bearing;
|
|
| 82 | -import com.sap.sailing.domain.common.MaxPointsReason;
|
|
| 83 | -import com.sap.sailing.domain.common.PassingInstruction;
|
|
| 84 | -import com.sap.sailing.domain.common.Positioned;
|
|
| 85 | -import com.sap.sailing.domain.common.RaceIdentifier;
|
|
| 86 | -import com.sap.sailing.domain.common.Speed;
|
|
| 87 | -import com.sap.sailing.domain.common.SpeedWithBearing;
|
|
| 88 | -import com.sap.sailing.domain.common.Wind;
|
|
| 89 | -import com.sap.sailing.domain.common.WindSource;
|
|
| 90 | -import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
|
| 91 | -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
|
| 92 | -import com.sap.sailing.domain.leaderboard.Leaderboard;
|
|
| 93 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
|
| 94 | -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
|
| 95 | -import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
|
| 96 | -import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
|
| 97 | -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
|
| 98 | -import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
|
| 99 | -import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
|
| 100 | -import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
|
|
| 101 | -import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
|
| 102 | -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
|
| 103 | -import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
|
| 104 | -import com.sap.sailing.domain.tracking.TrackedRace;
|
|
| 105 | -import com.sap.sailing.domain.tracking.TrackedRegatta;
|
|
| 106 | -import com.sap.sailing.domain.tracking.WindTrack;
|
|
| 107 | -import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
|
| 108 | -import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
|
|
| 109 | -import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer;
|
|
| 110 | -import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer;
|
|
| 111 | -import com.sap.sse.common.Duration;
|
|
| 112 | -import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
|
| 113 | -import com.sap.sse.common.TimePoint;
|
|
| 114 | -import com.sap.sse.common.TimeRange;
|
|
| 115 | -import com.sap.sse.common.Timed;
|
|
| 116 | -import com.sap.sse.common.TypeBasedServiceFinder;
|
|
| 117 | -import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
|
| 118 | -import com.sap.sse.common.Util;
|
|
| 119 | -import com.sap.sse.common.impl.MillisecondsTimePoint;
|
|
| 120 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 121 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 122 | -
|
|
| 123 | -public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
|
| 124 | - private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName());
|
|
| 125 | - private final DB database;
|
|
| 126 | - private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create();
|
|
| 127 | - private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
|
|
| 128 | -
|
|
| 129 | - /**
|
|
| 130 | - * Uses <code>null</code> for the device type service finder and hence will be unable to store device identifiers.
|
|
| 131 | - * Use this constructor only for testing purposes or in cases where there will happen absolutely no access to
|
|
| 132 | - * {@link DeviceIdentifier} objects.
|
|
| 133 | - */
|
|
| 134 | - public MongoObjectFactoryImpl(DB database) {
|
|
| 135 | - this(database, /* deviceTypeServiceFinder */ null);
|
|
| 136 | - }
|
|
| 137 | -
|
|
| 138 | - public MongoObjectFactoryImpl(DB database, TypeBasedServiceFinderFactory serviceFinderFactory) {
|
|
| 139 | - this.database = database;
|
|
| 140 | - if (serviceFinderFactory != null) {
|
|
| 141 | - this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class);
|
|
| 142 | - this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler());
|
|
| 143 | - } else {
|
|
| 144 | - this.deviceIdentifierServiceFinder = null;
|
|
| 145 | - }
|
|
| 146 | - }
|
|
| 147 | -
|
|
| 148 | - @Override
|
|
| 149 | - public DB getDatabase() {
|
|
| 150 | - return database;
|
|
| 151 | - }
|
|
| 152 | -
|
|
| 153 | - public DBObject storeWind(Wind wind) {
|
|
| 154 | - DBObject result = new BasicDBObject();
|
|
| 155 | - storePositioned(wind, result);
|
|
| 156 | - storeTimed(wind, result);
|
|
| 157 | - storeSpeedWithBearing(wind, result);
|
|
| 158 | - return result;
|
|
| 159 | - }
|
|
| 160 | -
|
|
| 161 | - public static void storeTimePoint(TimePoint timePoint, DBObject result, String fieldName) {
|
|
| 162 | - if (timePoint != null) {
|
|
| 163 | - result.put(fieldName, timePoint.asMillis());
|
|
| 164 | - }
|
|
| 165 | - }
|
|
| 166 | -
|
|
| 167 | - public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) {
|
|
| 168 | - storeTimePoint(timePoint, result, field.name());
|
|
| 169 | - }
|
|
| 170 | -
|
|
| 171 | - public static void storeTimeRange(TimeRange timeRange, DBObject result, FieldNames field) {
|
|
| 172 | - if (timeRange != null) {
|
|
| 173 | - DBObject timeRangeObj = new BasicDBObject();
|
|
| 174 | - storeTimePoint(timeRange.from(), timeRangeObj, FieldNames.FROM_MILLIS);
|
|
| 175 | - storeTimePoint(timeRange.to(), timeRangeObj, FieldNames.TO_MILLIS);
|
|
| 176 | - result.put(field.name(), timeRangeObj);
|
|
| 177 | - }
|
|
| 178 | - }
|
|
| 179 | -
|
|
| 180 | - public void storeTimed(Timed timed, DBObject result) {
|
|
| 181 | - if (timed.getTimePoint() != null) {
|
|
| 182 | - storeTimePoint(timed.getTimePoint(), result, FieldNames.TIME_AS_MILLIS);
|
|
| 183 | - }
|
|
| 184 | - }
|
|
| 185 | -
|
|
| 186 | - public void storeSpeedWithBearing(SpeedWithBearing speedWithBearing, DBObject result) {
|
|
| 187 | - storeSpeed(speedWithBearing, result);
|
|
| 188 | - storeBearing(speedWithBearing.getBearing(), result);
|
|
| 189 | -
|
|
| 190 | - }
|
|
| 191 | -
|
|
| 192 | - public void storeBearing(Bearing bearing, DBObject result) {
|
|
| 193 | - result.put(FieldNames.DEGREE_BEARING.name(), bearing.getDegrees());
|
|
| 194 | - }
|
|
| 195 | -
|
|
| 196 | - public void storeSpeed(Speed speed, DBObject result) {
|
|
| 197 | - result.put(FieldNames.KNOT_SPEED.name(), speed.getKnots());
|
|
| 198 | - }
|
|
| 199 | -
|
|
| 200 | - public void storePositioned(Positioned positioned, DBObject result) {
|
|
| 201 | - if (positioned.getPosition() != null) {
|
|
| 202 | - result.put(FieldNames.LAT_DEG.name(), positioned.getPosition().getLatDeg());
|
|
| 203 | - result.put(FieldNames.LNG_DEG.name(), positioned.getPosition().getLngDeg());
|
|
| 204 | - }
|
|
| 205 | - }
|
|
| 206 | -
|
|
| 207 | - @Override
|
|
| 208 | - public void addWindTrackDumper(TrackedRegatta trackedRegatta, TrackedRace trackedRace, WindSource windSource) {
|
|
| 209 | - WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
|
|
| 210 | - windTrack.addListener(new MongoWindListener(trackedRace, trackedRegatta.getRegatta().getName(), windSource, this, database));
|
|
| 211 | - }
|
|
| 212 | -
|
|
| 213 | - public DBCollection getWindTrackCollection() {
|
|
| 214 | - DBCollection result = database.getCollection(CollectionNames.WIND_TRACKS.name());
|
|
| 215 | - result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), null));
|
|
| 216 | - return result;
|
|
| 217 | - }
|
|
| 218 | -
|
|
| 219 | - public DBCollection getGPSFixCollection() {
|
|
| 220 | - DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name());
|
|
| 221 | - DBObject index = new BasicDBObject();
|
|
| 222 | - index.put(FieldNames.DEVICE_ID.name(), null);
|
|
| 223 | - index.put(FieldNames.TIME_AS_MILLIS.name(), null);
|
|
| 224 | - gpsFixCollection.createIndex(index);
|
|
| 225 | - return gpsFixCollection;
|
|
| 226 | - }
|
|
| 227 | -
|
|
| 228 | - public DBCollection getGPSFixMetadataCollection() {
|
|
| 229 | - DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name());
|
|
| 230 | - DBObject index = new BasicDBObject();
|
|
| 231 | - index.put(FieldNames.DEVICE_ID.name(), null);
|
|
| 232 | - collection.createIndex(index);
|
|
| 233 | - return collection;
|
|
| 234 | - }
|
|
| 235 | -
|
|
| 236 | - /**
|
|
| 237 | - * @param regattaName
|
|
| 238 | - * the regatta name is stored only for human readability purposes because a time stamp may be a bit unhandy for
|
|
| 239 | - * identifying where the wind fix was collected
|
|
| 240 | - */
|
|
| 241 | - public DBObject storeWindTrackEntry(RaceDefinition race, String regattaName, WindSource windSource, Wind wind) {
|
|
| 242 | - BasicDBObject result = new BasicDBObject();
|
|
| 243 | - result.put(FieldNames.RACE_ID.name(), race.getId());
|
|
| 244 | - result.put(FieldNames.REGATTA_NAME.name(), regattaName);
|
|
| 245 | - result.put(FieldNames.WIND_SOURCE_NAME.name(), windSource.name());
|
|
| 246 | - if (windSource.getId() != null) {
|
|
| 247 | - result.put(FieldNames.WIND_SOURCE_ID.name(), windSource.getId());
|
|
| 248 | - }
|
|
| 249 | - result.put(FieldNames.WIND.name(), storeWind(wind));
|
|
| 250 | - return result;
|
|
| 251 | - }
|
|
| 252 | -
|
|
| 253 | - private void storeRaceIdentifiers(RaceColumn raceColumn, DBObject dbObject) {
|
|
| 254 | - BasicDBObject raceIdentifiersPerFleet = new BasicDBObject();
|
|
| 255 | - for (Fleet fleet : raceColumn.getFleets()) {
|
|
| 256 | - RaceIdentifier raceIdentifier = raceColumn.getRaceIdentifier(fleet);
|
|
| 257 | - if (raceIdentifier != null) {
|
|
| 258 | - DBObject raceIdentifierForFleet = new BasicDBObject();
|
|
| 259 | - storeRaceIdentifier(raceIdentifierForFleet, raceIdentifier);
|
|
| 260 | - raceIdentifiersPerFleet.put(MongoUtils.escapeDollarAndDot(fleet.getName()), raceIdentifierForFleet);
|
|
| 261 | - }
|
|
| 262 | - }
|
|
| 263 | - dbObject.put(FieldNames.RACE_IDENTIFIERS.name(), raceIdentifiersPerFleet);
|
|
| 264 | - }
|
|
| 265 | -
|
|
| 266 | - private void storeRaceIdentifier(DBObject dbObject, RaceIdentifier raceIdentifier) {
|
|
| 267 | - if (raceIdentifier != null) {
|
|
| 268 | - dbObject.put(FieldNames.EVENT_NAME.name(), raceIdentifier.getRegattaName());
|
|
| 269 | - dbObject.put(FieldNames.RACE_NAME.name(), raceIdentifier.getRaceName());
|
|
| 270 | - }
|
|
| 271 | - }
|
|
| 272 | -
|
|
| 273 | - @Override
|
|
| 274 | - public void storeLeaderboard(Leaderboard leaderboard) {
|
|
| 275 | - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
|
| 276 | - try {
|
|
| 277 | - leaderboardCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), 1));
|
|
| 278 | - } catch (NullPointerException npe) {
|
|
| 279 | - // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE
|
|
| 280 | - logger.log(Level.SEVERE, "storeLeaderboard", npe);
|
|
| 281 | - }
|
|
| 282 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
|
|
| 283 | - BasicDBObject dbLeaderboard = new BasicDBObject();
|
|
| 284 | - dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
|
|
| 285 | - if (leaderboard.getDisplayName() != null) {
|
|
| 286 | - dbLeaderboard.put(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), leaderboard.getDisplayName());
|
|
| 287 | - }
|
|
| 288 | - BasicDBList dbSuppressedCompetitorIds = new BasicDBList();
|
|
| 289 | - for (Competitor suppressedCompetitor : leaderboard.getSuppressedCompetitors()) {
|
|
| 290 | - dbSuppressedCompetitorIds.add(suppressedCompetitor.getId());
|
|
| 291 | - }
|
|
| 292 | - dbLeaderboard.put(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name(), dbSuppressedCompetitorIds);
|
|
| 293 | - if (leaderboard instanceof FlexibleLeaderboard) {
|
|
| 294 | - storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard, dbLeaderboard);
|
|
| 295 | - } else if (leaderboard instanceof RegattaLeaderboard) {
|
|
| 296 | - storeRegattaLeaderboard((RegattaLeaderboard) leaderboard, dbLeaderboard);
|
|
| 297 | - } else {
|
|
| 298 | - // at least store the scoring scheme
|
|
| 299 | - dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name());
|
|
| 300 | - }
|
|
| 301 | - if (leaderboard.getDefaultCourseArea() != null) {
|
|
| 302 | - dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), leaderboard.getDefaultCourseArea().getId().toString());
|
|
| 303 | - } else {
|
|
| 304 | - dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), null);
|
|
| 305 | - }
|
|
| 306 | - storeColumnFactors(leaderboard, dbLeaderboard);
|
|
| 307 | - storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard);
|
|
| 308 | - leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 309 | - }
|
|
| 310 | -
|
|
| 311 | - private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) {
|
|
| 312 | - DBObject raceColumnFactors = new BasicDBObject();
|
|
| 313 | - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
|
| 314 | - Double explicitFactor = raceColumn.getExplicitFactor();
|
|
| 315 | - if (explicitFactor != null) {
|
|
| 316 | - raceColumnFactors.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), explicitFactor);
|
|
| 317 | - }
|
|
| 318 | - }
|
|
| 319 | - dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMN_FACTORS.name(), raceColumnFactors);
|
|
| 320 | - }
|
|
| 321 | -
|
|
| 322 | - private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) {
|
|
| 323 | - dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName());
|
|
| 324 | - }
|
|
| 325 | -
|
|
| 326 | - private void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard, BasicDBObject dbLeaderboard) {
|
|
| 327 | - BasicDBList dbRaceColumns = new BasicDBList();
|
|
| 328 | - dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name());
|
|
| 329 | - dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns);
|
|
| 330 | - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
|
| 331 | - BasicDBObject dbRaceColumn = storeRaceColumn(raceColumn);
|
|
| 332 | - dbRaceColumns.add(dbRaceColumn);
|
|
| 333 | - }
|
|
| 334 | - }
|
|
| 335 | -
|
|
| 336 | - private void storeLeaderboardCorrectionsAndDiscards(Leaderboard leaderboard, BasicDBObject dbLeaderboard) {
|
|
| 337 | - if (leaderboard.hasCarriedPoints()) {
|
|
| 338 | - BasicDBList dbCarriedPoints = new BasicDBList();
|
|
| 339 | - dbLeaderboard.put(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name(), dbCarriedPoints);
|
|
| 340 | - for (Entry<Competitor, Double> competitorWithCarriedPoints : leaderboard
|
|
| 341 | - .getCompetitorsForWhichThereAreCarriedPoints().entrySet()) {
|
|
| 342 | - double carriedPoints = competitorWithCarriedPoints.getValue();
|
|
| 343 | - Competitor competitor = competitorWithCarriedPoints.getKey();
|
|
| 344 | - DBObject dbCarriedPointsForCompetitor = new BasicDBObject();
|
|
| 345 | - dbCarriedPointsForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId());
|
|
| 346 | - dbCarriedPointsForCompetitor.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), carriedPoints);
|
|
| 347 | - dbCarriedPoints.add(dbCarriedPointsForCompetitor);
|
|
| 348 | - }
|
|
| 349 | - }
|
|
| 350 | - BasicDBObject dbScoreCorrections = new BasicDBObject();
|
|
| 351 | - storeScoreCorrections(leaderboard, dbScoreCorrections);
|
|
| 352 | - dbLeaderboard.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections);
|
|
| 353 | - final ResultDiscardingRule resultDiscardingRule = leaderboard.getResultDiscardingRule();
|
|
| 354 | - storeResultDiscardingRule(dbLeaderboard, resultDiscardingRule, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS);
|
|
| 355 | - BasicDBList competitorDisplayNames = new BasicDBList();
|
|
| 356 | - for (Competitor competitor : leaderboard.getCompetitors()) {
|
|
| 357 | - String displayNameForCompetitor = leaderboard.getDisplayName(competitor);
|
|
| 358 | - if (displayNameForCompetitor != null) {
|
|
| 359 | - DBObject dbDisplayName = new BasicDBObject();
|
|
| 360 | - dbDisplayName.put(FieldNames.COMPETITOR_ID.name(), competitor.getId());
|
|
| 361 | - dbDisplayName.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), displayNameForCompetitor);
|
|
| 362 | - competitorDisplayNames.add(dbDisplayName);
|
|
| 363 | - }
|
|
| 364 | - }
|
|
| 365 | - dbLeaderboard.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames);
|
|
| 366 | - }
|
|
| 367 | -
|
|
| 368 | - /**
|
|
| 369 | - * Stores the result discarding rule to <code>dbObject</code>'s field identified by <code>field</code> if the result discarding
|
|
| 370 | - * rule is not <code>null</code> and is of type {@link ThresholdBasedResultDiscardingRule}. Otherwise, it is assumed that the
|
|
| 371 | - * result discarding rule is otherwise implicitly obtained, e.g., from a definition of a regatta with its series, stored elsewhere.
|
|
| 372 | - */
|
|
| 373 | - private void storeResultDiscardingRule(DBObject dbObject,
|
|
| 374 | - final ResultDiscardingRule resultDiscardingRule, FieldNames field) {
|
|
| 375 | - if (resultDiscardingRule != null && resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) {
|
|
| 376 | - BasicDBList dbResultDiscardingThresholds = new BasicDBList();
|
|
| 377 | - for (int threshold : ((ThresholdBasedResultDiscardingRule) resultDiscardingRule).getDiscardIndexResultsStartingWithHowManyRaces()) {
|
|
| 378 | - dbResultDiscardingThresholds.add(threshold);
|
|
| 379 | - }
|
|
| 380 | - dbObject.put(field.name(), dbResultDiscardingThresholds);
|
|
| 381 | - }
|
|
| 382 | - }
|
|
| 383 | -
|
|
| 384 | - private BasicDBObject storeRaceColumn(RaceColumn raceColumn) {
|
|
| 385 | - BasicDBObject dbRaceColumn = new BasicDBObject();
|
|
| 386 | - dbRaceColumn.put(FieldNames.LEADERBOARD_COLUMN_NAME.name(), raceColumn.getName());
|
|
| 387 | - dbRaceColumn.put(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name(), raceColumn.isMedalRace());
|
|
| 388 | - storeRaceIdentifiers(raceColumn, dbRaceColumn);
|
|
| 389 | - return dbRaceColumn;
|
|
| 390 | - }
|
|
| 391 | -
|
|
| 392 | - private void storeScoreCorrections(Leaderboard leaderboard, BasicDBObject dbScoreCorrections) {
|
|
| 393 | - TimePoint now = MillisecondsTimePoint.now();
|
|
| 394 | - SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
|
| 395 | - for (RaceColumn raceColumn : scoreCorrection.getRaceColumnsThatHaveCorrections()) {
|
|
| 396 | - BasicDBList dbCorrectionForRace = new BasicDBList();
|
|
| 397 | - for (Competitor competitor : scoreCorrection.getCompetitorsThatHaveCorrectionsIn(raceColumn)) {
|
|
| 398 | - // TODO bug 655: make score corrections time dependent
|
|
| 399 | - if (scoreCorrection.isScoreCorrected(competitor, raceColumn, now)) {
|
|
| 400 | - BasicDBObject dbCorrectionForCompetitor = new BasicDBObject();
|
|
| 401 | - dbCorrectionForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId());
|
|
| 402 | - MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn, now);
|
|
| 403 | - if (maxPointsReason != MaxPointsReason.NONE) {
|
|
| 404 | - dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(),
|
|
| 405 | - maxPointsReason.name());
|
|
| 406 | - }
|
|
| 407 | - Double explicitScoreCorrection = scoreCorrection
|
|
| 408 | - .getExplicitScoreCorrection(competitor, raceColumn);
|
|
| 409 | - if (explicitScoreCorrection != null) {
|
|
| 410 | - dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_CORRECTED_SCORE.name(),
|
|
| 411 | - explicitScoreCorrection);
|
|
| 412 | - }
|
|
| 413 | - dbCorrectionForRace.add(dbCorrectionForCompetitor);
|
|
| 414 | - }
|
|
| 415 | - }
|
|
| 416 | - if (!dbCorrectionForRace.isEmpty()) {
|
|
| 417 | - // using the column name as the key for the score corrections requires re-writing the score corrections
|
|
| 418 | - // of a meta-leaderboard if the name of one of its leaderboards changes
|
|
| 419 | - dbScoreCorrections.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), dbCorrectionForRace);
|
|
| 420 | - }
|
|
| 421 | - }
|
|
| 422 | - final TimePoint timePointOfLastCorrectionsValidity = scoreCorrection.getTimePointOfLastCorrectionsValidity();
|
|
| 423 | - if (timePointOfLastCorrectionsValidity != null) {
|
|
| 424 | - dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name(), timePointOfLastCorrectionsValidity.asMillis());
|
|
| 425 | - }
|
|
| 426 | - if (scoreCorrection.getComment() != null) {
|
|
| 427 | - dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), scoreCorrection.getComment());
|
|
| 428 | - }
|
|
| 429 | - }
|
|
| 430 | -
|
|
| 431 | - @Override
|
|
| 432 | - public void removeLeaderboard(String leaderboardName) {
|
|
| 433 | - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
|
| 434 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboardName);
|
|
| 435 | - leaderboardCollection.remove(query);
|
|
| 436 | - }
|
|
| 437 | -
|
|
| 438 | - @Override
|
|
| 439 | - public void renameLeaderboard(String oldName, String newName) {
|
|
| 440 | - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
|
| 441 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), oldName);
|
|
| 442 | - BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), newName));
|
|
| 443 | - leaderboardCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 444 | - }
|
|
| 445 | -
|
|
| 446 | - @Override
|
|
| 447 | - public void storeLeaderboardGroup(LeaderboardGroup leaderboardGroup) {
|
|
| 448 | - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
|
|
| 449 | - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
|
| 450 | -
|
|
| 451 | - try {
|
|
| 452 | - leaderboardGroupCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), 1));
|
|
| 453 | - } catch (NullPointerException npe) {
|
|
| 454 | - // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE
|
|
| 455 | - logger.log(Level.SEVERE, "storeLeaderboardGroup", npe);
|
|
| 456 | - }
|
|
| 457 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName());
|
|
| 458 | - BasicDBObject dbLeaderboardGroup = new BasicDBObject();
|
|
| 459 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), leaderboardGroup.getId());
|
|
| 460 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName());
|
|
| 461 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name(), leaderboardGroup.getDescription());
|
|
| 462 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name(), leaderboardGroup.getDisplayName());
|
|
| 463 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name(), leaderboardGroup.isDisplayGroupsInReverseOrder());
|
|
| 464 | - final Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard();
|
|
| 465 | - if (overallLeaderboard != null) {
|
|
| 466 | - BasicDBObject overallLeaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), overallLeaderboard.getName());
|
|
| 467 | - DBObject dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery);
|
|
| 468 | - if (dbOverallLeaderboard == null) {
|
|
| 469 | - storeLeaderboard(overallLeaderboard);
|
|
| 470 | - dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery);
|
|
| 471 | - }
|
|
| 472 | - ObjectId dbOverallLeaderboardId = (ObjectId) dbOverallLeaderboard.get("_id");
|
|
| 473 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), dbOverallLeaderboardId);
|
|
| 474 | - }
|
|
| 475 | - BasicDBList dbLeaderboardIds = new BasicDBList();
|
|
| 476 | - for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
|
| 477 | - BasicDBObject leaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
|
|
| 478 | - DBObject dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery);
|
|
| 479 | - if (dbLeaderboard == null) {
|
|
| 480 | - storeLeaderboard(leaderboard);
|
|
| 481 | - dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery);
|
|
| 482 | - }
|
|
| 483 | - ObjectId dbLeaderboardId = (ObjectId) dbLeaderboard.get("_id");
|
|
| 484 | - dbLeaderboardIds.add(dbLeaderboardId);
|
|
| 485 | - }
|
|
| 486 | - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), dbLeaderboardIds);
|
|
| 487 | - leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false, WriteConcern.SAFE);
|
|
| 488 | - }
|
|
| 489 | -
|
|
| 490 | - @Override
|
|
| 491 | - public void removeLeaderboardGroup(String groupName) {
|
|
| 492 | - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
|
|
| 493 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), groupName);
|
|
| 494 | - leaderboardGroupCollection.remove(query);
|
|
| 495 | - }
|
|
| 496 | -
|
|
| 497 | - @Override
|
|
| 498 | - public void renameLeaderboardGroup(String oldName, String newName) {
|
|
| 499 | - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
|
|
| 500 | - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), oldName);
|
|
| 501 | - BasicDBObject update = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), newName));
|
|
| 502 | - leaderboardGroupCollection.update(query, update, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 503 | - }
|
|
| 504 | -
|
|
| 505 | - @Override
|
|
| 506 | - public void storeServerConfiguration(SailingServerConfiguration serverConfiguration) {
|
|
| 507 | - DBCollection serverCollection = database.getCollection(CollectionNames.SERVER_CONFIGURATION.name());
|
|
| 508 | - DBObject newServerConfig = new BasicDBObject();
|
|
| 509 | - newServerConfig.put(FieldNames.SERVER_IS_STANDALONE.name(), serverConfiguration.isStandaloneServer());
|
|
| 510 | - DBObject currentServerConfig = serverCollection.findOne();
|
|
| 511 | - if(currentServerConfig != null) {
|
|
| 512 | - serverCollection.update(currentServerConfig, newServerConfig, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 513 | - } else {
|
|
| 514 | - serverCollection.save(newServerConfig);
|
|
| 515 | - }
|
|
| 516 | - }
|
|
| 517 | -
|
|
| 518 | - @Override
|
|
| 519 | - public void storeSailingServer(RemoteSailingServerReference server) {
|
|
| 520 | - DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name());
|
|
| 521 | - serverCollection.createIndex(new BasicDBObject(FieldNames.SERVER_NAME.name(), 1));
|
|
| 522 | - DBObject query = new BasicDBObject();
|
|
| 523 | - query.put(FieldNames.SERVER_NAME.name(), server.getName());
|
|
| 524 | - DBObject serverDBObject = new BasicDBObject();
|
|
| 525 | - serverDBObject.put(FieldNames.SERVER_NAME.name(), server.getName());
|
|
| 526 | - serverDBObject.put(FieldNames.SERVER_URL.name(), server.getURL().toExternalForm());
|
|
| 527 | - serverCollection.update(query, serverDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 528 | - }
|
|
| 529 | -
|
|
| 530 | - @Override
|
|
| 531 | - public void removeSailingServer(String name) {
|
|
| 532 | - DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name());
|
|
| 533 | - BasicDBObject query = new BasicDBObject(FieldNames.SERVER_NAME.name(), name);
|
|
| 534 | - serverCollection.remove(query);
|
|
| 535 | - }
|
|
| 536 | -
|
|
| 537 | - /**
|
|
| 538 | - * StoreEvent() uses some deprecated methods of event to keep backward compatibility.
|
|
| 539 | - */
|
|
| 540 | - @SuppressWarnings("deprecation")
|
|
| 541 | - @Override
|
|
| 542 | - public void storeEvent(Event event) {
|
|
| 543 | - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name());
|
|
| 544 | - eventCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1));
|
|
| 545 | - DBObject query = new BasicDBObject();
|
|
| 546 | - query.put(FieldNames.EVENT_ID.name(), event.getId());
|
|
| 547 | - DBObject eventDBObject = new BasicDBObject();
|
|
| 548 | - eventDBObject.put(FieldNames.EVENT_NAME.name(), event.getName());
|
|
| 549 | - eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription());
|
|
| 550 | - eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId());
|
|
| 551 | - eventDBObject.put(FieldNames.EVENT_LOGO_IMAGE_URL.name(), event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null);
|
|
| 552 | - eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null);
|
|
| 553 | - eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name(), event.getSailorsInfoWebsiteURL() != null ? event.getSailorsInfoWebsiteURL().toString() : null);
|
|
| 554 | - storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE);
|
|
| 555 | - storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE);
|
|
| 556 | - eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic());
|
|
| 557 | - DBObject venueDBObject = getVenueAsDBObject(event.getVenue());
|
|
| 558 | - eventDBObject.put(FieldNames.VENUE.name(), venueDBObject);
|
|
| 559 | - BasicDBList imageURLs = new BasicDBList();
|
|
| 560 | - for (URL imageURL : event.getImageURLs()) {
|
|
| 561 | - imageURLs.add(imageURL.toString());
|
|
| 562 | - }
|
|
| 563 | - eventDBObject.put(FieldNames.EVENT_IMAGE_URLS.name(), imageURLs);
|
|
| 564 | - BasicDBList videoURLs = new BasicDBList();
|
|
| 565 | - for (URL videoURL : event.getVideoURLs()) {
|
|
| 566 | - videoURLs.add(videoURL.toString());
|
|
| 567 | - }
|
|
| 568 | - eventDBObject.put(FieldNames.EVENT_VIDEO_URLS.name(), videoURLs);
|
|
| 569 | - BasicDBList sponsorImageURLs = new BasicDBList();
|
|
| 570 | - for (URL sponsorImageURL : event.getSponsorImageURLs()) {
|
|
| 571 | - sponsorImageURLs.add(sponsorImageURL.toString());
|
|
| 572 | - }
|
|
| 573 | - eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs);
|
|
| 574 | - BasicDBList images = new BasicDBList();
|
|
| 575 | - for (ImageDescriptor image : event.getImages()) {
|
|
| 576 | - DBObject imageObject = createImageObject(image);
|
|
| 577 | - images.add(imageObject);
|
|
| 578 | - }
|
|
| 579 | - eventDBObject.put(FieldNames.EVENT_IMAGES.name(), images);
|
|
| 580 | - BasicDBList videos = new BasicDBList();
|
|
| 581 | - for (VideoDescriptor video: event.getVideos()) {
|
|
| 582 | - DBObject videoObject = createVideoObject(video);
|
|
| 583 | - videos.add(videoObject);
|
|
| 584 | - }
|
|
| 585 | - eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos);
|
|
| 586 | - eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 587 | - // now store the links to the leaderboard groups
|
|
| 588 | - DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name());
|
|
| 589 | - linksCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1));
|
|
| 590 | - BasicDBList lgUUIDs = new BasicDBList();
|
|
| 591 | - for (LeaderboardGroup lg : event.getLeaderboardGroups()) {
|
|
| 592 | - lgUUIDs.add(lg.getId());
|
|
| 593 | - }
|
|
| 594 | - DBObject dbLinks = new BasicDBObject();
|
|
| 595 | - dbLinks.put(FieldNames.EVENT_ID.name(), event.getId());
|
|
| 596 | - dbLinks.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), lgUUIDs);
|
|
| 597 | - linksCollection.update(query, dbLinks, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 598 | - }
|
|
| 599 | -
|
|
| 600 | - @Override
|
|
| 601 | - public void renameEvent(Serializable id, String newName) {
|
|
| 602 | - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name());
|
|
| 603 | - BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id);
|
|
| 604 | - BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.EVENT_NAME.name(), newName));
|
|
| 605 | - eventCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 606 | - }
|
|
| 607 | -
|
|
| 608 | - @Override
|
|
| 609 | - public void removeEvent(Serializable id) {
|
|
| 610 | - DBCollection eventsCollection = database.getCollection(CollectionNames.EVENTS.name());
|
|
| 611 | - BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id);
|
|
| 612 | - eventsCollection.remove(query);
|
|
| 613 | - }
|
|
| 614 | -
|
|
| 615 | - private DBObject getVenueAsDBObject(Venue venue) {
|
|
| 616 | - DBObject result = new BasicDBObject();
|
|
| 617 | - result.put(FieldNames.VENUE_NAME.name(), venue.getName());
|
|
| 618 | - BasicDBList courseAreaList = new BasicDBList();
|
|
| 619 | - result.put(FieldNames.COURSE_AREAS.name(), courseAreaList);
|
|
| 620 | - for (CourseArea courseArea : venue.getCourseAreas()) {
|
|
| 621 | - DBObject dbCourseArea = new BasicDBObject();
|
|
| 622 | - courseAreaList.add(dbCourseArea);
|
|
| 623 | - dbCourseArea.put(FieldNames.COURSE_AREA_NAME.name(), courseArea.getName());
|
|
| 624 | - dbCourseArea.put(FieldNames.COURSE_AREA_ID.name(), courseArea.getId());
|
|
| 625 | - }
|
|
| 626 | - return result;
|
|
| 627 | - }
|
|
| 628 | -
|
|
| 629 | - @Override
|
|
| 630 | - public void storeRegatta(Regatta regatta) {
|
|
| 631 | - DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name());
|
|
| 632 | - regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1));
|
|
| 633 | - regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_ID.name(), 1));
|
|
| 634 | - DBObject dbRegatta = new BasicDBObject();
|
|
| 635 | - DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
|
| 636 | - dbRegatta.put(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
|
| 637 | - dbRegatta.put(FieldNames.REGATTA_ID.name(), regatta.getId());
|
|
| 638 | - storeTimePoint(regatta.getStartDate(), dbRegatta, FieldNames.REGATTA_START_DATE);
|
|
| 639 | - storeTimePoint(regatta.getEndDate(), dbRegatta, FieldNames.REGATTA_END_DATE);
|
|
| 640 | - dbRegatta.put(FieldNames.SCORING_SCHEME_TYPE.name(), regatta.getScoringScheme().getType().name());
|
|
| 641 | - if (regatta.getBoatClass() != null) {
|
|
| 642 | - dbRegatta.put(FieldNames.BOAT_CLASS_NAME.name(), regatta.getBoatClass().getName());
|
|
| 643 | - dbRegatta.put(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name(), regatta.getBoatClass().typicallyStartsUpwind());
|
|
| 644 | - }
|
|
| 645 | - dbRegatta.put(FieldNames.REGATTA_SERIES.name(), storeSeries(regatta.getSeries()));
|
|
| 646 | -
|
|
| 647 | - if (regatta.getDefaultCourseArea() != null) {
|
|
| 648 | - dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), regatta.getDefaultCourseArea().getId().toString());
|
|
| 649 | - } else {
|
|
| 650 | - dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), null);
|
|
| 651 | - }
|
|
| 652 | - if (regatta.getRegattaConfiguration() != null) {
|
|
| 653 | - JsonSerializer<RegattaConfiguration> serializer = RegattaConfigurationJsonSerializer.create();
|
|
| 654 | - JSONObject json = serializer.serialize(regatta.getRegattaConfiguration());
|
|
| 655 | - DBObject configurationObject = (DBObject) JSON.parse(json.toString());
|
|
| 656 | - dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject);
|
|
| 657 | - }
|
|
| 658 | - dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference());
|
|
| 659 | - dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta));
|
|
| 660 | - regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 661 | - }
|
|
| 662 | -
|
|
| 663 | - private DBObject storeRankingMetric(Regatta regatta) {
|
|
| 664 | - DBObject rankingMetricJson = new BasicDBObject();
|
|
| 665 | - final String rankingMetricTypeName = regatta.getRankingMetricType().name();
|
|
| 666 | - rankingMetricJson.put(FieldNames.REGATTA_RANKING_METRIC_TYPE.name(), rankingMetricTypeName);
|
|
| 667 | - return rankingMetricJson;
|
|
| 668 | - }
|
|
| 669 | -
|
|
| 670 | - @Override
|
|
| 671 | - public void removeRegatta(Regatta regatta) {
|
|
| 672 | - DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name());
|
|
| 673 | - DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
|
| 674 | - regattasCollection.remove(query);
|
|
| 675 | - }
|
|
| 676 | -
|
|
| 677 | - private BasicDBList storeSeries(Iterable<? extends Series> series) {
|
|
| 678 | - BasicDBList dbSeries = new BasicDBList();
|
|
| 679 | - for (Series s : series) {
|
|
| 680 | - dbSeries.add(storeSeries(s));
|
|
| 681 | - }
|
|
| 682 | - return dbSeries;
|
|
| 683 | - }
|
|
| 684 | -
|
|
| 685 | - private DBObject storeSeries(Series s) {
|
|
| 686 | - DBObject dbSeries = new BasicDBObject();
|
|
| 687 | - dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName());
|
|
| 688 | - dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal());
|
|
| 689 | - dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring());
|
|
| 690 | - dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore());
|
|
| 691 | - dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward());
|
|
| 692 | - BasicDBList dbFleets = new BasicDBList();
|
|
| 693 | - for (Fleet fleet : s.getFleets()) {
|
|
| 694 | - dbFleets.add(storeFleet(fleet));
|
|
| 695 | - }
|
|
| 696 | - dbSeries.put(FieldNames.SERIES_FLEETS.name(), dbFleets);
|
|
| 697 | - BasicDBList dbRaceColumns = new BasicDBList();
|
|
| 698 | - for (RaceColumn raceColumn : s.getRaceColumns()) {
|
|
| 699 | - dbRaceColumns.add(storeRaceColumn(raceColumn));
|
|
| 700 | - }
|
|
| 701 | - dbSeries.put(FieldNames.SERIES_RACE_COLUMNS.name(), dbRaceColumns);
|
|
| 702 | - if (s.getResultDiscardingRule() != null) {
|
|
| 703 | - storeResultDiscardingRule(dbSeries, s.getResultDiscardingRule(), FieldNames.SERIES_DISCARDING_THRESHOLDS);
|
|
| 704 | - }
|
|
| 705 | - return dbSeries;
|
|
| 706 | - }
|
|
| 707 | -
|
|
| 708 | - private DBObject storeFleet(Fleet fleet) {
|
|
| 709 | - DBObject dbFleet = new BasicDBObject(FieldNames.FLEET_NAME.name(), fleet.getName());
|
|
| 710 | - if (fleet instanceof FleetImpl) {
|
|
| 711 | - dbFleet.put(FieldNames.FLEET_ORDERING.name(), ((FleetImpl) fleet).getOrdering());
|
|
| 712 | - if(fleet.getColor() != null) {
|
|
| 713 | - com.sap.sse.common.Util.Triple<Integer, Integer, Integer> colorAsRGB = fleet.getColor().getAsRGB();
|
|
| 714 | - // we save the color as a integer value representing the RGB values
|
|
| 715 | - int colorAsInt = (256 * 256 * colorAsRGB.getC()) + colorAsRGB.getB() * 256 + colorAsRGB.getA();
|
|
| 716 | - dbFleet.put(FieldNames.FLEET_COLOR.name(), colorAsInt);
|
|
| 717 | - } else {
|
|
| 718 | - dbFleet.put(FieldNames.FLEET_COLOR.name(), null);
|
|
| 719 | - }
|
|
| 720 | - }
|
|
| 721 | - return dbFleet;
|
|
| 722 | - }
|
|
| 723 | -
|
|
| 724 | - @Override
|
|
| 725 | - public void storeRegattaForRaceID(String raceIDAsString, Regatta regatta) {
|
|
| 726 | - DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name());
|
|
| 727 | - DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
|
| 728 | - DBObject entry = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
|
| 729 | - entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
|
| 730 | - regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 731 | - }
|
|
| 732 | -
|
|
| 733 | - @Override
|
|
| 734 | - public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) {
|
|
| 735 | - DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name());
|
|
| 736 | - DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
|
| 737 | - regattaForRaceIDCollection.remove(query);
|
|
| 738 | - }
|
|
| 739 | -
|
|
| 740 | - public DBCollection getRaceLogCollection() {
|
|
| 741 | - DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name());
|
|
| 742 | - result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null));
|
|
| 743 | - return result;
|
|
| 744 | - }
|
|
| 745 | -
|
|
| 746 | - private void storeRaceLogEventAuthor(DBObject dbObject, AbstractLogEventAuthor author) {
|
|
| 747 | - if (author != null) {
|
|
| 748 | - dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name(), author.getName());
|
|
| 749 | - dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name(), author.getPriority());
|
|
| 750 | - }
|
|
| 751 | - }
|
|
| 752 | -
|
|
| 753 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFlagEvent flagEvent) {
|
|
| 754 | - BasicDBObject result = new BasicDBObject();
|
|
| 755 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 756 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFlagEvent(flagEvent));
|
|
| 757 | - return result;
|
|
| 758 | - }
|
|
| 759 | -
|
|
| 760 | - private void storeRaceLogIdentifier(RaceLogIdentifier raceLogIdentifier, DBObject result) {
|
|
| 761 | - result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
|
| 762 | - }
|
|
| 763 | -
|
|
| 764 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTimeEvent startTimeEvent) {
|
|
| 765 | - BasicDBObject result = new BasicDBObject();
|
|
| 766 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 767 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTimeEvent(startTimeEvent));
|
|
| 768 | - return result;
|
|
| 769 | - }
|
|
| 770 | -
|
|
| 771 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPassChangeEvent passChangeEvent) {
|
|
| 772 | - BasicDBObject result = new BasicDBObject();
|
|
| 773 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 774 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPassChangeEvent(passChangeEvent));
|
|
| 775 | - return result;
|
|
| 776 | - }
|
|
| 777 | -
|
|
| 778 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent raceStatusEvent) {
|
|
| 779 | - BasicDBObject result = new BasicDBObject();
|
|
| 780 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 781 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRaceStatusEvent(raceStatusEvent));
|
|
| 782 | - return result;
|
|
| 783 | - }
|
|
| 784 | -
|
|
| 785 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseAreaChangedEvent courseAreaChangedEvent) {
|
|
| 786 | - BasicDBObject result = new BasicDBObject();
|
|
| 787 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 788 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseAreaChangedEvent(courseAreaChangedEvent));
|
|
| 789 | - return result;
|
|
| 790 | - }
|
|
| 791 | -
|
|
| 792 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseDesignChangedEvent courseDesignChangedEvent) {
|
|
| 793 | - BasicDBObject result = new BasicDBObject();
|
|
| 794 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 795 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseDesignChangedEvent(courseDesignChangedEvent));
|
|
| 796 | - return result;
|
|
| 797 | - }
|
|
| 798 | -
|
|
| 799 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) {
|
|
| 800 | - BasicDBObject result = new BasicDBObject();
|
|
| 801 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 802 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningListChangedEvent(finishPositioningListChangedEvent));
|
|
| 803 | - return result;
|
|
| 804 | - }
|
|
| 805 | -
|
|
| 806 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) {
|
|
| 807 | - BasicDBObject result = new BasicDBObject();
|
|
| 808 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 809 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningConfirmedEvent(finishPositioningConfirmedEvent));
|
|
| 810 | - return result;
|
|
| 811 | - }
|
|
| 812 | -
|
|
| 813 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPathfinderEvent pathfinderEvent) {
|
|
| 814 | - BasicDBObject result = new BasicDBObject();
|
|
| 815 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 816 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPathfinderEvent(pathfinderEvent));
|
|
| 817 | - return result;
|
|
| 818 | - }
|
|
| 819 | -
|
|
| 820 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent) {
|
|
| 821 | - BasicDBObject result = new BasicDBObject();
|
|
| 822 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 823 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogGateLineOpeningTimeEvent(gateLineOpeningTimeEvent));
|
|
| 824 | - return result;
|
|
| 825 | - }
|
|
| 826 | -
|
|
| 827 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartProcedureChangedEvent event) {
|
|
| 828 | - DBObject result = new BasicDBObject();
|
|
| 829 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 830 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartProcedureChangedEvent(event));
|
|
| 831 | - return result;
|
|
| 832 | - }
|
|
| 833 | -
|
|
| 834 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogProtestStartTimeEvent event) {
|
|
| 835 | - DBObject result = new BasicDBObject();
|
|
| 836 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 837 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogProtestStartTimeEvent(event));
|
|
| 838 | - return result;
|
|
| 839 | - }
|
|
| 840 | -
|
|
| 841 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogWindFixEvent event) {
|
|
| 842 | - DBObject result = new BasicDBObject();
|
|
| 843 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 844 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event));
|
|
| 845 | - return result;
|
|
| 846 | - }
|
|
| 847 | -
|
|
| 848 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceCompetitorMappingEvent event) {
|
|
| 849 | - BasicDBObject result = new BasicDBObject();
|
|
| 850 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 851 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceCompetitorMappingEvent(event));
|
|
| 852 | - return result;
|
|
| 853 | - }
|
|
| 854 | -
|
|
| 855 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceMarkMappingEvent event) {
|
|
| 856 | - BasicDBObject result = new BasicDBObject();
|
|
| 857 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 858 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceMarkMappingEvent(event));
|
|
| 859 | - return result;
|
|
| 860 | - }
|
|
| 861 | -
|
|
| 862 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) {
|
|
| 863 | - BasicDBObject result = new BasicDBObject();
|
|
| 864 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 865 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDenoteForTrackingEvent(event));
|
|
| 866 | - return result;
|
|
| 867 | - }
|
|
| 868 | -
|
|
| 869 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTrackingEvent event) {
|
|
| 870 | - BasicDBObject result = new BasicDBObject();
|
|
| 871 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 872 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTrackingEvent(event));
|
|
| 873 | - return result;
|
|
| 874 | - }
|
|
| 875 | -
|
|
| 876 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRevokeEvent event) {
|
|
| 877 | - BasicDBObject result = new BasicDBObject();
|
|
| 878 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 879 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRevokeEvent(event));
|
|
| 880 | - return result;
|
|
| 881 | - }
|
|
| 882 | -
|
|
| 883 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRegisterCompetitorEvent event) {
|
|
| 884 | - BasicDBObject result = new BasicDBObject();
|
|
| 885 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 886 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRegisterCompetitorEvent(event));
|
|
| 887 | - return result;
|
|
| 888 | - }
|
|
| 889 | -
|
|
| 890 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDefineMarkEvent event) {
|
|
| 891 | - BasicDBObject result = new BasicDBObject();
|
|
| 892 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 893 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDefineMarkEvent(event));
|
|
| 894 | - return result;
|
|
| 895 | - }
|
|
| 896 | -
|
|
| 897 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCloseOpenEndedDeviceMappingEvent event) {
|
|
| 898 | - BasicDBObject result = new BasicDBObject();
|
|
| 899 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 900 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCloseOpenEndedDeviceMappingEvent(event));
|
|
| 901 | - return result;
|
|
| 902 | - }
|
|
| 903 | -
|
|
| 904 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogEndOfTrackingEvent event) {
|
|
| 905 | - BasicDBObject result = new BasicDBObject();
|
|
| 906 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 907 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogEndOfTrackingEvent(event));
|
|
| 908 | - return result;
|
|
| 909 | - }
|
|
| 910 | -
|
|
| 911 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartOfTrackingEvent event) {
|
|
| 912 | - BasicDBObject result = new BasicDBObject();
|
|
| 913 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 914 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartOfTrackingEvent(event));
|
|
| 915 | - return result;
|
|
| 916 | - }
|
|
| 917 | -
|
|
| 918 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogAdditionalScoringInformationEvent event) {
|
|
| 919 | - BasicDBObject result = new BasicDBObject();
|
|
| 920 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 921 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeAdditionalScoringInformation(event));
|
|
| 922 | - return result;
|
|
| 923 | - }
|
|
| 924 | -
|
|
| 925 | - private Object storeAdditionalScoringInformation(RaceLogAdditionalScoringInformationEvent event) {
|
|
| 926 | - DBObject result = new BasicDBObject();
|
|
| 927 | - storeRaceLogEventProperties(event, result);
|
|
| 928 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogAdditionalScoringInformationEvent.class.getSimpleName());
|
|
| 929 | - result.put(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name(), event.getType().name());
|
|
| 930 | - return result;
|
|
| 931 | - }
|
|
| 932 | -
|
|
| 933 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFixedMarkPassingEvent event) {
|
|
| 934 | - BasicDBObject result = new BasicDBObject();
|
|
| 935 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 936 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFixedMarkPassingEvent(event));
|
|
| 937 | - return result;
|
|
| 938 | - }
|
|
| 939 | -
|
|
| 940 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogSuppressedMarkPassingsEvent event) {
|
|
| 941 | - BasicDBObject result = new BasicDBObject();
|
|
| 942 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 943 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogSuppressedMarkPassingsEvent(event));
|
|
| 944 | - return result;
|
|
| 945 | - }
|
|
| 946 | -
|
|
| 947 | - private Object storeRaceLogWindFix(RaceLogWindFixEvent event) {
|
|
| 948 | - DBObject result = new BasicDBObject();
|
|
| 949 | - storeRaceLogEventProperties(event, result);
|
|
| 950 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogWindFixEvent.class.getSimpleName());
|
|
| 951 | - result.put(FieldNames.WIND.name(), storeWind(event.getWindFix()));
|
|
| 952 | - result.put(FieldNames.IS_MAGNETIC.name(), event.isMagnetic());
|
|
| 953 | - return result;
|
|
| 954 | - }
|
|
| 955 | -
|
|
| 956 | - private Object storeRaceLogProtestStartTimeEvent(RaceLogProtestStartTimeEvent event) {
|
|
| 957 | - DBObject result = new BasicDBObject();
|
|
| 958 | - storeRaceLogEventProperties(event, result);
|
|
| 959 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogProtestStartTimeEvent.class.getSimpleName());
|
|
| 960 | - storeTimePoint(event.getProtestStartTime(), result, FieldNames.RACE_LOG_PROTEST_START_TIME);
|
|
| 961 | - return result;
|
|
| 962 | - }
|
|
| 963 | -
|
|
| 964 | - private Object storeRaceLogEndOfTrackingEvent(RaceLogEndOfTrackingEvent event) {
|
|
| 965 | - DBObject result = new BasicDBObject();
|
|
| 966 | - storeRaceLogEventProperties(event, result);
|
|
| 967 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogEndOfTrackingEvent.class.getSimpleName());
|
|
| 968 | - return result;
|
|
| 969 | - }
|
|
| 970 | -
|
|
| 971 | - private Object storeRaceLogStartOfTrackingEvent(RaceLogStartOfTrackingEvent event) {
|
|
| 972 | - DBObject result = new BasicDBObject();
|
|
| 973 | - storeRaceLogEventProperties(event, result);
|
|
| 974 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartOfTrackingEvent.class.getSimpleName());
|
|
| 975 | - return result;
|
|
| 976 | - }
|
|
| 977 | -
|
|
| 978 | - private Object storeRaceLogStartProcedureChangedEvent(RaceLogStartProcedureChangedEvent event) {
|
|
| 979 | - DBObject result = new BasicDBObject();
|
|
| 980 | - storeRaceLogEventProperties(event, result);
|
|
| 981 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartProcedureChangedEvent.class.getSimpleName());
|
|
| 982 | - result.put(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name(), event.getStartProcedureType().name());
|
|
| 983 | - return result;
|
|
| 984 | - }
|
|
| 985 | -
|
|
| 986 | - private Object storeRaceLogPathfinderEvent(RaceLogPathfinderEvent pathfinderEvent) {
|
|
| 987 | - DBObject result = new BasicDBObject();
|
|
| 988 | - storeRaceLogEventProperties(pathfinderEvent, result);
|
|
| 989 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPathfinderEvent.class.getSimpleName());
|
|
| 990 | - result.put(FieldNames.RACE_LOG_PATHFINDER_ID.name(), pathfinderEvent.getPathfinderId());
|
|
| 991 | - return result;
|
|
| 992 | - }
|
|
| 993 | -
|
|
| 994 | - private void storeDeviceMappingEvent(DeviceMappingEvent<?, ?> event, DBObject result, FieldNames fromField, FieldNames toField) {
|
|
| 995 | - try {
|
|
| 996 | - result.put(FieldNames.DEVICE_ID.name(), storeDeviceId(deviceIdentifierServiceFinder, event.getDevice()));
|
|
| 997 | - } catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
|
|
| 998 | - logger.log(Level.WARNING, "Could not store device identifier for mappng event", e);
|
|
| 999 | - }
|
|
| 1000 | - if (event.getFrom() != null) {
|
|
| 1001 | - storeTimePoint(event.getFrom(), result, fromField);
|
|
| 1002 | - }
|
|
| 1003 | - if (event.getTo() != null) {
|
|
| 1004 | - storeTimePoint(event.getTo(), result, toField);
|
|
| 1005 | - }
|
|
| 1006 | - }
|
|
| 1007 | -
|
|
| 1008 | - private Object storeRaceLogDeviceCompetitorMappingEvent(RaceLogDeviceCompetitorMappingEvent event) {
|
|
| 1009 | - DBObject result = new BasicDBObject();
|
|
| 1010 | - storeRaceLogEventProperties(event, result);
|
|
| 1011 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceCompetitorMappingEvent.class.getSimpleName());
|
|
| 1012 | - storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO);
|
|
| 1013 | - result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId());
|
|
| 1014 | - return result;
|
|
| 1015 | - }
|
|
| 1016 | -
|
|
| 1017 | - private Object storeRaceLogDeviceMarkMappingEvent(RaceLogDeviceMarkMappingEvent event) {
|
|
| 1018 | - DBObject result = new BasicDBObject();
|
|
| 1019 | - storeRaceLogEventProperties(event, result);
|
|
| 1020 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceMarkMappingEvent.class.getSimpleName());
|
|
| 1021 | - storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO);
|
|
| 1022 | - result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo()));
|
|
| 1023 | - return result;
|
|
| 1024 | - }
|
|
| 1025 | -
|
|
| 1026 | - private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) {
|
|
| 1027 | - DBObject result = new BasicDBObject();
|
|
| 1028 | - storeRaceLogEventProperties(event, result);
|
|
| 1029 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDenoteForTrackingEvent.class.getSimpleName());
|
|
| 1030 | - result.put(FieldNames.RACE_NAME.name(), event.getRaceName());
|
|
| 1031 | - result.put(FieldNames.BOAT_CLASS_NAME.name(), event.getBoatClass().getName());
|
|
| 1032 | - result.put(FieldNames.RACE_ID.name(), event.getRaceId());
|
|
| 1033 | - return result;
|
|
| 1034 | - }
|
|
| 1035 | -
|
|
| 1036 | - private Object storeRaceLogStartTrackingEvent(RaceLogStartTrackingEvent event) {
|
|
| 1037 | - DBObject result = new BasicDBObject();
|
|
| 1038 | - storeRaceLogEventProperties(event, result);
|
|
| 1039 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTrackingEvent.class.getSimpleName());
|
|
| 1040 | - return result;
|
|
| 1041 | - }
|
|
| 1042 | -
|
|
| 1043 | - private Object storeRaceLogRevokeEvent(RaceLogRevokeEvent event) {
|
|
| 1044 | - DBObject result = new BasicDBObject();
|
|
| 1045 | - storeRaceLogEventProperties(event, result);
|
|
| 1046 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRevokeEvent.class.getSimpleName());
|
|
| 1047 | - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId());
|
|
| 1048 | - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType());
|
|
| 1049 | - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo());
|
|
| 1050 | - result.put(FieldNames.RACE_LOG_REVOKED_REASON.name(), event.getReason());
|
|
| 1051 | - return result;
|
|
| 1052 | - }
|
|
| 1053 | -
|
|
| 1054 | - private Object storeRaceLogRegisterCompetitorEvent(RaceLogRegisterCompetitorEvent event) {
|
|
| 1055 | - DBObject result = new BasicDBObject();
|
|
| 1056 | - storeRaceLogEventProperties(event, result);
|
|
| 1057 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRegisterCompetitorEvent.class.getSimpleName());
|
|
| 1058 | - result.put(FieldNames.RACE_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId());
|
|
| 1059 | - return result;
|
|
| 1060 | - }
|
|
| 1061 | -
|
|
| 1062 | - private Object storeRaceLogDefineMarkEvent(RaceLogDefineMarkEvent event) {
|
|
| 1063 | - DBObject result = new BasicDBObject();
|
|
| 1064 | - storeRaceLogEventProperties(event, result);
|
|
| 1065 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDefineMarkEvent.class.getSimpleName());
|
|
| 1066 | - result.put(FieldNames.RACE_LOG_MARK.name(), storeMark(event.getMark()));
|
|
| 1067 | - return result;
|
|
| 1068 | - }
|
|
| 1069 | -
|
|
| 1070 | - private Object storeRaceLogCloseOpenEndedDeviceMappingEvent(RaceLogCloseOpenEndedDeviceMappingEvent event) {
|
|
| 1071 | - DBObject result = new BasicDBObject();
|
|
| 1072 | - storeRaceLogEventProperties(event, result);
|
|
| 1073 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName());
|
|
| 1074 | - result.put(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId());
|
|
| 1075 | - storeTimePoint(event.getClosingTimePoint(), result, FieldNames.RACE_LOG_CLOSING_TIMEPOINT);
|
|
| 1076 | - return result;
|
|
| 1077 | - }
|
|
| 1078 | -
|
|
| 1079 | - private Object storeRaceLogFixedMarkPassingEvent(RaceLogFixedMarkPassingEvent event) {
|
|
| 1080 | - DBObject result = new BasicDBObject();
|
|
| 1081 | - storeRaceLogEventProperties(event, result);
|
|
| 1082 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFixedMarkPassingEvent.class.getSimpleName());
|
|
| 1083 | - result.put(FieldNames.INDEX_OF_PASSED_WAYPOINT.name(), event.getZeroBasedIndexOfPassedWaypoint());
|
|
| 1084 | - result.put(FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING.name(), event.getTimePointOfFixedPassing().asMillis());
|
|
| 1085 | - return result;
|
|
| 1086 | - }
|
|
| 1087 | -
|
|
| 1088 | - private Object storeRaceLogSuppressedMarkPassingsEvent(RaceLogSuppressedMarkPassingsEvent event) {
|
|
| 1089 | - DBObject result = new BasicDBObject();
|
|
| 1090 | - storeRaceLogEventProperties(event, result);
|
|
| 1091 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogSuppressedMarkPassingsEvent.class.getSimpleName());
|
|
| 1092 | - result.put(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name(), event.getZeroBasedIndexOfFirstSuppressedWaypoint());
|
|
| 1093 | - return result;
|
|
| 1094 | - }
|
|
| 1095 | -
|
|
| 1096 | - public DBObject storeRaceLogFlagEvent(RaceLogFlagEvent flagEvent) {
|
|
| 1097 | - DBObject result = new BasicDBObject();
|
|
| 1098 | - storeRaceLogEventProperties(flagEvent, result);
|
|
| 1099 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFlagEvent.class.getSimpleName());
|
|
| 1100 | - result.put(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name(), flagEvent.getUpperFlag().name());
|
|
| 1101 | - result.put(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name(), flagEvent.getLowerFlag().name());
|
|
| 1102 | - result.put(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name(), String.valueOf(flagEvent.isDisplayed()));
|
|
| 1103 | - return result;
|
|
| 1104 | - }
|
|
| 1105 | -
|
|
| 1106 | - private DBObject storeRaceLogStartTimeEvent(RaceLogStartTimeEvent startTimeEvent) {
|
|
| 1107 | - DBObject result = new BasicDBObject();
|
|
| 1108 | - storeRaceLogEventProperties(startTimeEvent, result);
|
|
| 1109 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTimeEvent.class.getSimpleName());
|
|
| 1110 | - storeTimePoint(startTimeEvent.getStartTime(), result, FieldNames.RACE_LOG_EVENT_START_TIME);
|
|
| 1111 | - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), startTimeEvent.getNextStatus().name());
|
|
| 1112 | - return result;
|
|
| 1113 | - }
|
|
| 1114 | -
|
|
| 1115 | - private void storeRaceLogEventProperties(RaceLogEvent event, DBObject result) {
|
|
| 1116 | - // for compatibility reasons we reuse the field name of Timed
|
|
| 1117 | - storeTimePoint(event.getLogicalTimePoint(), result, FieldNames.TIME_AS_MILLIS);
|
|
| 1118 | - storeTimePoint(event.getCreatedAt(), result, FieldNames.RACE_LOG_EVENT_CREATED_AT);
|
|
| 1119 | - result.put(FieldNames.RACE_LOG_EVENT_ID.name(), event.getId());
|
|
| 1120 | - result.put(FieldNames.RACE_LOG_EVENT_PASS_ID.name(), event.getPassId());
|
|
| 1121 | - result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedBoats()));
|
|
| 1122 | - storeRaceLogEventAuthor(result, event.getAuthor());
|
|
| 1123 | - }
|
|
| 1124 | -
|
|
| 1125 | -
|
|
| 1126 | - private BasicDBList storeInvolvedBoatsForRaceLogEvent(List<Competitor> competitors) {
|
|
| 1127 | - BasicDBList dbInvolvedCompetitorIds = new BasicDBList();
|
|
| 1128 | - for (Competitor competitor : competitors) {
|
|
| 1129 | - dbInvolvedCompetitorIds.add(competitor.getId());
|
|
| 1130 | - }
|
|
| 1131 | - return dbInvolvedCompetitorIds;
|
|
| 1132 | - }
|
|
| 1133 | -
|
|
| 1134 | - private DBObject storeRaceLogPassChangeEvent(RaceLogPassChangeEvent passChangeEvent) {
|
|
| 1135 | - DBObject result = new BasicDBObject();
|
|
| 1136 | - storeRaceLogEventProperties(passChangeEvent, result);
|
|
| 1137 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPassChangeEvent.class.getSimpleName());
|
|
| 1138 | - return result;
|
|
| 1139 | - }
|
|
| 1140 | -
|
|
| 1141 | - private DBObject storeRaceLogDependentStartTimeEvent(RaceLogDependentStartTimeEvent dependentStartTimeEvent) {
|
|
| 1142 | - DBObject result = new BasicDBObject();
|
|
| 1143 | - storeRaceLogEventProperties(dependentStartTimeEvent, result);
|
|
| 1144 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDependentStartTimeEvent.class.getSimpleName());
|
|
| 1145 | - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_REGATTALIKE.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRegattaLikeParentName());
|
|
| 1146 | - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_RACECOLUMN.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRaceColumnName());
|
|
| 1147 | - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_FLEET.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getFleetName());
|
|
| 1148 | - storeDuration(dependentStartTimeEvent.getStartTimeDifference(), result, FieldNames.RACE_LOG_START_TIME_DIFFERENCE_IN_MS);
|
|
| 1149 | - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), dependentStartTimeEvent.getNextStatus().name());
|
|
| 1150 | - return result;
|
|
| 1151 | - }
|
|
| 1152 | -
|
|
| 1153 | - private void storeDuration(Duration duration, DBObject result, FieldNames fieldName) {
|
|
| 1154 | - if (duration != null) {
|
|
| 1155 | - result.put(fieldName.name(), duration.asMillis());
|
|
| 1156 | - }
|
|
| 1157 | - }
|
|
| 1158 | -
|
|
| 1159 | - private DBObject storeRaceLogRaceStatusEvent(RaceLogRaceStatusEvent raceStatusEvent) {
|
|
| 1160 | - DBObject result = new BasicDBObject();
|
|
| 1161 | - storeRaceLogEventProperties(raceStatusEvent, result);
|
|
| 1162 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRaceStatusEvent.class.getSimpleName());
|
|
| 1163 | - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), raceStatusEvent.getNextStatus().name());
|
|
| 1164 | - return result;
|
|
| 1165 | - }
|
|
| 1166 | -
|
|
| 1167 | - private DBObject storeRaceLogCourseAreaChangedEvent(RaceLogCourseAreaChangedEvent courseAreaChangedEvent) {
|
|
| 1168 | - DBObject result = new BasicDBObject();
|
|
| 1169 | - storeRaceLogEventProperties(courseAreaChangedEvent, result);
|
|
| 1170 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseAreaChangedEvent.class.getSimpleName());
|
|
| 1171 | - result.put(FieldNames.COURSE_AREA_ID.name(), courseAreaChangedEvent.getCourseAreaId());
|
|
| 1172 | - return result;
|
|
| 1173 | - }
|
|
| 1174 | -
|
|
| 1175 | - private DBObject storeRaceLogCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent courseDesignChangedEvent) {
|
|
| 1176 | - DBObject result = new BasicDBObject();
|
|
| 1177 | - storeRaceLogEventProperties(courseDesignChangedEvent, result);
|
|
| 1178 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName());
|
|
| 1179 | - result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName());
|
|
| 1180 | - result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign()));
|
|
| 1181 | - return result;
|
|
| 1182 | - }
|
|
| 1183 | -
|
|
| 1184 | - private Object storeRaceLogFinishPositioningListChangedEvent(RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) {
|
|
| 1185 | - DBObject result = new BasicDBObject();
|
|
| 1186 | - storeRaceLogEventProperties(finishPositioningListChangedEvent, result);
|
|
| 1187 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningListChangedEvent.class.getSimpleName());
|
|
| 1188 | - result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
|
|
| 1189 | -
|
|
| 1190 | - return result;
|
|
| 1191 | - }
|
|
| 1192 | -
|
|
| 1193 | - private Object storeRaceLogFinishPositioningConfirmedEvent(RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) {
|
|
| 1194 | - DBObject result = new BasicDBObject();
|
|
| 1195 | - storeRaceLogEventProperties(finishPositioningConfirmedEvent, result);
|
|
| 1196 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName());
|
|
| 1197 | - result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
|
|
| 1198 | -
|
|
| 1199 | - return result;
|
|
| 1200 | - }
|
|
| 1201 | -
|
|
| 1202 | - private Object storeRaceLogGateLineOpeningTimeEvent(RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent){
|
|
| 1203 | - DBObject result = new BasicDBObject();
|
|
| 1204 | - storeRaceLogEventProperties(gateLineOpeningTimeEvent, result);
|
|
| 1205 | - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogGateLineOpeningTimeEvent.class.getSimpleName());
|
|
| 1206 | - result.put(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGateLaunchStopTime());
|
|
| 1207 | - result.put(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGolfDownTime());
|
|
| 1208 | - return result;
|
|
| 1209 | - }
|
|
| 1210 | -
|
|
| 1211 | - private BasicDBList storePositionedCompetitors(List<com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason>> positionedCompetitors) {
|
|
| 1212 | - BasicDBList dbList = new BasicDBList();
|
|
| 1213 | - if (positionedCompetitors != null) {
|
|
| 1214 | - for (com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason> competitorPair : positionedCompetitors) {
|
|
| 1215 | - dbList.add(storePositionedCompetitor(competitorPair));
|
|
| 1216 | - }
|
|
| 1217 | - }
|
|
| 1218 | - return dbList;
|
|
| 1219 | - }
|
|
| 1220 | -
|
|
| 1221 | - private DBObject storePositionedCompetitor(com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason> competitorTriple) {
|
|
| 1222 | - DBObject result = new BasicDBObject();
|
|
| 1223 | - result.put(FieldNames.COMPETITOR_ID.name(), competitorTriple.getA());
|
|
| 1224 | - result.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), competitorTriple.getB());
|
|
| 1225 | - result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), competitorTriple.getC().name());
|
|
| 1226 | -
|
|
| 1227 | - return result;
|
|
| 1228 | - }
|
|
| 1229 | -
|
|
| 1230 | - private BasicDBList storeCourseBase(CourseBase courseData) {
|
|
| 1231 | - BasicDBList dbList = new BasicDBList();
|
|
| 1232 | -
|
|
| 1233 | - for (Waypoint waypoint : courseData.getWaypoints()) {
|
|
| 1234 | - dbList.add(storeWaypoint(waypoint));
|
|
| 1235 | - }
|
|
| 1236 | - return dbList;
|
|
| 1237 | - }
|
|
| 1238 | -
|
|
| 1239 | - private DBObject storeWaypoint(Waypoint waypoint) {
|
|
| 1240 | - DBObject result = new BasicDBObject();
|
|
| 1241 | - result.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), getPassingInstructions(waypoint.getPassingInstructions()));
|
|
| 1242 | - result.put(FieldNames.CONTROLPOINT.name(), storeControlPoint(waypoint.getControlPoint()));
|
|
| 1243 | - return result;
|
|
| 1244 | - }
|
|
| 1245 | -
|
|
| 1246 | - private DBObject storeControlPoint(ControlPoint controlPoint) {
|
|
| 1247 | - DBObject result = new BasicDBObject();
|
|
| 1248 | - if (controlPoint instanceof Mark) {
|
|
| 1249 | - result.put(FieldNames.CONTROLPOINT_CLASS.name(), Mark.class.getSimpleName());
|
|
| 1250 | - result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeMark((Mark) controlPoint));
|
|
| 1251 | - } else if (controlPoint instanceof ControlPointWithTwoMarks) {
|
|
| 1252 | - result.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName());
|
|
| 1253 | - result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeControlPointWithTwoMarks((ControlPointWithTwoMarks) controlPoint));
|
|
| 1254 | - }
|
|
| 1255 | - return result;
|
|
| 1256 | - }
|
|
| 1257 | -
|
|
| 1258 | - private DBObject storeControlPointWithTwoMarks(ControlPointWithTwoMarks cpwtm) {
|
|
| 1259 | - DBObject result = new BasicDBObject();
|
|
| 1260 | - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), cpwtm.getId());
|
|
| 1261 | - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), cpwtm.getName());
|
|
| 1262 | - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), storeMark(cpwtm.getLeft()));
|
|
| 1263 | - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), storeMark(cpwtm.getRight()));
|
|
| 1264 | - return result;
|
|
| 1265 | - }
|
|
| 1266 | -
|
|
| 1267 | - private DBObject storeMark(Mark mark) {
|
|
| 1268 | - DBObject result = new BasicDBObject();
|
|
| 1269 | - result.put(FieldNames.MARK_ID.name(), mark.getId());
|
|
| 1270 | - result.put(FieldNames.MARK_COLOR.name(), mark.getColor());
|
|
| 1271 | - result.put(FieldNames.MARK_NAME.name(), mark.getName());
|
|
| 1272 | - result.put(FieldNames.MARK_PATTERN.name(), mark.getPattern());
|
|
| 1273 | - result.put(FieldNames.MARK_SHAPE.name(), mark.getShape());
|
|
| 1274 | - result.put(FieldNames.MARK_TYPE.name(), mark.getType() == null ? null : mark.getType().name());
|
|
| 1275 | - return result;
|
|
| 1276 | - }
|
|
| 1277 | -
|
|
| 1278 | - private String getPassingInstructions(PassingInstruction passingInstructions) {
|
|
| 1279 | - final String passing;
|
|
| 1280 | - if (passingInstructions != null) {
|
|
| 1281 | - passing = passingInstructions.name();
|
|
| 1282 | - } else {
|
|
| 1283 | - passing = null;
|
|
| 1284 | - }
|
|
| 1285 | - return passing;
|
|
| 1286 | - }
|
|
| 1287 | - @Override
|
|
| 1288 | - public void storeCompetitor(Competitor competitor) {
|
|
| 1289 | - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
|
| 1290 | - JSONObject json = competitorSerializer.serialize(competitor);
|
|
| 1291 | - DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
|
|
| 1292 | - DBObject entry = (DBObject) JSON.parse(json.toString());
|
|
| 1293 | - collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
|
|
| 1294 | - }
|
|
| 1295 | -
|
|
| 1296 | - @Override
|
|
| 1297 | - public void removeAllCompetitors() {
|
|
| 1298 | - logger.info("Removing all persistent competitor info");
|
|
| 1299 | - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
|
| 1300 | - collection.drop();
|
|
| 1301 | - }
|
|
| 1302 | -
|
|
| 1303 | - @Override
|
|
| 1304 | - public void removeCompetitor(Competitor competitor) {
|
|
| 1305 | - logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId());
|
|
| 1306 | - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
|
| 1307 | - DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
|
|
| 1308 | - collection.remove(query, WriteConcern.SAFE);
|
|
| 1309 | - }
|
|
| 1310 | -
|
|
| 1311 | - @Override
|
|
| 1312 | - public void storeDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) {
|
|
| 1313 | - DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name());
|
|
| 1314 | -
|
|
| 1315 | - DBObject query = new BasicDBObject();
|
|
| 1316 | - query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier());
|
|
| 1317 | -
|
|
| 1318 | - DBObject entryObject = new BasicDBObject();
|
|
| 1319 | - entryObject.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier());
|
|
| 1320 | - entryObject.put(FieldNames.CONFIGURATION_MATCHER.name(), createDeviceConfigurationMatcherObject(matcher));
|
|
| 1321 | - entryObject.put(FieldNames.CONFIGURATION_CONFIG.name(), createDeviceConfigurationObject(configuration));
|
|
| 1322 | -
|
|
| 1323 | - configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
|
| 1324 | - }
|
|
| 1325 | -
|
|
| 1326 | - private DBObject createDeviceConfigurationMatcherObject(DeviceConfigurationMatcher matcher) {
|
|
| 1327 | - DBObject matcherObject = new BasicDBObject();
|
|
| 1328 | - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_TYPE.name(), matcher.getMatcherType().name());
|
|
| 1329 | - if (matcher instanceof DeviceConfigurationMatcherSingle) {
|
|
| 1330 | - BasicDBList client = new BasicDBList();
|
|
| 1331 | - client.add(((DeviceConfigurationMatcherSingle)matcher).getClientIdentifier());
|
|
| 1332 | - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), client);
|
|
| 1333 | - } else if (matcher instanceof DeviceConfigurationMatcherMulti) {
|
|
| 1334 | - BasicDBList clients = new BasicDBList();
|
|
| 1335 | - Util.addAll(((DeviceConfigurationMatcherMulti)matcher).getClientIdentifiers(), clients);
|
|
| 1336 | - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), clients);
|
|
| 1337 | - }
|
|
| 1338 | - return matcherObject;
|
|
| 1339 | - }
|
|
| 1340 | -
|
|
| 1341 | - private DBObject createDeviceConfigurationObject(DeviceConfiguration configuration) {
|
|
| 1342 | - JsonSerializer<DeviceConfiguration> serializer = DeviceConfigurationJsonSerializer.create();
|
|
| 1343 | - JSONObject json = serializer.serialize(configuration);
|
|
| 1344 | - DBObject entry = (DBObject) JSON.parse(json.toString());
|
|
| 1345 | - return entry;
|
|
| 1346 | - }
|
|
| 1347 | -
|
|
| 1348 | - @Override
|
|
| 1349 | - public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) {
|
|
| 1350 | - DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name());
|
|
| 1351 | - DBObject query = new BasicDBObject();
|
|
| 1352 | - query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier());
|
|
| 1353 | - configurationsCollections.remove(query);
|
|
| 1354 | - }
|
|
| 1355 | -
|
|
| 1356 | - public static DBObject storeDeviceId(
|
|
| 1357 | - TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder, DeviceIdentifier device)
|
|
| 1358 | - throws TransformationException, NoCorrespondingServiceRegisteredException {
|
|
| 1359 | - String type = device.getIdentifierType();
|
|
| 1360 | - DeviceIdentifierMongoHandler handler = deviceIdentifierServiceFinder.findService(type);
|
|
| 1361 | - com.sap.sse.common.Util.Pair<String, ? extends Object> pair = handler.serialize(device);
|
|
| 1362 | - type = pair.getA();
|
|
| 1363 | - Object deviceTypeSpecificId = pair.getB();
|
|
| 1364 | - return new BasicDBObjectBuilder()
|
|
| 1365 | - .add(FieldNames.DEVICE_TYPE.name(), type)
|
|
| 1366 | - .add(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), deviceTypeSpecificId)
|
|
| 1367 | - .add(FieldNames.DEVICE_STRING_REPRESENTATION.name(), device.getStringRepresentation()).get();
|
|
| 1368 | - }
|
|
| 1369 | -
|
|
| 1370 | - void storeRaceLogEventEvent(DBObject eventEntry) {
|
|
| 1371 | - getRaceLogCollection().insert(eventEntry);
|
|
| 1372 | - }
|
|
| 1373 | -
|
|
| 1374 | - @Override
|
|
| 1375 | - public void removeRaceLog(RaceLogIdentifier identifier) {
|
|
| 1376 | - DBObject query = new BasicDBObject();
|
|
| 1377 | - storeRaceLogIdentifier(identifier, query);
|
|
| 1378 | - getRaceLogCollection().remove(query);
|
|
| 1379 | - }
|
|
| 1380 | -
|
|
| 1381 | - @Override
|
|
| 1382 | - public void removeRegattaLog(RegattaLikeIdentifier identifier) {
|
|
| 1383 | - DBObject query = new BasicDBObject();
|
|
| 1384 | - addRegattaLikeIdentifier(identifier, query);
|
|
| 1385 | - getRegattaLogCollection().remove(query);
|
|
| 1386 | - }
|
|
| 1387 | -
|
|
| 1388 | - @Override
|
|
| 1389 | - public void storeResultUrl(String resultProviderName, URL url) {
|
|
| 1390 | - DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name());
|
|
| 1391 | - DBObject query = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName);
|
|
| 1392 | - DBObject entry = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName);
|
|
| 1393 | - entry.put(FieldNames.RESULT_URL.name(), url.toString());
|
|
| 1394 | - resultUrlsCollection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
|
|
| 1395 | - }
|
|
| 1396 | -
|
|
| 1397 | - @Override
|
|
| 1398 | - public void removeResultUrl(String resultProviderName, URL url) {
|
|
| 1399 | - DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name());
|
|
| 1400 | - DBObject query = new BasicDBObjectBuilder().add(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName)
|
|
| 1401 | - .add(FieldNames.RESULT_URL.name(), url.toString()).get();
|
|
| 1402 | - resultUrlsCollection.remove(query);
|
|
| 1403 | - }
|
|
| 1404 | -
|
|
| 1405 | - public DBCollection getRegattaLogCollection() {
|
|
| 1406 | - DBCollection result = database.getCollection(CollectionNames.REGATTA_LOGS.name());
|
|
| 1407 | - DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), null);
|
|
| 1408 | - index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), null);
|
|
| 1409 | - result.createIndex(index);
|
|
| 1410 | - return result;
|
|
| 1411 | - }
|
|
| 1412 | -
|
|
| 1413 | - private DBObject createBasicRegattaLogEventDBObject(RegattaLogEvent event) {
|
|
| 1414 | - DBObject result = new BasicDBObject();
|
|
| 1415 | - storeTimed(event, result);
|
|
| 1416 | - storeTimePoint(event.getCreatedAt(), result, FieldNames.REGATTA_LOG_EVENT_CREATED_AT);
|
|
| 1417 | - result.put(FieldNames.REGATTA_LOG_EVENT_ID.name(), event.getId());
|
|
| 1418 | - result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name(), event.getAuthor().getName());
|
|
| 1419 | - result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name(), event.getAuthor().getPriority());
|
|
| 1420 | - return result;
|
|
| 1421 | - }
|
|
| 1422 | -
|
|
| 1423 | - private void addRegattaLikeIdentifier(RegattaLikeIdentifier regattaLikeId, DBObject toObject) {
|
|
| 1424 | - toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), regattaLikeId.getIdentifierType());
|
|
| 1425 | - toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), regattaLikeId.getName());
|
|
| 1426 | - }
|
|
| 1427 | -
|
|
| 1428 | - private void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, DBObject innerObject) {
|
|
| 1429 | - DBObject result = new BasicDBObject(FieldNames.REGATTA_LOG_EVENT.name(), innerObject);
|
|
| 1430 | - addRegattaLikeIdentifier(regattaLikeId, result);
|
|
| 1431 | - getRegattaLogCollection().insert(result);
|
|
| 1432 | - }
|
|
| 1433 | -
|
|
| 1434 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceCompetitorMappingEvent event) {
|
|
| 1435 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1436 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName());
|
|
| 1437 | - storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO);
|
|
| 1438 | - result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId());
|
|
| 1439 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1440 | - }
|
|
| 1441 | -
|
|
| 1442 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceMarkMappingEvent event) {
|
|
| 1443 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1444 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceMarkMappingEvent.class.getSimpleName());
|
|
| 1445 | - storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO);
|
|
| 1446 | - result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo()));
|
|
| 1447 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1448 | - }
|
|
| 1449 | -
|
|
| 1450 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRevokeEvent event) {
|
|
| 1451 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1452 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRevokeEvent.class.getSimpleName());
|
|
| 1453 | - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId());
|
|
| 1454 | - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType());
|
|
| 1455 | - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo());
|
|
| 1456 | - result.put(FieldNames.REGATTA_LOG_REVOKED_REASON.name(), event.getReason());
|
|
| 1457 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1458 | - }
|
|
| 1459 | -
|
|
| 1460 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterCompetitorEvent event) {
|
|
| 1461 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1462 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterCompetitorEvent.class.getSimpleName());
|
|
| 1463 | - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId());
|
|
| 1464 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1465 | - }
|
|
| 1466 | -
|
|
| 1467 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogCloseOpenEndedDeviceMappingEvent event) {
|
|
| 1468 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1469 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName());
|
|
| 1470 | - result.put(FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId());
|
|
| 1471 | - storeTimePoint(event.getClosingTimePoint(), result, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT);
|
|
| 1472 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1473 | - }
|
|
| 1474 | -
|
|
| 1475 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnTimeFactorEvent event) {
|
|
| 1476 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1477 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName());
|
|
| 1478 | - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId());
|
|
| 1479 | - result.put(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name(), event.getTimeOnTimeFactor());
|
|
| 1480 | - }
|
|
| 1481 | -
|
|
| 1482 | - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDependentStartTimeEvent event) {
|
|
| 1483 | - BasicDBObject result = new BasicDBObject();
|
|
| 1484 | - storeRaceLogIdentifier(raceLogIdentifier, result);
|
|
| 1485 | - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDependentStartTimeEvent(event));
|
|
| 1486 | - return result;
|
|
| 1487 | - }
|
|
| 1488 | -
|
|
| 1489 | - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) {
|
|
| 1490 | - DBObject result = createBasicRegattaLogEventDBObject(event);
|
|
| 1491 | - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName());
|
|
| 1492 | - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId());
|
|
| 1493 | - result.put(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name(), event.getTimeOnDistanceAllowancePerNauticalMile().asSeconds());
|
|
| 1494 | - storeRegattaLogEvent(regattaLikeId, result);
|
|
| 1495 | - }
|
|
| 1496 | -
|
|
| 1497 | - private DBObject createImageObject(ImageDescriptor image) {
|
|
| 1498 | - DBObject result = new BasicDBObject();
|
|
| 1499 | - result.put(FieldNames.IMAGE_URL.name(), image.getURL().toString());
|
|
| 1500 | - result.put(FieldNames.IMAGE_LOCALE.name(), image.getLocale() != null ? image.getLocale().toLanguageTag() : null);
|
|
| 1501 | - result.put(FieldNames.IMAGE_TITLE.name(), image.getTitle());
|
|
| 1502 | - result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle());
|
|
| 1503 | - result.put(FieldNames.IMAGE_COPYRIGHT.name(), image.getCopyright());
|
|
| 1504 | - result.put(FieldNames.IMAGE_WIDTH_IN_PX.name(), image.getWidthInPx());
|
|
| 1505 | - result.put(FieldNames.IMAGE_HEIGHT_IN_PX.name(), image.getHeightInPx());
|
|
| 1506 | - storeTimePoint(image.getCreatedAtDate(), result, FieldNames.IMAGE_CREATEDATDATE);
|
|
| 1507 | - BasicDBList tags = new BasicDBList();
|
|
| 1508 | - for (String tag : image.getTags()) {
|
|
| 1509 | - tags.add(tag);
|
|
| 1510 | - }
|
|
| 1511 | - result.put(FieldNames.IMAGE_TAGS.name(), tags);
|
|
| 1512 | - return result;
|
|
| 1513 | - }
|
|
| 1514 | -
|
|
| 1515 | - private DBObject createVideoObject(VideoDescriptor video) {
|
|
| 1516 | - DBObject result = new BasicDBObject();
|
|
| 1517 | - result.put(FieldNames.VIDEO_URL.name(), video.getURL().toString());
|
|
| 1518 | - result.put(FieldNames.VIDEO_LOCALE.name(), video.getLocale() != null ? video.getLocale().toLanguageTag() : null);
|
|
| 1519 | - result.put(FieldNames.VIDEO_THUMBNAIL_URL.name(), video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null);
|
|
| 1520 | - result.put(FieldNames.VIDEO_TITLE.name(), video.getTitle());
|
|
| 1521 | - result.put(FieldNames.VIDEO_SUBTITLE.name(), video.getSubtitle());
|
|
| 1522 | - result.put(FieldNames.VIDEO_MIMETYPE.name(), video.getMimeType() != null ? video.getMimeType().name() : null);
|
|
| 1523 | - result.put(FieldNames.VIDEO_COPYRIGHT.name(), video.getCopyright());
|
|
| 1524 | - result.put(FieldNames.VIDEO_LENGTH_IN_SECONDS.name(), video.getLengthInSeconds());
|
|
| 1525 | - storeTimePoint(video.getCreatedAtDate(), result, FieldNames.VIDEO_CREATEDATDATE);
|
|
| 1526 | - BasicDBList tags = new BasicDBList();
|
|
| 1527 | - for (String tag : video.getTags()) {
|
|
| 1528 | - tags.add(tag);
|
|
| 1529 | - }
|
|
| 1530 | - result.put(FieldNames.VIDEO_TAGS.name(), tags);
|
|
| 1531 | - return result;
|
|
| 1532 | - }
|
|
| 1533 | -}
|
|
| 1 | +package com.sap.sailing.domain.persistence.impl; |
|
| 2 | + |
|
| 3 | +import java.io.Serializable; |
|
| 4 | +import java.net.URL; |
|
| 5 | +import java.util.List; |
|
| 6 | +import java.util.Map.Entry; |
|
| 7 | +import java.util.logging.Level; |
|
| 8 | +import java.util.logging.Logger; |
|
| 9 | + |
|
| 10 | +import org.bson.types.ObjectId; |
|
| 11 | +import org.json.simple.JSONObject; |
|
| 12 | + |
|
| 13 | +import com.mongodb.BasicDBList; |
|
| 14 | +import com.mongodb.BasicDBObject; |
|
| 15 | +import com.mongodb.BasicDBObjectBuilder; |
|
| 16 | +import com.mongodb.DB; |
|
| 17 | +import com.mongodb.DBCollection; |
|
| 18 | +import com.mongodb.DBObject; |
|
| 19 | +import com.mongodb.WriteConcern; |
|
| 20 | +import com.mongodb.util.JSON; |
|
| 21 | +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; |
|
| 22 | +import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent; |
|
| 23 | +import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; |
|
| 24 | +import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent; |
|
| 25 | +import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent; |
|
| 26 | +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; |
|
| 27 | +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; |
|
| 28 | +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent; |
|
| 29 | +import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent; |
|
| 30 | +import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; |
|
| 31 | +import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent; |
|
| 32 | +import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; |
|
| 33 | +import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; |
|
| 34 | +import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; |
|
| 35 | +import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; |
|
| 36 | +import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; |
|
| 37 | +import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; |
|
| 38 | +import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; |
|
| 39 | +import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; |
|
| 40 | +import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent; |
|
| 41 | +import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent; |
|
| 42 | +import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent; |
|
| 43 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent; |
|
| 44 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent; |
|
| 45 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; |
|
| 46 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; |
|
| 47 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent; |
|
| 48 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent; |
|
| 49 | +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent; |
|
| 50 | +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; |
|
| 51 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent; |
|
| 52 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent; |
|
| 53 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; |
|
| 54 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent; |
|
| 55 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent; |
|
| 56 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent; |
|
| 57 | +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent; |
|
| 58 | +import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; |
|
| 59 | +import com.sap.sailing.domain.base.Competitor; |
|
| 60 | +import com.sap.sailing.domain.base.ControlPoint; |
|
| 61 | +import com.sap.sailing.domain.base.ControlPointWithTwoMarks; |
|
| 62 | +import com.sap.sailing.domain.base.CourseArea; |
|
| 63 | +import com.sap.sailing.domain.base.CourseBase; |
|
| 64 | +import com.sap.sailing.domain.base.Event; |
|
| 65 | +import com.sap.sailing.domain.base.Fleet; |
|
| 66 | +import com.sap.sailing.domain.base.Mark; |
|
| 67 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 68 | +import com.sap.sailing.domain.base.RaceDefinition; |
|
| 69 | +import com.sap.sailing.domain.base.Regatta; |
|
| 70 | +import com.sap.sailing.domain.base.RemoteSailingServerReference; |
|
| 71 | +import com.sap.sailing.domain.base.SailingServerConfiguration; |
|
| 72 | +import com.sap.sailing.domain.base.Series; |
|
| 73 | +import com.sap.sailing.domain.base.Venue; |
|
| 74 | +import com.sap.sailing.domain.base.Waypoint; |
|
| 75 | +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; |
|
| 76 | +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; |
|
| 77 | +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; |
|
| 78 | +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti; |
|
| 79 | +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle; |
|
| 80 | +import com.sap.sailing.domain.base.impl.FleetImpl; |
|
| 81 | +import com.sap.sailing.domain.common.Bearing; |
|
| 82 | +import com.sap.sailing.domain.common.MaxPointsReason; |
|
| 83 | +import com.sap.sailing.domain.common.PassingInstruction; |
|
| 84 | +import com.sap.sailing.domain.common.Positioned; |
|
| 85 | +import com.sap.sailing.domain.common.RaceIdentifier; |
|
| 86 | +import com.sap.sailing.domain.common.Speed; |
|
| 87 | +import com.sap.sailing.domain.common.SpeedWithBearing; |
|
| 88 | +import com.sap.sailing.domain.common.Wind; |
|
| 89 | +import com.sap.sailing.domain.common.WindSource; |
|
| 90 | +import com.sap.sailing.domain.common.racelog.tracking.TransformationException; |
|
| 91 | +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; |
|
| 92 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 93 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; |
|
| 94 | +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; |
|
| 95 | +import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; |
|
| 96 | +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; |
|
| 97 | +import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; |
|
| 98 | +import com.sap.sailing.domain.persistence.MongoObjectFactory; |
|
| 99 | +import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; |
|
| 100 | +import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; |
|
| 101 | +import com.sap.sailing.domain.racelog.RaceLogIdentifier; |
|
| 102 | +import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; |
|
| 103 | +import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; |
|
| 104 | +import com.sap.sailing.domain.tracking.TrackedRace; |
|
| 105 | +import com.sap.sailing.domain.tracking.TrackedRegatta; |
|
| 106 | +import com.sap.sailing.domain.tracking.WindTrack; |
|
| 107 | +import com.sap.sailing.server.gateway.serialization.JsonSerializer; |
|
| 108 | +import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer; |
|
| 109 | +import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer; |
|
| 110 | +import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer; |
|
| 111 | +import com.sap.sse.common.Duration; |
|
| 112 | +import com.sap.sse.common.NoCorrespondingServiceRegisteredException; |
|
| 113 | +import com.sap.sse.common.TimePoint; |
|
| 114 | +import com.sap.sse.common.TimeRange; |
|
| 115 | +import com.sap.sse.common.Timed; |
|
| 116 | +import com.sap.sse.common.TypeBasedServiceFinder; |
|
| 117 | +import com.sap.sse.common.TypeBasedServiceFinderFactory; |
|
| 118 | +import com.sap.sse.common.Util; |
|
| 119 | +import com.sap.sse.common.impl.MillisecondsTimePoint; |
|
| 120 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 121 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 122 | + |
|
| 123 | +public class MongoObjectFactoryImpl implements MongoObjectFactory { |
|
| 124 | + private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName()); |
|
| 125 | + private final DB database; |
|
| 126 | + private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create(); |
|
| 127 | + private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder; |
|
| 128 | + |
|
| 129 | + /** |
|
| 130 | + * Uses <code>null</code> for the device type service finder and hence will be unable to store device identifiers. |
|
| 131 | + * Use this constructor only for testing purposes or in cases where there will happen absolutely no access to |
|
| 132 | + * {@link DeviceIdentifier} objects. |
|
| 133 | + */ |
|
| 134 | + public MongoObjectFactoryImpl(DB database) { |
|
| 135 | + this(database, /* deviceTypeServiceFinder */ null); |
|
| 136 | + } |
|
| 137 | + |
|
| 138 | + public MongoObjectFactoryImpl(DB database, TypeBasedServiceFinderFactory serviceFinderFactory) { |
|
| 139 | + this.database = database; |
|
| 140 | + if (serviceFinderFactory != null) { |
|
| 141 | + this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); |
|
| 142 | + this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); |
|
| 143 | + } else { |
|
| 144 | + this.deviceIdentifierServiceFinder = null; |
|
| 145 | + } |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + @Override |
|
| 149 | + public DB getDatabase() { |
|
| 150 | + return database; |
|
| 151 | + } |
|
| 152 | + |
|
| 153 | + public DBObject storeWind(Wind wind) { |
|
| 154 | + DBObject result = new BasicDBObject(); |
|
| 155 | + storePositioned(wind, result); |
|
| 156 | + storeTimed(wind, result); |
|
| 157 | + storeSpeedWithBearing(wind, result); |
|
| 158 | + return result; |
|
| 159 | + } |
|
| 160 | + |
|
| 161 | + public static void storeTimePoint(TimePoint timePoint, DBObject result, String fieldName) { |
|
| 162 | + if (timePoint != null) { |
|
| 163 | + result.put(fieldName, timePoint.asMillis()); |
|
| 164 | + } |
|
| 165 | + } |
|
| 166 | + |
|
| 167 | + public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) { |
|
| 168 | + storeTimePoint(timePoint, result, field.name()); |
|
| 169 | + } |
|
| 170 | + |
|
| 171 | + public static void storeTimeRange(TimeRange timeRange, DBObject result, FieldNames field) { |
|
| 172 | + if (timeRange != null) { |
|
| 173 | + DBObject timeRangeObj = new BasicDBObject(); |
|
| 174 | + storeTimePoint(timeRange.from(), timeRangeObj, FieldNames.FROM_MILLIS); |
|
| 175 | + storeTimePoint(timeRange.to(), timeRangeObj, FieldNames.TO_MILLIS); |
|
| 176 | + result.put(field.name(), timeRangeObj); |
|
| 177 | + } |
|
| 178 | + } |
|
| 179 | + |
|
| 180 | + public void storeTimed(Timed timed, DBObject result) { |
|
| 181 | + if (timed.getTimePoint() != null) { |
|
| 182 | + storeTimePoint(timed.getTimePoint(), result, FieldNames.TIME_AS_MILLIS); |
|
| 183 | + } |
|
| 184 | + } |
|
| 185 | + |
|
| 186 | + public void storeSpeedWithBearing(SpeedWithBearing speedWithBearing, DBObject result) { |
|
| 187 | + storeSpeed(speedWithBearing, result); |
|
| 188 | + storeBearing(speedWithBearing.getBearing(), result); |
|
| 189 | + |
|
| 190 | + } |
|
| 191 | + |
|
| 192 | + public void storeBearing(Bearing bearing, DBObject result) { |
|
| 193 | + result.put(FieldNames.DEGREE_BEARING.name(), bearing.getDegrees()); |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + public void storeSpeed(Speed speed, DBObject result) { |
|
| 197 | + result.put(FieldNames.KNOT_SPEED.name(), speed.getKnots()); |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + public void storePositioned(Positioned positioned, DBObject result) { |
|
| 201 | + if (positioned.getPosition() != null) { |
|
| 202 | + result.put(FieldNames.LAT_DEG.name(), positioned.getPosition().getLatDeg()); |
|
| 203 | + result.put(FieldNames.LNG_DEG.name(), positioned.getPosition().getLngDeg()); |
|
| 204 | + } |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + @Override |
|
| 208 | + public void addWindTrackDumper(TrackedRegatta trackedRegatta, TrackedRace trackedRace, WindSource windSource) { |
|
| 209 | + WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource); |
|
| 210 | + windTrack.addListener(new MongoWindListener(trackedRace, trackedRegatta.getRegatta().getName(), windSource, this, database)); |
|
| 211 | + } |
|
| 212 | + |
|
| 213 | + public DBCollection getWindTrackCollection() { |
|
| 214 | + DBCollection result = database.getCollection(CollectionNames.WIND_TRACKS.name()); |
|
| 215 | + result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), null)); |
|
| 216 | + return result; |
|
| 217 | + } |
|
| 218 | + |
|
| 219 | + public DBCollection getGPSFixCollection() { |
|
| 220 | + DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name()); |
|
| 221 | + DBObject index = new BasicDBObject(); |
|
| 222 | + index.put(FieldNames.DEVICE_ID.name(), null); |
|
| 223 | + index.put(FieldNames.TIME_AS_MILLIS.name(), null); |
|
| 224 | + gpsFixCollection.createIndex(index); |
|
| 225 | + return gpsFixCollection; |
|
| 226 | + } |
|
| 227 | + |
|
| 228 | + public DBCollection getGPSFixMetadataCollection() { |
|
| 229 | + DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name()); |
|
| 230 | + DBObject index = new BasicDBObject(); |
|
| 231 | + index.put(FieldNames.DEVICE_ID.name(), null); |
|
| 232 | + collection.createIndex(index); |
|
| 233 | + return collection; |
|
| 234 | + } |
|
| 235 | + |
|
| 236 | + /** |
|
| 237 | + * @param regattaName |
|
| 238 | + * the regatta name is stored only for human readability purposes because a time stamp may be a bit unhandy for |
|
| 239 | + * identifying where the wind fix was collected |
|
| 240 | + */ |
|
| 241 | + public DBObject storeWindTrackEntry(RaceDefinition race, String regattaName, WindSource windSource, Wind wind) { |
|
| 242 | + BasicDBObject result = new BasicDBObject(); |
|
| 243 | + result.put(FieldNames.RACE_ID.name(), race.getId()); |
|
| 244 | + result.put(FieldNames.REGATTA_NAME.name(), regattaName); |
|
| 245 | + result.put(FieldNames.WIND_SOURCE_NAME.name(), windSource.name()); |
|
| 246 | + if (windSource.getId() != null) { |
|
| 247 | + result.put(FieldNames.WIND_SOURCE_ID.name(), windSource.getId()); |
|
| 248 | + } |
|
| 249 | + result.put(FieldNames.WIND.name(), storeWind(wind)); |
|
| 250 | + return result; |
|
| 251 | + } |
|
| 252 | + |
|
| 253 | + private void storeRaceIdentifiers(RaceColumn raceColumn, DBObject dbObject) { |
|
| 254 | + BasicDBObject raceIdentifiersPerFleet = new BasicDBObject(); |
|
| 255 | + for (Fleet fleet : raceColumn.getFleets()) { |
|
| 256 | + RaceIdentifier raceIdentifier = raceColumn.getRaceIdentifier(fleet); |
|
| 257 | + if (raceIdentifier != null) { |
|
| 258 | + DBObject raceIdentifierForFleet = new BasicDBObject(); |
|
| 259 | + storeRaceIdentifier(raceIdentifierForFleet, raceIdentifier); |
|
| 260 | + raceIdentifiersPerFleet.put(MongoUtils.escapeDollarAndDot(fleet.getName()), raceIdentifierForFleet); |
|
| 261 | + } |
|
| 262 | + } |
|
| 263 | + dbObject.put(FieldNames.RACE_IDENTIFIERS.name(), raceIdentifiersPerFleet); |
|
| 264 | + } |
|
| 265 | + |
|
| 266 | + private void storeRaceIdentifier(DBObject dbObject, RaceIdentifier raceIdentifier) { |
|
| 267 | + if (raceIdentifier != null) { |
|
| 268 | + dbObject.put(FieldNames.EVENT_NAME.name(), raceIdentifier.getRegattaName()); |
|
| 269 | + dbObject.put(FieldNames.RACE_NAME.name(), raceIdentifier.getRaceName()); |
|
| 270 | + } |
|
| 271 | + } |
|
| 272 | + |
|
| 273 | + @Override |
|
| 274 | + public void storeLeaderboard(Leaderboard leaderboard) { |
|
| 275 | + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); |
|
| 276 | + try { |
|
| 277 | + leaderboardCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), 1)); |
|
| 278 | + } catch (NullPointerException npe) { |
|
| 279 | + // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE |
|
| 280 | + logger.log(Level.SEVERE, "storeLeaderboard", npe); |
|
| 281 | + } |
|
| 282 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); |
|
| 283 | + BasicDBObject dbLeaderboard = new BasicDBObject(); |
|
| 284 | + dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); |
|
| 285 | + if (leaderboard.getDisplayName() != null) { |
|
| 286 | + dbLeaderboard.put(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), leaderboard.getDisplayName()); |
|
| 287 | + } |
|
| 288 | + BasicDBList dbSuppressedCompetitorIds = new BasicDBList(); |
|
| 289 | + for (Competitor suppressedCompetitor : leaderboard.getSuppressedCompetitors()) { |
|
| 290 | + dbSuppressedCompetitorIds.add(suppressedCompetitor.getId()); |
|
| 291 | + } |
|
| 292 | + dbLeaderboard.put(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name(), dbSuppressedCompetitorIds); |
|
| 293 | + if (leaderboard instanceof FlexibleLeaderboard) { |
|
| 294 | + storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard, dbLeaderboard); |
|
| 295 | + } else if (leaderboard instanceof RegattaLeaderboard) { |
|
| 296 | + storeRegattaLeaderboard((RegattaLeaderboard) leaderboard, dbLeaderboard); |
|
| 297 | + } else { |
|
| 298 | + // at least store the scoring scheme |
|
| 299 | + dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); |
|
| 300 | + } |
|
| 301 | + if (leaderboard.getDefaultCourseArea() != null) { |
|
| 302 | + dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), leaderboard.getDefaultCourseArea().getId().toString()); |
|
| 303 | + } else { |
|
| 304 | + dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), null); |
|
| 305 | + } |
|
| 306 | + storeColumnFactors(leaderboard, dbLeaderboard); |
|
| 307 | + storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard); |
|
| 308 | + leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 309 | + } |
|
| 310 | + |
|
| 311 | + private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { |
|
| 312 | + DBObject raceColumnFactors = new BasicDBObject(); |
|
| 313 | + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { |
|
| 314 | + Double explicitFactor = raceColumn.getExplicitFactor(); |
|
| 315 | + if (explicitFactor != null) { |
|
| 316 | + raceColumnFactors.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), explicitFactor); |
|
| 317 | + } |
|
| 318 | + } |
|
| 319 | + dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMN_FACTORS.name(), raceColumnFactors); |
|
| 320 | + } |
|
| 321 | + |
|
| 322 | + private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) { |
|
| 323 | + dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName()); |
|
| 324 | + } |
|
| 325 | + |
|
| 326 | + private void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard, BasicDBObject dbLeaderboard) { |
|
| 327 | + BasicDBList dbRaceColumns = new BasicDBList(); |
|
| 328 | + dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); |
|
| 329 | + dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns); |
|
| 330 | + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { |
|
| 331 | + BasicDBObject dbRaceColumn = storeRaceColumn(raceColumn); |
|
| 332 | + dbRaceColumns.add(dbRaceColumn); |
|
| 333 | + } |
|
| 334 | + } |
|
| 335 | + |
|
| 336 | + private void storeLeaderboardCorrectionsAndDiscards(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { |
|
| 337 | + if (leaderboard.hasCarriedPoints()) { |
|
| 338 | + BasicDBList dbCarriedPoints = new BasicDBList(); |
|
| 339 | + dbLeaderboard.put(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name(), dbCarriedPoints); |
|
| 340 | + for (Entry<Competitor, Double> competitorWithCarriedPoints : leaderboard |
|
| 341 | + .getCompetitorsForWhichThereAreCarriedPoints().entrySet()) { |
|
| 342 | + double carriedPoints = competitorWithCarriedPoints.getValue(); |
|
| 343 | + Competitor competitor = competitorWithCarriedPoints.getKey(); |
|
| 344 | + DBObject dbCarriedPointsForCompetitor = new BasicDBObject(); |
|
| 345 | + dbCarriedPointsForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); |
|
| 346 | + dbCarriedPointsForCompetitor.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), carriedPoints); |
|
| 347 | + dbCarriedPoints.add(dbCarriedPointsForCompetitor); |
|
| 348 | + } |
|
| 349 | + } |
|
| 350 | + BasicDBObject dbScoreCorrections = new BasicDBObject(); |
|
| 351 | + storeScoreCorrections(leaderboard, dbScoreCorrections); |
|
| 352 | + dbLeaderboard.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections); |
|
| 353 | + final ResultDiscardingRule resultDiscardingRule = leaderboard.getResultDiscardingRule(); |
|
| 354 | + storeResultDiscardingRule(dbLeaderboard, resultDiscardingRule, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS); |
|
| 355 | + BasicDBList competitorDisplayNames = new BasicDBList(); |
|
| 356 | + for (Competitor competitor : leaderboard.getCompetitors()) { |
|
| 357 | + String displayNameForCompetitor = leaderboard.getDisplayName(competitor); |
|
| 358 | + if (displayNameForCompetitor != null) { |
|
| 359 | + DBObject dbDisplayName = new BasicDBObject(); |
|
| 360 | + dbDisplayName.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); |
|
| 361 | + dbDisplayName.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), displayNameForCompetitor); |
|
| 362 | + competitorDisplayNames.add(dbDisplayName); |
|
| 363 | + } |
|
| 364 | + } |
|
| 365 | + dbLeaderboard.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames); |
|
| 366 | + } |
|
| 367 | + |
|
| 368 | + /** |
|
| 369 | + * Stores the result discarding rule to <code>dbObject</code>'s field identified by <code>field</code> if the result discarding |
|
| 370 | + * rule is not <code>null</code> and is of type {@link ThresholdBasedResultDiscardingRule}. Otherwise, it is assumed that the |
|
| 371 | + * result discarding rule is otherwise implicitly obtained, e.g., from a definition of a regatta with its series, stored elsewhere. |
|
| 372 | + */ |
|
| 373 | + private void storeResultDiscardingRule(DBObject dbObject, |
|
| 374 | + final ResultDiscardingRule resultDiscardingRule, FieldNames field) { |
|
| 375 | + if (resultDiscardingRule != null && resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) { |
|
| 376 | + BasicDBList dbResultDiscardingThresholds = new BasicDBList(); |
|
| 377 | + for (int threshold : ((ThresholdBasedResultDiscardingRule) resultDiscardingRule).getDiscardIndexResultsStartingWithHowManyRaces()) { |
|
| 378 | + dbResultDiscardingThresholds.add(threshold); |
|
| 379 | + } |
|
| 380 | + dbObject.put(field.name(), dbResultDiscardingThresholds); |
|
| 381 | + } |
|
| 382 | + } |
|
| 383 | + |
|
| 384 | + private BasicDBObject storeRaceColumn(RaceColumn raceColumn) { |
|
| 385 | + BasicDBObject dbRaceColumn = new BasicDBObject(); |
|
| 386 | + dbRaceColumn.put(FieldNames.LEADERBOARD_COLUMN_NAME.name(), raceColumn.getName()); |
|
| 387 | + dbRaceColumn.put(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name(), raceColumn.isMedalRace()); |
|
| 388 | + storeRaceIdentifiers(raceColumn, dbRaceColumn); |
|
| 389 | + return dbRaceColumn; |
|
| 390 | + } |
|
| 391 | + |
|
| 392 | + private void storeScoreCorrections(Leaderboard leaderboard, BasicDBObject dbScoreCorrections) { |
|
| 393 | + TimePoint now = MillisecondsTimePoint.now(); |
|
| 394 | + SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); |
|
| 395 | + for (RaceColumn raceColumn : scoreCorrection.getRaceColumnsThatHaveCorrections()) { |
|
| 396 | + BasicDBList dbCorrectionForRace = new BasicDBList(); |
|
| 397 | + for (Competitor competitor : scoreCorrection.getCompetitorsThatHaveCorrectionsIn(raceColumn)) { |
|
| 398 | + // TODO bug 655: make score corrections time dependent |
|
| 399 | + if (scoreCorrection.isScoreCorrected(competitor, raceColumn, now)) { |
|
| 400 | + BasicDBObject dbCorrectionForCompetitor = new BasicDBObject(); |
|
| 401 | + dbCorrectionForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); |
|
| 402 | + MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn, now); |
|
| 403 | + if (maxPointsReason != MaxPointsReason.NONE) { |
|
| 404 | + dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), |
|
| 405 | + maxPointsReason.name()); |
|
| 406 | + } |
|
| 407 | + Double explicitScoreCorrection = scoreCorrection |
|
| 408 | + .getExplicitScoreCorrection(competitor, raceColumn); |
|
| 409 | + if (explicitScoreCorrection != null) { |
|
| 410 | + dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_CORRECTED_SCORE.name(), |
|
| 411 | + explicitScoreCorrection); |
|
| 412 | + } |
|
| 413 | + dbCorrectionForRace.add(dbCorrectionForCompetitor); |
|
| 414 | + } |
|
| 415 | + } |
|
| 416 | + if (!dbCorrectionForRace.isEmpty()) { |
|
| 417 | + // using the column name as the key for the score corrections requires re-writing the score corrections |
|
| 418 | + // of a meta-leaderboard if the name of one of its leaderboards changes |
|
| 419 | + dbScoreCorrections.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), dbCorrectionForRace); |
|
| 420 | + } |
|
| 421 | + } |
|
| 422 | + final TimePoint timePointOfLastCorrectionsValidity = scoreCorrection.getTimePointOfLastCorrectionsValidity(); |
|
| 423 | + if (timePointOfLastCorrectionsValidity != null) { |
|
| 424 | + dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name(), timePointOfLastCorrectionsValidity.asMillis()); |
|
| 425 | + } |
|
| 426 | + if (scoreCorrection.getComment() != null) { |
|
| 427 | + dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), scoreCorrection.getComment()); |
|
| 428 | + } |
|
| 429 | + } |
|
| 430 | + |
|
| 431 | + @Override |
|
| 432 | + public void removeLeaderboard(String leaderboardName) { |
|
| 433 | + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); |
|
| 434 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboardName); |
|
| 435 | + leaderboardCollection.remove(query); |
|
| 436 | + } |
|
| 437 | + |
|
| 438 | + @Override |
|
| 439 | + public void renameLeaderboard(String oldName, String newName) { |
|
| 440 | + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); |
|
| 441 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), oldName); |
|
| 442 | + BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), newName)); |
|
| 443 | + leaderboardCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 444 | + } |
|
| 445 | + |
|
| 446 | + @Override |
|
| 447 | + public void storeLeaderboardGroup(LeaderboardGroup leaderboardGroup) { |
|
| 448 | + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); |
|
| 449 | + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); |
|
| 450 | + |
|
| 451 | + try { |
|
| 452 | + leaderboardGroupCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), 1)); |
|
| 453 | + } catch (NullPointerException npe) { |
|
| 454 | + // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE |
|
| 455 | + logger.log(Level.SEVERE, "storeLeaderboardGroup", npe); |
|
| 456 | + } |
|
| 457 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); |
|
| 458 | + BasicDBObject dbLeaderboardGroup = new BasicDBObject(); |
|
| 459 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), leaderboardGroup.getId()); |
|
| 460 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); |
|
| 461 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name(), leaderboardGroup.getDescription()); |
|
| 462 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name(), leaderboardGroup.getDisplayName()); |
|
| 463 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name(), leaderboardGroup.isDisplayGroupsInReverseOrder()); |
|
| 464 | + final Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard(); |
|
| 465 | + if (overallLeaderboard != null) { |
|
| 466 | + BasicDBObject overallLeaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), overallLeaderboard.getName()); |
|
| 467 | + DBObject dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); |
|
| 468 | + if (dbOverallLeaderboard == null) { |
|
| 469 | + storeLeaderboard(overallLeaderboard); |
|
| 470 | + dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); |
|
| 471 | + } |
|
| 472 | + ObjectId dbOverallLeaderboardId = (ObjectId) dbOverallLeaderboard.get("_id"); |
|
| 473 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), dbOverallLeaderboardId); |
|
| 474 | + } |
|
| 475 | + BasicDBList dbLeaderboardIds = new BasicDBList(); |
|
| 476 | + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { |
|
| 477 | + BasicDBObject leaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); |
|
| 478 | + DBObject dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); |
|
| 479 | + if (dbLeaderboard == null) { |
|
| 480 | + storeLeaderboard(leaderboard); |
|
| 481 | + dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); |
|
| 482 | + } |
|
| 483 | + ObjectId dbLeaderboardId = (ObjectId) dbLeaderboard.get("_id"); |
|
| 484 | + dbLeaderboardIds.add(dbLeaderboardId); |
|
| 485 | + } |
|
| 486 | + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), dbLeaderboardIds); |
|
| 487 | + leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false, WriteConcern.SAFE); |
|
| 488 | + } |
|
| 489 | + |
|
| 490 | + @Override |
|
| 491 | + public void removeLeaderboardGroup(String groupName) { |
|
| 492 | + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); |
|
| 493 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), groupName); |
|
| 494 | + leaderboardGroupCollection.remove(query); |
|
| 495 | + } |
|
| 496 | + |
|
| 497 | + @Override |
|
| 498 | + public void renameLeaderboardGroup(String oldName, String newName) { |
|
| 499 | + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); |
|
| 500 | + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), oldName); |
|
| 501 | + BasicDBObject update = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), newName)); |
|
| 502 | + leaderboardGroupCollection.update(query, update, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 503 | + } |
|
| 504 | + |
|
| 505 | + @Override |
|
| 506 | + public void storeServerConfiguration(SailingServerConfiguration serverConfiguration) { |
|
| 507 | + DBCollection serverCollection = database.getCollection(CollectionNames.SERVER_CONFIGURATION.name()); |
|
| 508 | + DBObject newServerConfig = new BasicDBObject(); |
|
| 509 | + newServerConfig.put(FieldNames.SERVER_IS_STANDALONE.name(), serverConfiguration.isStandaloneServer()); |
|
| 510 | + DBObject currentServerConfig = serverCollection.findOne(); |
|
| 511 | + if(currentServerConfig != null) { |
|
| 512 | + serverCollection.update(currentServerConfig, newServerConfig, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 513 | + } else { |
|
| 514 | + serverCollection.save(newServerConfig); |
|
| 515 | + } |
|
| 516 | + } |
|
| 517 | + |
|
| 518 | + @Override |
|
| 519 | + public void storeSailingServer(RemoteSailingServerReference server) { |
|
| 520 | + DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); |
|
| 521 | + serverCollection.createIndex(new BasicDBObject(FieldNames.SERVER_NAME.name(), 1)); |
|
| 522 | + DBObject query = new BasicDBObject(); |
|
| 523 | + query.put(FieldNames.SERVER_NAME.name(), server.getName()); |
|
| 524 | + DBObject serverDBObject = new BasicDBObject(); |
|
| 525 | + serverDBObject.put(FieldNames.SERVER_NAME.name(), server.getName()); |
|
| 526 | + serverDBObject.put(FieldNames.SERVER_URL.name(), server.getURL().toExternalForm()); |
|
| 527 | + serverCollection.update(query, serverDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 528 | + } |
|
| 529 | + |
|
| 530 | + @Override |
|
| 531 | + public void removeSailingServer(String name) { |
|
| 532 | + DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); |
|
| 533 | + BasicDBObject query = new BasicDBObject(FieldNames.SERVER_NAME.name(), name); |
|
| 534 | + serverCollection.remove(query); |
|
| 535 | + } |
|
| 536 | + |
|
| 537 | + /** |
|
| 538 | + * StoreEvent() uses some deprecated methods of event to keep backward compatibility. |
|
| 539 | + */ |
|
| 540 | + @SuppressWarnings("deprecation") |
|
| 541 | + @Override |
|
| 542 | + public void storeEvent(Event event) { |
|
| 543 | + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); |
|
| 544 | + eventCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); |
|
| 545 | + DBObject query = new BasicDBObject(); |
|
| 546 | + query.put(FieldNames.EVENT_ID.name(), event.getId()); |
|
| 547 | + DBObject eventDBObject = new BasicDBObject(); |
|
| 548 | + eventDBObject.put(FieldNames.EVENT_NAME.name(), event.getName()); |
|
| 549 | + eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription()); |
|
| 550 | + eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId()); |
|
| 551 | + eventDBObject.put(FieldNames.EVENT_LOGO_IMAGE_URL.name(), event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null); |
|
| 552 | + eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); |
|
| 553 | + eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name(), event.getSailorsInfoWebsiteURL() != null ? event.getSailorsInfoWebsiteURL().toString() : null); |
|
| 554 | + storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE); |
|
| 555 | + storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE); |
|
| 556 | + eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic()); |
|
| 557 | + DBObject venueDBObject = getVenueAsDBObject(event.getVenue()); |
|
| 558 | + eventDBObject.put(FieldNames.VENUE.name(), venueDBObject); |
|
| 559 | + BasicDBList imageURLs = new BasicDBList(); |
|
| 560 | + for (URL imageURL : event.getImageURLs()) { |
|
| 561 | + imageURLs.add(imageURL.toString()); |
|
| 562 | + } |
|
| 563 | + eventDBObject.put(FieldNames.EVENT_IMAGE_URLS.name(), imageURLs); |
|
| 564 | + BasicDBList videoURLs = new BasicDBList(); |
|
| 565 | + for (URL videoURL : event.getVideoURLs()) { |
|
| 566 | + videoURLs.add(videoURL.toString()); |
|
| 567 | + } |
|
| 568 | + eventDBObject.put(FieldNames.EVENT_VIDEO_URLS.name(), videoURLs); |
|
| 569 | + BasicDBList sponsorImageURLs = new BasicDBList(); |
|
| 570 | + for (URL sponsorImageURL : event.getSponsorImageURLs()) { |
|
| 571 | + sponsorImageURLs.add(sponsorImageURL.toString()); |
|
| 572 | + } |
|
| 573 | + eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs); |
|
| 574 | + BasicDBList images = new BasicDBList(); |
|
| 575 | + for (ImageDescriptor image : event.getImages()) { |
|
| 576 | + DBObject imageObject = createImageObject(image); |
|
| 577 | + images.add(imageObject); |
|
| 578 | + } |
|
| 579 | + eventDBObject.put(FieldNames.EVENT_IMAGES.name(), images); |
|
| 580 | + BasicDBList videos = new BasicDBList(); |
|
| 581 | + for (VideoDescriptor video: event.getVideos()) { |
|
| 582 | + DBObject videoObject = createVideoObject(video); |
|
| 583 | + videos.add(videoObject); |
|
| 584 | + } |
|
| 585 | + eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos); |
|
| 586 | + eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 587 | + // now store the links to the leaderboard groups |
|
| 588 | + DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name()); |
|
| 589 | + linksCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); |
|
| 590 | + BasicDBList lgUUIDs = new BasicDBList(); |
|
| 591 | + for (LeaderboardGroup lg : event.getLeaderboardGroups()) { |
|
| 592 | + lgUUIDs.add(lg.getId()); |
|
| 593 | + } |
|
| 594 | + DBObject dbLinks = new BasicDBObject(); |
|
| 595 | + dbLinks.put(FieldNames.EVENT_ID.name(), event.getId()); |
|
| 596 | + dbLinks.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), lgUUIDs); |
|
| 597 | + linksCollection.update(query, dbLinks, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 598 | + } |
|
| 599 | + |
|
| 600 | + @Override |
|
| 601 | + public void renameEvent(Serializable id, String newName) { |
|
| 602 | + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); |
|
| 603 | + BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); |
|
| 604 | + BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.EVENT_NAME.name(), newName)); |
|
| 605 | + eventCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 606 | + } |
|
| 607 | + |
|
| 608 | + @Override |
|
| 609 | + public void removeEvent(Serializable id) { |
|
| 610 | + DBCollection eventsCollection = database.getCollection(CollectionNames.EVENTS.name()); |
|
| 611 | + BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); |
|
| 612 | + eventsCollection.remove(query); |
|
| 613 | + } |
|
| 614 | + |
|
| 615 | + private DBObject getVenueAsDBObject(Venue venue) { |
|
| 616 | + DBObject result = new BasicDBObject(); |
|
| 617 | + result.put(FieldNames.VENUE_NAME.name(), venue.getName()); |
|
| 618 | + BasicDBList courseAreaList = new BasicDBList(); |
|
| 619 | + result.put(FieldNames.COURSE_AREAS.name(), courseAreaList); |
|
| 620 | + for (CourseArea courseArea : venue.getCourseAreas()) { |
|
| 621 | + DBObject dbCourseArea = new BasicDBObject(); |
|
| 622 | + courseAreaList.add(dbCourseArea); |
|
| 623 | + dbCourseArea.put(FieldNames.COURSE_AREA_NAME.name(), courseArea.getName()); |
|
| 624 | + dbCourseArea.put(FieldNames.COURSE_AREA_ID.name(), courseArea.getId()); |
|
| 625 | + } |
|
| 626 | + return result; |
|
| 627 | + } |
|
| 628 | + |
|
| 629 | + @Override |
|
| 630 | + public void storeRegatta(Regatta regatta) { |
|
| 631 | + DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); |
|
| 632 | + regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); |
|
| 633 | + regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_ID.name(), 1)); |
|
| 634 | + DBObject dbRegatta = new BasicDBObject(); |
|
| 635 | + DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); |
|
| 636 | + dbRegatta.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); |
|
| 637 | + dbRegatta.put(FieldNames.REGATTA_ID.name(), regatta.getId()); |
|
| 638 | + storeTimePoint(regatta.getStartDate(), dbRegatta, FieldNames.REGATTA_START_DATE); |
|
| 639 | + storeTimePoint(regatta.getEndDate(), dbRegatta, FieldNames.REGATTA_END_DATE); |
|
| 640 | + dbRegatta.put(FieldNames.SCORING_SCHEME_TYPE.name(), regatta.getScoringScheme().getType().name()); |
|
| 641 | + if (regatta.getBoatClass() != null) { |
|
| 642 | + dbRegatta.put(FieldNames.BOAT_CLASS_NAME.name(), regatta.getBoatClass().getName()); |
|
| 643 | + dbRegatta.put(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name(), regatta.getBoatClass().typicallyStartsUpwind()); |
|
| 644 | + } |
|
| 645 | + dbRegatta.put(FieldNames.REGATTA_SERIES.name(), storeSeries(regatta.getSeries())); |
|
| 646 | + |
|
| 647 | + if (regatta.getDefaultCourseArea() != null) { |
|
| 648 | + dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), regatta.getDefaultCourseArea().getId().toString()); |
|
| 649 | + } else { |
|
| 650 | + dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), null); |
|
| 651 | + } |
|
| 652 | + if (regatta.getRegattaConfiguration() != null) { |
|
| 653 | + JsonSerializer<RegattaConfiguration> serializer = RegattaConfigurationJsonSerializer.create(); |
|
| 654 | + JSONObject json = serializer.serialize(regatta.getRegattaConfiguration()); |
|
| 655 | + DBObject configurationObject = (DBObject) JSON.parse(json.toString()); |
|
| 656 | + dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject); |
|
| 657 | + } |
|
| 658 | + dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference()); |
|
| 659 | + dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta)); |
|
| 660 | + regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 661 | + } |
|
| 662 | + |
|
| 663 | + private DBObject storeRankingMetric(Regatta regatta) { |
|
| 664 | + DBObject rankingMetricJson = new BasicDBObject(); |
|
| 665 | + final String rankingMetricTypeName = regatta.getRankingMetricType().name(); |
|
| 666 | + rankingMetricJson.put(FieldNames.REGATTA_RANKING_METRIC_TYPE.name(), rankingMetricTypeName); |
|
| 667 | + return rankingMetricJson; |
|
| 668 | + } |
|
| 669 | + |
|
| 670 | + @Override |
|
| 671 | + public void removeRegatta(Regatta regatta) { |
|
| 672 | + DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); |
|
| 673 | + DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); |
|
| 674 | + regattasCollection.remove(query); |
|
| 675 | + } |
|
| 676 | + |
|
| 677 | + private BasicDBList storeSeries(Iterable<? extends Series> series) { |
|
| 678 | + BasicDBList dbSeries = new BasicDBList(); |
|
| 679 | + for (Series s : series) { |
|
| 680 | + dbSeries.add(storeSeries(s)); |
|
| 681 | + } |
|
| 682 | + return dbSeries; |
|
| 683 | + } |
|
| 684 | + |
|
| 685 | + private DBObject storeSeries(Series s) { |
|
| 686 | + DBObject dbSeries = new BasicDBObject(); |
|
| 687 | + dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName()); |
|
| 688 | + dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal()); |
|
| 689 | + dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring()); |
|
| 690 | + dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore()); |
|
| 691 | + dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward()); |
|
| 692 | + BasicDBList dbFleets = new BasicDBList(); |
|
| 693 | + for (Fleet fleet : s.getFleets()) { |
|
| 694 | + dbFleets.add(storeFleet(fleet)); |
|
| 695 | + } |
|
| 696 | + dbSeries.put(FieldNames.SERIES_FLEETS.name(), dbFleets); |
|
| 697 | + BasicDBList dbRaceColumns = new BasicDBList(); |
|
| 698 | + for (RaceColumn raceColumn : s.getRaceColumns()) { |
|
| 699 | + dbRaceColumns.add(storeRaceColumn(raceColumn)); |
|
| 700 | + } |
|
| 701 | + dbSeries.put(FieldNames.SERIES_RACE_COLUMNS.name(), dbRaceColumns); |
|
| 702 | + if (s.getResultDiscardingRule() != null) { |
|
| 703 | + storeResultDiscardingRule(dbSeries, s.getResultDiscardingRule(), FieldNames.SERIES_DISCARDING_THRESHOLDS); |
|
| 704 | + } |
|
| 705 | + return dbSeries; |
|
| 706 | + } |
|
| 707 | + |
|
| 708 | + private DBObject storeFleet(Fleet fleet) { |
|
| 709 | + DBObject dbFleet = new BasicDBObject(FieldNames.FLEET_NAME.name(), fleet.getName()); |
|
| 710 | + if (fleet instanceof FleetImpl) { |
|
| 711 | + dbFleet.put(FieldNames.FLEET_ORDERING.name(), ((FleetImpl) fleet).getOrdering()); |
|
| 712 | + if(fleet.getColor() != null) { |
|
| 713 | + com.sap.sse.common.Util.Triple<Integer, Integer, Integer> colorAsRGB = fleet.getColor().getAsRGB(); |
|
| 714 | + // we save the color as a integer value representing the RGB values |
|
| 715 | + int colorAsInt = (256 * 256 * colorAsRGB.getC()) + colorAsRGB.getB() * 256 + colorAsRGB.getA(); |
|
| 716 | + dbFleet.put(FieldNames.FLEET_COLOR.name(), colorAsInt); |
|
| 717 | + } else { |
|
| 718 | + dbFleet.put(FieldNames.FLEET_COLOR.name(), null); |
|
| 719 | + } |
|
| 720 | + } |
|
| 721 | + return dbFleet; |
|
| 722 | + } |
|
| 723 | + |
|
| 724 | + @Override |
|
| 725 | + public void storeRegattaForRaceID(String raceIDAsString, Regatta regatta) { |
|
| 726 | + DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); |
|
| 727 | + DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); |
|
| 728 | + DBObject entry = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); |
|
| 729 | + entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); |
|
| 730 | + regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 731 | + } |
|
| 732 | + |
|
| 733 | + @Override |
|
| 734 | + public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) { |
|
| 735 | + DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); |
|
| 736 | + DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); |
|
| 737 | + regattaForRaceIDCollection.remove(query); |
|
| 738 | + } |
|
| 739 | + |
|
| 740 | + public DBCollection getRaceLogCollection() { |
|
| 741 | + DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name()); |
|
| 742 | + result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null)); |
|
| 743 | + return result; |
|
| 744 | + } |
|
| 745 | + |
|
| 746 | + private void storeRaceLogEventAuthor(DBObject dbObject, AbstractLogEventAuthor author) { |
|
| 747 | + if (author != null) { |
|
| 748 | + dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name(), author.getName()); |
|
| 749 | + dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name(), author.getPriority()); |
|
| 750 | + } |
|
| 751 | + } |
|
| 752 | + |
|
| 753 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFlagEvent flagEvent) { |
|
| 754 | + BasicDBObject result = new BasicDBObject(); |
|
| 755 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 756 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFlagEvent(flagEvent)); |
|
| 757 | + return result; |
|
| 758 | + } |
|
| 759 | + |
|
| 760 | + private void storeRaceLogIdentifier(RaceLogIdentifier raceLogIdentifier, DBObject result) { |
|
| 761 | + result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier())); |
|
| 762 | + } |
|
| 763 | + |
|
| 764 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTimeEvent startTimeEvent) { |
|
| 765 | + BasicDBObject result = new BasicDBObject(); |
|
| 766 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 767 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTimeEvent(startTimeEvent)); |
|
| 768 | + return result; |
|
| 769 | + } |
|
| 770 | + |
|
| 771 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPassChangeEvent passChangeEvent) { |
|
| 772 | + BasicDBObject result = new BasicDBObject(); |
|
| 773 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 774 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPassChangeEvent(passChangeEvent)); |
|
| 775 | + return result; |
|
| 776 | + } |
|
| 777 | + |
|
| 778 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent raceStatusEvent) { |
|
| 779 | + BasicDBObject result = new BasicDBObject(); |
|
| 780 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 781 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRaceStatusEvent(raceStatusEvent)); |
|
| 782 | + return result; |
|
| 783 | + } |
|
| 784 | + |
|
| 785 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { |
|
| 786 | + BasicDBObject result = new BasicDBObject(); |
|
| 787 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 788 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseAreaChangedEvent(courseAreaChangedEvent)); |
|
| 789 | + return result; |
|
| 790 | + } |
|
| 791 | + |
|
| 792 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { |
|
| 793 | + BasicDBObject result = new BasicDBObject(); |
|
| 794 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 795 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseDesignChangedEvent(courseDesignChangedEvent)); |
|
| 796 | + return result; |
|
| 797 | + } |
|
| 798 | + |
|
| 799 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { |
|
| 800 | + BasicDBObject result = new BasicDBObject(); |
|
| 801 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 802 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningListChangedEvent(finishPositioningListChangedEvent)); |
|
| 803 | + return result; |
|
| 804 | + } |
|
| 805 | + |
|
| 806 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { |
|
| 807 | + BasicDBObject result = new BasicDBObject(); |
|
| 808 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 809 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningConfirmedEvent(finishPositioningConfirmedEvent)); |
|
| 810 | + return result; |
|
| 811 | + } |
|
| 812 | + |
|
| 813 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPathfinderEvent pathfinderEvent) { |
|
| 814 | + BasicDBObject result = new BasicDBObject(); |
|
| 815 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 816 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPathfinderEvent(pathfinderEvent)); |
|
| 817 | + return result; |
|
| 818 | + } |
|
| 819 | + |
|
| 820 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent) { |
|
| 821 | + BasicDBObject result = new BasicDBObject(); |
|
| 822 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 823 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogGateLineOpeningTimeEvent(gateLineOpeningTimeEvent)); |
|
| 824 | + return result; |
|
| 825 | + } |
|
| 826 | + |
|
| 827 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartProcedureChangedEvent event) { |
|
| 828 | + DBObject result = new BasicDBObject(); |
|
| 829 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 830 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartProcedureChangedEvent(event)); |
|
| 831 | + return result; |
|
| 832 | + } |
|
| 833 | + |
|
| 834 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogProtestStartTimeEvent event) { |
|
| 835 | + DBObject result = new BasicDBObject(); |
|
| 836 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 837 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogProtestStartTimeEvent(event)); |
|
| 838 | + return result; |
|
| 839 | + } |
|
| 840 | + |
|
| 841 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogWindFixEvent event) { |
|
| 842 | + DBObject result = new BasicDBObject(); |
|
| 843 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 844 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event)); |
|
| 845 | + return result; |
|
| 846 | + } |
|
| 847 | + |
|
| 848 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceCompetitorMappingEvent event) { |
|
| 849 | + BasicDBObject result = new BasicDBObject(); |
|
| 850 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 851 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceCompetitorMappingEvent(event)); |
|
| 852 | + return result; |
|
| 853 | + } |
|
| 854 | + |
|
| 855 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceMarkMappingEvent event) { |
|
| 856 | + BasicDBObject result = new BasicDBObject(); |
|
| 857 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 858 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceMarkMappingEvent(event)); |
|
| 859 | + return result; |
|
| 860 | + } |
|
| 861 | + |
|
| 862 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) { |
|
| 863 | + BasicDBObject result = new BasicDBObject(); |
|
| 864 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 865 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDenoteForTrackingEvent(event)); |
|
| 866 | + return result; |
|
| 867 | + } |
|
| 868 | + |
|
| 869 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTrackingEvent event) { |
|
| 870 | + BasicDBObject result = new BasicDBObject(); |
|
| 871 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 872 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTrackingEvent(event)); |
|
| 873 | + return result; |
|
| 874 | + } |
|
| 875 | + |
|
| 876 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRevokeEvent event) { |
|
| 877 | + BasicDBObject result = new BasicDBObject(); |
|
| 878 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 879 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRevokeEvent(event)); |
|
| 880 | + return result; |
|
| 881 | + } |
|
| 882 | + |
|
| 883 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRegisterCompetitorEvent event) { |
|
| 884 | + BasicDBObject result = new BasicDBObject(); |
|
| 885 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 886 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRegisterCompetitorEvent(event)); |
|
| 887 | + return result; |
|
| 888 | + } |
|
| 889 | + |
|
| 890 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDefineMarkEvent event) { |
|
| 891 | + BasicDBObject result = new BasicDBObject(); |
|
| 892 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 893 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDefineMarkEvent(event)); |
|
| 894 | + return result; |
|
| 895 | + } |
|
| 896 | + |
|
| 897 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCloseOpenEndedDeviceMappingEvent event) { |
|
| 898 | + BasicDBObject result = new BasicDBObject(); |
|
| 899 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 900 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCloseOpenEndedDeviceMappingEvent(event)); |
|
| 901 | + return result; |
|
| 902 | + } |
|
| 903 | + |
|
| 904 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogEndOfTrackingEvent event) { |
|
| 905 | + BasicDBObject result = new BasicDBObject(); |
|
| 906 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 907 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogEndOfTrackingEvent(event)); |
|
| 908 | + return result; |
|
| 909 | + } |
|
| 910 | + |
|
| 911 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartOfTrackingEvent event) { |
|
| 912 | + BasicDBObject result = new BasicDBObject(); |
|
| 913 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 914 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartOfTrackingEvent(event)); |
|
| 915 | + return result; |
|
| 916 | + } |
|
| 917 | + |
|
| 918 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogAdditionalScoringInformationEvent event) { |
|
| 919 | + BasicDBObject result = new BasicDBObject(); |
|
| 920 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 921 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeAdditionalScoringInformation(event)); |
|
| 922 | + return result; |
|
| 923 | + } |
|
| 924 | + |
|
| 925 | + private Object storeAdditionalScoringInformation(RaceLogAdditionalScoringInformationEvent event) { |
|
| 926 | + DBObject result = new BasicDBObject(); |
|
| 927 | + storeRaceLogEventProperties(event, result); |
|
| 928 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogAdditionalScoringInformationEvent.class.getSimpleName()); |
|
| 929 | + result.put(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name(), event.getType().name()); |
|
| 930 | + return result; |
|
| 931 | + } |
|
| 932 | + |
|
| 933 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFixedMarkPassingEvent event) { |
|
| 934 | + BasicDBObject result = new BasicDBObject(); |
|
| 935 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 936 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFixedMarkPassingEvent(event)); |
|
| 937 | + return result; |
|
| 938 | + } |
|
| 939 | + |
|
| 940 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogSuppressedMarkPassingsEvent event) { |
|
| 941 | + BasicDBObject result = new BasicDBObject(); |
|
| 942 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 943 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogSuppressedMarkPassingsEvent(event)); |
|
| 944 | + return result; |
|
| 945 | + } |
|
| 946 | + |
|
| 947 | + private Object storeRaceLogWindFix(RaceLogWindFixEvent event) { |
|
| 948 | + DBObject result = new BasicDBObject(); |
|
| 949 | + storeRaceLogEventProperties(event, result); |
|
| 950 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogWindFixEvent.class.getSimpleName()); |
|
| 951 | + result.put(FieldNames.WIND.name(), storeWind(event.getWindFix())); |
|
| 952 | + result.put(FieldNames.IS_MAGNETIC.name(), event.isMagnetic()); |
|
| 953 | + return result; |
|
| 954 | + } |
|
| 955 | + |
|
| 956 | + private Object storeRaceLogProtestStartTimeEvent(RaceLogProtestStartTimeEvent event) { |
|
| 957 | + DBObject result = new BasicDBObject(); |
|
| 958 | + storeRaceLogEventProperties(event, result); |
|
| 959 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogProtestStartTimeEvent.class.getSimpleName()); |
|
| 960 | + storeTimePoint(event.getProtestStartTime(), result, FieldNames.RACE_LOG_PROTEST_START_TIME); |
|
| 961 | + return result; |
|
| 962 | + } |
|
| 963 | + |
|
| 964 | + private Object storeRaceLogEndOfTrackingEvent(RaceLogEndOfTrackingEvent event) { |
|
| 965 | + DBObject result = new BasicDBObject(); |
|
| 966 | + storeRaceLogEventProperties(event, result); |
|
| 967 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogEndOfTrackingEvent.class.getSimpleName()); |
|
| 968 | + return result; |
|
| 969 | + } |
|
| 970 | + |
|
| 971 | + private Object storeRaceLogStartOfTrackingEvent(RaceLogStartOfTrackingEvent event) { |
|
| 972 | + DBObject result = new BasicDBObject(); |
|
| 973 | + storeRaceLogEventProperties(event, result); |
|
| 974 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartOfTrackingEvent.class.getSimpleName()); |
|
| 975 | + return result; |
|
| 976 | + } |
|
| 977 | + |
|
| 978 | + private Object storeRaceLogStartProcedureChangedEvent(RaceLogStartProcedureChangedEvent event) { |
|
| 979 | + DBObject result = new BasicDBObject(); |
|
| 980 | + storeRaceLogEventProperties(event, result); |
|
| 981 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartProcedureChangedEvent.class.getSimpleName()); |
|
| 982 | + result.put(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name(), event.getStartProcedureType().name()); |
|
| 983 | + return result; |
|
| 984 | + } |
|
| 985 | + |
|
| 986 | + private Object storeRaceLogPathfinderEvent(RaceLogPathfinderEvent pathfinderEvent) { |
|
| 987 | + DBObject result = new BasicDBObject(); |
|
| 988 | + storeRaceLogEventProperties(pathfinderEvent, result); |
|
| 989 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPathfinderEvent.class.getSimpleName()); |
|
| 990 | + result.put(FieldNames.RACE_LOG_PATHFINDER_ID.name(), pathfinderEvent.getPathfinderId()); |
|
| 991 | + return result; |
|
| 992 | + } |
|
| 993 | + |
|
| 994 | + private void storeDeviceMappingEvent(DeviceMappingEvent<?, ?> event, DBObject result, FieldNames fromField, FieldNames toField) { |
|
| 995 | + try { |
|
| 996 | + result.put(FieldNames.DEVICE_ID.name(), storeDeviceId(deviceIdentifierServiceFinder, event.getDevice())); |
|
| 997 | + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { |
|
| 998 | + logger.log(Level.WARNING, "Could not store device identifier for mappng event", e); |
|
| 999 | + } |
|
| 1000 | + if (event.getFrom() != null) { |
|
| 1001 | + storeTimePoint(event.getFrom(), result, fromField); |
|
| 1002 | + } |
|
| 1003 | + if (event.getTo() != null) { |
|
| 1004 | + storeTimePoint(event.getTo(), result, toField); |
|
| 1005 | + } |
|
| 1006 | + } |
|
| 1007 | + |
|
| 1008 | + private Object storeRaceLogDeviceCompetitorMappingEvent(RaceLogDeviceCompetitorMappingEvent event) { |
|
| 1009 | + DBObject result = new BasicDBObject(); |
|
| 1010 | + storeRaceLogEventProperties(event, result); |
|
| 1011 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceCompetitorMappingEvent.class.getSimpleName()); |
|
| 1012 | + storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO); |
|
| 1013 | + result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId()); |
|
| 1014 | + return result; |
|
| 1015 | + } |
|
| 1016 | + |
|
| 1017 | + private Object storeRaceLogDeviceMarkMappingEvent(RaceLogDeviceMarkMappingEvent event) { |
|
| 1018 | + DBObject result = new BasicDBObject(); |
|
| 1019 | + storeRaceLogEventProperties(event, result); |
|
| 1020 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceMarkMappingEvent.class.getSimpleName()); |
|
| 1021 | + storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO); |
|
| 1022 | + result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo())); |
|
| 1023 | + return result; |
|
| 1024 | + } |
|
| 1025 | + |
|
| 1026 | + private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) { |
|
| 1027 | + DBObject result = new BasicDBObject(); |
|
| 1028 | + storeRaceLogEventProperties(event, result); |
|
| 1029 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDenoteForTrackingEvent.class.getSimpleName()); |
|
| 1030 | + result.put(FieldNames.RACE_NAME.name(), event.getRaceName()); |
|
| 1031 | + result.put(FieldNames.BOAT_CLASS_NAME.name(), event.getBoatClass().getName()); |
|
| 1032 | + result.put(FieldNames.RACE_ID.name(), event.getRaceId()); |
|
| 1033 | + return result; |
|
| 1034 | + } |
|
| 1035 | + |
|
| 1036 | + private Object storeRaceLogStartTrackingEvent(RaceLogStartTrackingEvent event) { |
|
| 1037 | + DBObject result = new BasicDBObject(); |
|
| 1038 | + storeRaceLogEventProperties(event, result); |
|
| 1039 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTrackingEvent.class.getSimpleName()); |
|
| 1040 | + return result; |
|
| 1041 | + } |
|
| 1042 | + |
|
| 1043 | + private Object storeRaceLogRevokeEvent(RaceLogRevokeEvent event) { |
|
| 1044 | + DBObject result = new BasicDBObject(); |
|
| 1045 | + storeRaceLogEventProperties(event, result); |
|
| 1046 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRevokeEvent.class.getSimpleName()); |
|
| 1047 | + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); |
|
| 1048 | + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); |
|
| 1049 | + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); |
|
| 1050 | + result.put(FieldNames.RACE_LOG_REVOKED_REASON.name(), event.getReason()); |
|
| 1051 | + return result; |
|
| 1052 | + } |
|
| 1053 | + |
|
| 1054 | + private Object storeRaceLogRegisterCompetitorEvent(RaceLogRegisterCompetitorEvent event) { |
|
| 1055 | + DBObject result = new BasicDBObject(); |
|
| 1056 | + storeRaceLogEventProperties(event, result); |
|
| 1057 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRegisterCompetitorEvent.class.getSimpleName()); |
|
| 1058 | + result.put(FieldNames.RACE_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); |
|
| 1059 | + return result; |
|
| 1060 | + } |
|
| 1061 | + |
|
| 1062 | + private Object storeRaceLogDefineMarkEvent(RaceLogDefineMarkEvent event) { |
|
| 1063 | + DBObject result = new BasicDBObject(); |
|
| 1064 | + storeRaceLogEventProperties(event, result); |
|
| 1065 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDefineMarkEvent.class.getSimpleName()); |
|
| 1066 | + result.put(FieldNames.RACE_LOG_MARK.name(), storeMark(event.getMark())); |
|
| 1067 | + return result; |
|
| 1068 | + } |
|
| 1069 | + |
|
| 1070 | + private Object storeRaceLogCloseOpenEndedDeviceMappingEvent(RaceLogCloseOpenEndedDeviceMappingEvent event) { |
|
| 1071 | + DBObject result = new BasicDBObject(); |
|
| 1072 | + storeRaceLogEventProperties(event, result); |
|
| 1073 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); |
|
| 1074 | + result.put(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId()); |
|
| 1075 | + storeTimePoint(event.getClosingTimePoint(), result, FieldNames.RACE_LOG_CLOSING_TIMEPOINT); |
|
| 1076 | + return result; |
|
| 1077 | + } |
|
| 1078 | + |
|
| 1079 | + private Object storeRaceLogFixedMarkPassingEvent(RaceLogFixedMarkPassingEvent event) { |
|
| 1080 | + DBObject result = new BasicDBObject(); |
|
| 1081 | + storeRaceLogEventProperties(event, result); |
|
| 1082 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFixedMarkPassingEvent.class.getSimpleName()); |
|
| 1083 | + result.put(FieldNames.INDEX_OF_PASSED_WAYPOINT.name(), event.getZeroBasedIndexOfPassedWaypoint()); |
|
| 1084 | + result.put(FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING.name(), event.getTimePointOfFixedPassing().asMillis()); |
|
| 1085 | + return result; |
|
| 1086 | + } |
|
| 1087 | + |
|
| 1088 | + private Object storeRaceLogSuppressedMarkPassingsEvent(RaceLogSuppressedMarkPassingsEvent event) { |
|
| 1089 | + DBObject result = new BasicDBObject(); |
|
| 1090 | + storeRaceLogEventProperties(event, result); |
|
| 1091 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogSuppressedMarkPassingsEvent.class.getSimpleName()); |
|
| 1092 | + result.put(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name(), event.getZeroBasedIndexOfFirstSuppressedWaypoint()); |
|
| 1093 | + return result; |
|
| 1094 | + } |
|
| 1095 | + |
|
| 1096 | + public DBObject storeRaceLogFlagEvent(RaceLogFlagEvent flagEvent) { |
|
| 1097 | + DBObject result = new BasicDBObject(); |
|
| 1098 | + storeRaceLogEventProperties(flagEvent, result); |
|
| 1099 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFlagEvent.class.getSimpleName()); |
|
| 1100 | + result.put(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name(), flagEvent.getUpperFlag().name()); |
|
| 1101 | + result.put(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name(), flagEvent.getLowerFlag().name()); |
|
| 1102 | + result.put(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name(), String.valueOf(flagEvent.isDisplayed())); |
|
| 1103 | + return result; |
|
| 1104 | + } |
|
| 1105 | + |
|
| 1106 | + private DBObject storeRaceLogStartTimeEvent(RaceLogStartTimeEvent startTimeEvent) { |
|
| 1107 | + DBObject result = new BasicDBObject(); |
|
| 1108 | + storeRaceLogEventProperties(startTimeEvent, result); |
|
| 1109 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTimeEvent.class.getSimpleName()); |
|
| 1110 | + storeTimePoint(startTimeEvent.getStartTime(), result, FieldNames.RACE_LOG_EVENT_START_TIME); |
|
| 1111 | + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), startTimeEvent.getNextStatus().name()); |
|
| 1112 | + return result; |
|
| 1113 | + } |
|
| 1114 | + |
|
| 1115 | + private void storeRaceLogEventProperties(RaceLogEvent event, DBObject result) { |
|
| 1116 | + // for compatibility reasons we reuse the field name of Timed |
|
| 1117 | + storeTimePoint(event.getLogicalTimePoint(), result, FieldNames.TIME_AS_MILLIS); |
|
| 1118 | + storeTimePoint(event.getCreatedAt(), result, FieldNames.RACE_LOG_EVENT_CREATED_AT); |
|
| 1119 | + result.put(FieldNames.RACE_LOG_EVENT_ID.name(), event.getId()); |
|
| 1120 | + result.put(FieldNames.RACE_LOG_EVENT_PASS_ID.name(), event.getPassId()); |
|
| 1121 | + result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedBoats())); |
|
| 1122 | + storeRaceLogEventAuthor(result, event.getAuthor()); |
|
| 1123 | + } |
|
| 1124 | + |
|
| 1125 | + |
|
| 1126 | + private BasicDBList storeInvolvedBoatsForRaceLogEvent(List<Competitor> competitors) { |
|
| 1127 | + BasicDBList dbInvolvedCompetitorIds = new BasicDBList(); |
|
| 1128 | + for (Competitor competitor : competitors) { |
|
| 1129 | + dbInvolvedCompetitorIds.add(competitor.getId()); |
|
| 1130 | + } |
|
| 1131 | + return dbInvolvedCompetitorIds; |
|
| 1132 | + } |
|
| 1133 | + |
|
| 1134 | + private DBObject storeRaceLogPassChangeEvent(RaceLogPassChangeEvent passChangeEvent) { |
|
| 1135 | + DBObject result = new BasicDBObject(); |
|
| 1136 | + storeRaceLogEventProperties(passChangeEvent, result); |
|
| 1137 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPassChangeEvent.class.getSimpleName()); |
|
| 1138 | + return result; |
|
| 1139 | + } |
|
| 1140 | + |
|
| 1141 | + private DBObject storeRaceLogDependentStartTimeEvent(RaceLogDependentStartTimeEvent dependentStartTimeEvent) { |
|
| 1142 | + DBObject result = new BasicDBObject(); |
|
| 1143 | + storeRaceLogEventProperties(dependentStartTimeEvent, result); |
|
| 1144 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDependentStartTimeEvent.class.getSimpleName()); |
|
| 1145 | + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_REGATTALIKE.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRegattaLikeParentName()); |
|
| 1146 | + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_RACECOLUMN.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRaceColumnName()); |
|
| 1147 | + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_FLEET.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getFleetName()); |
|
| 1148 | + storeDuration(dependentStartTimeEvent.getStartTimeDifference(), result, FieldNames.RACE_LOG_START_TIME_DIFFERENCE_IN_MS); |
|
| 1149 | + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), dependentStartTimeEvent.getNextStatus().name()); |
|
| 1150 | + return result; |
|
| 1151 | + } |
|
| 1152 | + |
|
| 1153 | + private void storeDuration(Duration duration, DBObject result, FieldNames fieldName) { |
|
| 1154 | + if (duration != null) { |
|
| 1155 | + result.put(fieldName.name(), duration.asMillis()); |
|
| 1156 | + } |
|
| 1157 | + } |
|
| 1158 | + |
|
| 1159 | + private DBObject storeRaceLogRaceStatusEvent(RaceLogRaceStatusEvent raceStatusEvent) { |
|
| 1160 | + DBObject result = new BasicDBObject(); |
|
| 1161 | + storeRaceLogEventProperties(raceStatusEvent, result); |
|
| 1162 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRaceStatusEvent.class.getSimpleName()); |
|
| 1163 | + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), raceStatusEvent.getNextStatus().name()); |
|
| 1164 | + return result; |
|
| 1165 | + } |
|
| 1166 | + |
|
| 1167 | + private DBObject storeRaceLogCourseAreaChangedEvent(RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { |
|
| 1168 | + DBObject result = new BasicDBObject(); |
|
| 1169 | + storeRaceLogEventProperties(courseAreaChangedEvent, result); |
|
| 1170 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseAreaChangedEvent.class.getSimpleName()); |
|
| 1171 | + result.put(FieldNames.COURSE_AREA_ID.name(), courseAreaChangedEvent.getCourseAreaId()); |
|
| 1172 | + return result; |
|
| 1173 | + } |
|
| 1174 | + |
|
| 1175 | + private DBObject storeRaceLogCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { |
|
| 1176 | + DBObject result = new BasicDBObject(); |
|
| 1177 | + storeRaceLogEventProperties(courseDesignChangedEvent, result); |
|
| 1178 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName()); |
|
| 1179 | + result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName()); |
|
| 1180 | + result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign())); |
|
| 1181 | + return result; |
|
| 1182 | + } |
|
| 1183 | + |
|
| 1184 | + private Object storeRaceLogFinishPositioningListChangedEvent(RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { |
|
| 1185 | + DBObject result = new BasicDBObject(); |
|
| 1186 | + storeRaceLogEventProperties(finishPositioningListChangedEvent, result); |
|
| 1187 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningListChangedEvent.class.getSimpleName()); |
|
| 1188 | + result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); |
|
| 1189 | + |
|
| 1190 | + return result; |
|
| 1191 | + } |
|
| 1192 | + |
|
| 1193 | + private Object storeRaceLogFinishPositioningConfirmedEvent(RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { |
|
| 1194 | + DBObject result = new BasicDBObject(); |
|
| 1195 | + storeRaceLogEventProperties(finishPositioningConfirmedEvent, result); |
|
| 1196 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName()); |
|
| 1197 | + result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); |
|
| 1198 | + |
|
| 1199 | + return result; |
|
| 1200 | + } |
|
| 1201 | + |
|
| 1202 | + private Object storeRaceLogGateLineOpeningTimeEvent(RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent){ |
|
| 1203 | + DBObject result = new BasicDBObject(); |
|
| 1204 | + storeRaceLogEventProperties(gateLineOpeningTimeEvent, result); |
|
| 1205 | + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogGateLineOpeningTimeEvent.class.getSimpleName()); |
|
| 1206 | + result.put(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGateLaunchStopTime()); |
|
| 1207 | + result.put(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGolfDownTime()); |
|
| 1208 | + return result; |
|
| 1209 | + } |
|
| 1210 | + |
|
| 1211 | + private BasicDBList storePositionedCompetitors(List<com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason>> positionedCompetitors) { |
|
| 1212 | + BasicDBList dbList = new BasicDBList(); |
|
| 1213 | + if (positionedCompetitors != null) { |
|
| 1214 | + for (com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason> competitorPair : positionedCompetitors) { |
|
| 1215 | + dbList.add(storePositionedCompetitor(competitorPair)); |
|
| 1216 | + } |
|
| 1217 | + } |
|
| 1218 | + return dbList; |
|
| 1219 | + } |
|
| 1220 | + |
|
| 1221 | + private DBObject storePositionedCompetitor(com.sap.sse.common.Util.Triple<Serializable, String, MaxPointsReason> competitorTriple) { |
|
| 1222 | + DBObject result = new BasicDBObject(); |
|
| 1223 | + result.put(FieldNames.COMPETITOR_ID.name(), competitorTriple.getA()); |
|
| 1224 | + result.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), competitorTriple.getB()); |
|
| 1225 | + result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), competitorTriple.getC().name()); |
|
| 1226 | + |
|
| 1227 | + return result; |
|
| 1228 | + } |
|
| 1229 | + |
|
| 1230 | + private BasicDBList storeCourseBase(CourseBase courseData) { |
|
| 1231 | + BasicDBList dbList = new BasicDBList(); |
|
| 1232 | + |
|
| 1233 | + for (Waypoint waypoint : courseData.getWaypoints()) { |
|
| 1234 | + dbList.add(storeWaypoint(waypoint)); |
|
| 1235 | + } |
|
| 1236 | + return dbList; |
|
| 1237 | + } |
|
| 1238 | + |
|
| 1239 | + private DBObject storeWaypoint(Waypoint waypoint) { |
|
| 1240 | + DBObject result = new BasicDBObject(); |
|
| 1241 | + result.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), getPassingInstructions(waypoint.getPassingInstructions())); |
|
| 1242 | + result.put(FieldNames.CONTROLPOINT.name(), storeControlPoint(waypoint.getControlPoint())); |
|
| 1243 | + return result; |
|
| 1244 | + } |
|
| 1245 | + |
|
| 1246 | + private DBObject storeControlPoint(ControlPoint controlPoint) { |
|
| 1247 | + DBObject result = new BasicDBObject(); |
|
| 1248 | + if (controlPoint instanceof Mark) { |
|
| 1249 | + result.put(FieldNames.CONTROLPOINT_CLASS.name(), Mark.class.getSimpleName()); |
|
| 1250 | + result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeMark((Mark) controlPoint)); |
|
| 1251 | + } else if (controlPoint instanceof ControlPointWithTwoMarks) { |
|
| 1252 | + result.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); |
|
| 1253 | + result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeControlPointWithTwoMarks((ControlPointWithTwoMarks) controlPoint)); |
|
| 1254 | + } |
|
| 1255 | + return result; |
|
| 1256 | + } |
|
| 1257 | + |
|
| 1258 | + private DBObject storeControlPointWithTwoMarks(ControlPointWithTwoMarks cpwtm) { |
|
| 1259 | + DBObject result = new BasicDBObject(); |
|
| 1260 | + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), cpwtm.getId()); |
|
| 1261 | + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), cpwtm.getName()); |
|
| 1262 | + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), storeMark(cpwtm.getLeft())); |
|
| 1263 | + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), storeMark(cpwtm.getRight())); |
|
| 1264 | + return result; |
|
| 1265 | + } |
|
| 1266 | + |
|
| 1267 | + private DBObject storeMark(Mark mark) { |
|
| 1268 | + DBObject result = new BasicDBObject(); |
|
| 1269 | + result.put(FieldNames.MARK_ID.name(), mark.getId()); |
|
| 1270 | + result.put(FieldNames.MARK_COLOR.name(), mark.getColor()); |
|
| 1271 | + result.put(FieldNames.MARK_NAME.name(), mark.getName()); |
|
| 1272 | + result.put(FieldNames.MARK_PATTERN.name(), mark.getPattern()); |
|
| 1273 | + result.put(FieldNames.MARK_SHAPE.name(), mark.getShape()); |
|
| 1274 | + result.put(FieldNames.MARK_TYPE.name(), mark.getType() == null ? null : mark.getType().name()); |
|
| 1275 | + return result; |
|
| 1276 | + } |
|
| 1277 | + |
|
| 1278 | + private String getPassingInstructions(PassingInstruction passingInstructions) { |
|
| 1279 | + final String passing; |
|
| 1280 | + if (passingInstructions != null) { |
|
| 1281 | + passing = passingInstructions.name(); |
|
| 1282 | + } else { |
|
| 1283 | + passing = null; |
|
| 1284 | + } |
|
| 1285 | + return passing; |
|
| 1286 | + } |
|
| 1287 | + @Override |
|
| 1288 | + public void storeCompetitor(Competitor competitor) { |
|
| 1289 | + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); |
|
| 1290 | + JSONObject json = competitorSerializer.serialize(competitor); |
|
| 1291 | + DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); |
|
| 1292 | + DBObject entry = (DBObject) JSON.parse(json.toString()); |
|
| 1293 | + collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); |
|
| 1294 | + } |
|
| 1295 | + |
|
| 1296 | + @Override |
|
| 1297 | + public void removeAllCompetitors() { |
|
| 1298 | + logger.info("Removing all persistent competitor info"); |
|
| 1299 | + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); |
|
| 1300 | + collection.drop(); |
|
| 1301 | + } |
|
| 1302 | + |
|
| 1303 | + @Override |
|
| 1304 | + public void removeCompetitor(Competitor competitor) { |
|
| 1305 | + logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId()); |
|
| 1306 | + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); |
|
| 1307 | + DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); |
|
| 1308 | + collection.remove(query, WriteConcern.SAFE); |
|
| 1309 | + } |
|
| 1310 | + |
|
| 1311 | + @Override |
|
| 1312 | + public void storeDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) { |
|
| 1313 | + DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); |
|
| 1314 | + |
|
| 1315 | + DBObject query = new BasicDBObject(); |
|
| 1316 | + query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); |
|
| 1317 | + |
|
| 1318 | + DBObject entryObject = new BasicDBObject(); |
|
| 1319 | + entryObject.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); |
|
| 1320 | + entryObject.put(FieldNames.CONFIGURATION_MATCHER.name(), createDeviceConfigurationMatcherObject(matcher)); |
|
| 1321 | + entryObject.put(FieldNames.CONFIGURATION_CONFIG.name(), createDeviceConfigurationObject(configuration)); |
|
| 1322 | + |
|
| 1323 | + configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); |
|
| 1324 | + } |
|
| 1325 | + |
|
| 1326 | + private DBObject createDeviceConfigurationMatcherObject(DeviceConfigurationMatcher matcher) { |
|
| 1327 | + DBObject matcherObject = new BasicDBObject(); |
|
| 1328 | + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_TYPE.name(), matcher.getMatcherType().name()); |
|
| 1329 | + if (matcher instanceof DeviceConfigurationMatcherSingle) { |
|
| 1330 | + BasicDBList client = new BasicDBList(); |
|
| 1331 | + client.add(((DeviceConfigurationMatcherSingle)matcher).getClientIdentifier()); |
|
| 1332 | + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), client); |
|
| 1333 | + } else if (matcher instanceof DeviceConfigurationMatcherMulti) { |
|
| 1334 | + BasicDBList clients = new BasicDBList(); |
|
| 1335 | + Util.addAll(((DeviceConfigurationMatcherMulti)matcher).getClientIdentifiers(), clients); |
|
| 1336 | + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), clients); |
|
| 1337 | + } |
|
| 1338 | + return matcherObject; |
|
| 1339 | + } |
|
| 1340 | + |
|
| 1341 | + private DBObject createDeviceConfigurationObject(DeviceConfiguration configuration) { |
|
| 1342 | + JsonSerializer<DeviceConfiguration> serializer = DeviceConfigurationJsonSerializer.create(); |
|
| 1343 | + JSONObject json = serializer.serialize(configuration); |
|
| 1344 | + DBObject entry = (DBObject) JSON.parse(json.toString()); |
|
| 1345 | + return entry; |
|
| 1346 | + } |
|
| 1347 | + |
|
| 1348 | + @Override |
|
| 1349 | + public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) { |
|
| 1350 | + DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); |
|
| 1351 | + DBObject query = new BasicDBObject(); |
|
| 1352 | + query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); |
|
| 1353 | + configurationsCollections.remove(query); |
|
| 1354 | + } |
|
| 1355 | + |
|
| 1356 | + public static DBObject storeDeviceId( |
|
| 1357 | + TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder, DeviceIdentifier device) |
|
| 1358 | + throws TransformationException, NoCorrespondingServiceRegisteredException { |
|
| 1359 | + String type = device.getIdentifierType(); |
|
| 1360 | + DeviceIdentifierMongoHandler handler = deviceIdentifierServiceFinder.findService(type); |
|
| 1361 | + com.sap.sse.common.Util.Pair<String, ? extends Object> pair = handler.serialize(device); |
|
| 1362 | + type = pair.getA(); |
|
| 1363 | + Object deviceTypeSpecificId = pair.getB(); |
|
| 1364 | + return new BasicDBObjectBuilder() |
|
| 1365 | + .add(FieldNames.DEVICE_TYPE.name(), type) |
|
| 1366 | + .add(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), deviceTypeSpecificId) |
|
| 1367 | + .add(FieldNames.DEVICE_STRING_REPRESENTATION.name(), device.getStringRepresentation()).get(); |
|
| 1368 | + } |
|
| 1369 | + |
|
| 1370 | + void storeRaceLogEventEvent(DBObject eventEntry) { |
|
| 1371 | + getRaceLogCollection().insert(eventEntry); |
|
| 1372 | + } |
|
| 1373 | + |
|
| 1374 | + @Override |
|
| 1375 | + public void removeRaceLog(RaceLogIdentifier identifier) { |
|
| 1376 | + DBObject query = new BasicDBObject(); |
|
| 1377 | + storeRaceLogIdentifier(identifier, query); |
|
| 1378 | + getRaceLogCollection().remove(query); |
|
| 1379 | + } |
|
| 1380 | + |
|
| 1381 | + @Override |
|
| 1382 | + public void removeRegattaLog(RegattaLikeIdentifier identifier) { |
|
| 1383 | + DBObject query = new BasicDBObject(); |
|
| 1384 | + addRegattaLikeIdentifier(identifier, query); |
|
| 1385 | + getRegattaLogCollection().remove(query); |
|
| 1386 | + } |
|
| 1387 | + |
|
| 1388 | + @Override |
|
| 1389 | + public void storeResultUrl(String resultProviderName, URL url) { |
|
| 1390 | + DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); |
|
| 1391 | + DBObject query = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); |
|
| 1392 | + DBObject entry = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); |
|
| 1393 | + entry.put(FieldNames.RESULT_URL.name(), url.toString()); |
|
| 1394 | + resultUrlsCollection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); |
|
| 1395 | + } |
|
| 1396 | + |
|
| 1397 | + @Override |
|
| 1398 | + public void removeResultUrl(String resultProviderName, URL url) { |
|
| 1399 | + DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); |
|
| 1400 | + DBObject query = new BasicDBObjectBuilder().add(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName) |
|
| 1401 | + .add(FieldNames.RESULT_URL.name(), url.toString()).get(); |
|
| 1402 | + resultUrlsCollection.remove(query); |
|
| 1403 | + } |
|
| 1404 | + |
|
| 1405 | + public DBCollection getRegattaLogCollection() { |
|
| 1406 | + DBCollection result = database.getCollection(CollectionNames.REGATTA_LOGS.name()); |
|
| 1407 | + DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), null); |
|
| 1408 | + index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), null); |
|
| 1409 | + result.createIndex(index); |
|
| 1410 | + return result; |
|
| 1411 | + } |
|
| 1412 | + |
|
| 1413 | + private DBObject createBasicRegattaLogEventDBObject(RegattaLogEvent event) { |
|
| 1414 | + DBObject result = new BasicDBObject(); |
|
| 1415 | + storeTimed(event, result); |
|
| 1416 | + storeTimePoint(event.getCreatedAt(), result, FieldNames.REGATTA_LOG_EVENT_CREATED_AT); |
|
| 1417 | + result.put(FieldNames.REGATTA_LOG_EVENT_ID.name(), event.getId()); |
|
| 1418 | + result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name(), event.getAuthor().getName()); |
|
| 1419 | + result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name(), event.getAuthor().getPriority()); |
|
| 1420 | + return result; |
|
| 1421 | + } |
|
| 1422 | + |
|
| 1423 | + private void addRegattaLikeIdentifier(RegattaLikeIdentifier regattaLikeId, DBObject toObject) { |
|
| 1424 | + toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), regattaLikeId.getIdentifierType()); |
|
| 1425 | + toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), regattaLikeId.getName()); |
|
| 1426 | + } |
|
| 1427 | + |
|
| 1428 | + private void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, DBObject innerObject) { |
|
| 1429 | + DBObject result = new BasicDBObject(FieldNames.REGATTA_LOG_EVENT.name(), innerObject); |
|
| 1430 | + addRegattaLikeIdentifier(regattaLikeId, result); |
|
| 1431 | + getRegattaLogCollection().insert(result); |
|
| 1432 | + } |
|
| 1433 | + |
|
| 1434 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceCompetitorMappingEvent event) { |
|
| 1435 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1436 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName()); |
|
| 1437 | + storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); |
|
| 1438 | + result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId()); |
|
| 1439 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1440 | + } |
|
| 1441 | + |
|
| 1442 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceMarkMappingEvent event) { |
|
| 1443 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1444 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceMarkMappingEvent.class.getSimpleName()); |
|
| 1445 | + storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); |
|
| 1446 | + result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo())); |
|
| 1447 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1448 | + } |
|
| 1449 | + |
|
| 1450 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRevokeEvent event) { |
|
| 1451 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1452 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRevokeEvent.class.getSimpleName()); |
|
| 1453 | + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); |
|
| 1454 | + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); |
|
| 1455 | + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); |
|
| 1456 | + result.put(FieldNames.REGATTA_LOG_REVOKED_REASON.name(), event.getReason()); |
|
| 1457 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1458 | + } |
|
| 1459 | + |
|
| 1460 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterCompetitorEvent event) { |
|
| 1461 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1462 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterCompetitorEvent.class.getSimpleName()); |
|
| 1463 | + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); |
|
| 1464 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1465 | + } |
|
| 1466 | + |
|
| 1467 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogCloseOpenEndedDeviceMappingEvent event) { |
|
| 1468 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1469 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); |
|
| 1470 | + result.put(FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId()); |
|
| 1471 | + storeTimePoint(event.getClosingTimePoint(), result, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT); |
|
| 1472 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1473 | + } |
|
| 1474 | + |
|
| 1475 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnTimeFactorEvent event) { |
|
| 1476 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1477 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); |
|
| 1478 | + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); |
|
| 1479 | + result.put(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name(), event.getTimeOnTimeFactor()); |
|
| 1480 | + } |
|
| 1481 | + |
|
| 1482 | + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDependentStartTimeEvent event) { |
|
| 1483 | + BasicDBObject result = new BasicDBObject(); |
|
| 1484 | + storeRaceLogIdentifier(raceLogIdentifier, result); |
|
| 1485 | + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDependentStartTimeEvent(event)); |
|
| 1486 | + return result; |
|
| 1487 | + } |
|
| 1488 | + |
|
| 1489 | + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) { |
|
| 1490 | + DBObject result = createBasicRegattaLogEventDBObject(event); |
|
| 1491 | + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); |
|
| 1492 | + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); |
|
| 1493 | + result.put(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name(), event.getTimeOnDistanceAllowancePerNauticalMile().asSeconds()); |
|
| 1494 | + storeRegattaLogEvent(regattaLikeId, result); |
|
| 1495 | + } |
|
| 1496 | + |
|
| 1497 | + private DBObject createImageObject(ImageDescriptor image) { |
|
| 1498 | + DBObject result = new BasicDBObject(); |
|
| 1499 | + result.put(FieldNames.IMAGE_URL.name(), image.getURL().toString()); |
|
| 1500 | + result.put(FieldNames.IMAGE_LOCALE.name(), image.getLocale() != null ? image.getLocale().toLanguageTag() : null); |
|
| 1501 | + result.put(FieldNames.IMAGE_TITLE.name(), image.getTitle()); |
|
| 1502 | + result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle()); |
|
| 1503 | + result.put(FieldNames.IMAGE_COPYRIGHT.name(), image.getCopyright()); |
|
| 1504 | + result.put(FieldNames.IMAGE_WIDTH_IN_PX.name(), image.getWidthInPx()); |
|
| 1505 | + result.put(FieldNames.IMAGE_HEIGHT_IN_PX.name(), image.getHeightInPx()); |
|
| 1506 | + storeTimePoint(image.getCreatedAtDate(), result, FieldNames.IMAGE_CREATEDATDATE); |
|
| 1507 | + BasicDBList tags = new BasicDBList(); |
|
| 1508 | + for (String tag : image.getTags()) { |
|
| 1509 | + tags.add(tag); |
|
| 1510 | + } |
|
| 1511 | + result.put(FieldNames.IMAGE_TAGS.name(), tags); |
|
| 1512 | + return result; |
|
| 1513 | + } |
|
| 1514 | + |
|
| 1515 | + private DBObject createVideoObject(VideoDescriptor video) { |
|
| 1516 | + DBObject result = new BasicDBObject(); |
|
| 1517 | + result.put(FieldNames.VIDEO_URL.name(), video.getURL().toString()); |
|
| 1518 | + result.put(FieldNames.VIDEO_LOCALE.name(), video.getLocale() != null ? video.getLocale().toLanguageTag() : null); |
|
| 1519 | + result.put(FieldNames.VIDEO_THUMBNAIL_URL.name(), video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null); |
|
| 1520 | + result.put(FieldNames.VIDEO_TITLE.name(), video.getTitle()); |
|
| 1521 | + result.put(FieldNames.VIDEO_SUBTITLE.name(), video.getSubtitle()); |
|
| 1522 | + result.put(FieldNames.VIDEO_MIMETYPE.name(), video.getMimeType() != null ? video.getMimeType().name() : null); |
|
| 1523 | + result.put(FieldNames.VIDEO_COPYRIGHT.name(), video.getCopyright()); |
|
| 1524 | + result.put(FieldNames.VIDEO_LENGTH_IN_SECONDS.name(), video.getLengthInSeconds()); |
|
| 1525 | + storeTimePoint(video.getCreatedAtDate(), result, FieldNames.VIDEO_CREATEDATDATE); |
|
| 1526 | + BasicDBList tags = new BasicDBList(); |
|
| 1527 | + for (String tag : video.getTags()) { |
|
| 1528 | + tags.add(tag); |
|
| 1529 | + } |
|
| 1530 | + result.put(FieldNames.VIDEO_TAGS.name(), tags); |
|
| 1531 | + return result; |
|
| 1532 | + } |
|
| 1533 | +} |
java/com.sap.sailing.domain.shared.android/pom.xml
| ... | ... | @@ -1,39 +1,39 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
| 4 | - <modelVersion>4.0.0</modelVersion>
|
|
| 5 | - <parent>
|
|
| 6 | - <artifactId>root</artifactId>
|
|
| 7 | - <groupId>com.sap.sailing</groupId>
|
|
| 8 | - <version>1.0.0-SNAPSHOT</version>
|
|
| 9 | - </parent>
|
|
| 10 | - <artifactId>com.sap.sailing.domain.shared.android</artifactId>
|
|
| 11 | - <packaging>eclipse-plugin</packaging>
|
|
| 12 | - <build>
|
|
| 13 | - <plugins>
|
|
| 14 | - <plugin>
|
|
| 15 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 16 | - <artifactId>tycho-compiler-plugin</artifactId>
|
|
| 17 | - <version>${tycho-version}</version>
|
|
| 18 | - <configuration>
|
|
| 19 | - <source>1.7</source>
|
|
| 20 | - <target>1.7</target>
|
|
| 21 | - </configuration>
|
|
| 22 | - </plugin>
|
|
| 23 | - <plugin>
|
|
| 24 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 25 | - <artifactId>tycho-source-plugin</artifactId>
|
|
| 26 | - <version>${tycho-version}</version>
|
|
| 27 | - <executions>
|
|
| 28 | - <execution>
|
|
| 29 | - <id>plugin-source</id>
|
|
| 30 | - <phase>generate-sources</phase>
|
|
| 31 | - <goals>
|
|
| 32 | - <goal>plugin-source</goal>
|
|
| 33 | - </goals>
|
|
| 34 | - </execution>
|
|
| 35 | - </executions>
|
|
| 36 | - </plugin>
|
|
| 37 | - </plugins>
|
|
| 38 | - </build>
|
|
| 39 | -</project>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>com.sap.sailing.domain.shared.android</artifactId> |
|
| 11 | + <packaging>eclipse-plugin</packaging> |
|
| 12 | + <build> |
|
| 13 | + <plugins> |
|
| 14 | + <plugin> |
|
| 15 | + <groupId>org.eclipse.tycho</groupId> |
|
| 16 | + <artifactId>tycho-compiler-plugin</artifactId> |
|
| 17 | + <version>${tycho-version}</version> |
|
| 18 | + <configuration> |
|
| 19 | + <source>1.7</source> |
|
| 20 | + <target>1.7</target> |
|
| 21 | + </configuration> |
|
| 22 | + </plugin> |
|
| 23 | + <plugin> |
|
| 24 | + <groupId>org.eclipse.tycho</groupId> |
|
| 25 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 26 | + <version>${tycho-version}</version> |
|
| 27 | + <executions> |
|
| 28 | + <execution> |
|
| 29 | + <id>plugin-source</id> |
|
| 30 | + <phase>generate-sources</phase> |
|
| 31 | + <goals> |
|
| 32 | + <goal>plugin-source</goal> |
|
| 33 | + </goals> |
|
| 34 | + </execution> |
|
| 35 | + </executions> |
|
| 36 | + </plugin> |
|
| 37 | + </plugins> |
|
| 38 | + </build> |
|
| 39 | +</project> |
java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java
| ... | ... | @@ -1,98 +1,98 @@ |
| 1 | -package com.sap.sailing.domain.base;
|
|
| 2 | -
|
|
| 3 | -import java.net.URL;
|
|
| 4 | -import java.util.Map;
|
|
| 5 | -
|
|
| 6 | -import com.sap.sailing.domain.common.Renamable;
|
|
| 7 | -import com.sap.sse.common.Named;
|
|
| 8 | -import com.sap.sse.common.TimePoint;
|
|
| 9 | -import com.sap.sse.common.WithID;
|
|
| 10 | -import com.sap.sse.common.media.ImageSize;
|
|
| 11 | -import com.sap.sse.common.media.WithMedia;
|
|
| 12 | -
|
|
| 13 | -/**
|
|
| 14 | - * Base interface for an Event consisting of all static information, which might be shared
|
|
| 15 | - * by the server and an Android application.
|
|
| 16 | - */
|
|
| 17 | -public interface EventBase extends Named, WithDescription, Renamable, WithID, WithMedia {
|
|
| 18 | -
|
|
| 19 | - void setDescription(String description);
|
|
| 20 | -
|
|
| 21 | - /**
|
|
| 22 | - * @return a non-<code>null</code> venue for this event
|
|
| 23 | - */
|
|
| 24 | - Venue getVenue();
|
|
| 25 | -
|
|
| 26 | - /**
|
|
| 27 | - * @return the start date of the event
|
|
| 28 | - */
|
|
| 29 | - TimePoint getStartDate();
|
|
| 30 | -
|
|
| 31 | - void setStartDate(TimePoint startDate);
|
|
| 32 | -
|
|
| 33 | - /**
|
|
| 34 | - * @return the end date of the event
|
|
| 35 | - */
|
|
| 36 | - TimePoint getEndDate();
|
|
| 37 | -
|
|
| 38 | - void setEndDate(TimePoint startDate);
|
|
| 39 | -
|
|
| 40 | - boolean isPublic();
|
|
| 41 | -
|
|
| 42 | - void setPublic(boolean isPublic);
|
|
| 43 | -
|
|
| 44 | - /**
|
|
| 45 | - * @deprecated
|
|
| 46 | - * Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to image resources that can be
|
|
| 47 | - * used to represent the event, e.g., on a web page.
|
|
| 48 | - *
|
|
| 49 | - * @return a non-<code>null</code> value which may be empty
|
|
| 50 | - */
|
|
| 51 | - Iterable<URL> getImageURLs();
|
|
| 52 | -
|
|
| 53 | - /**
|
|
| 54 | - * @deprecated
|
|
| 55 | - * An event may have zero or more sponsors, each of which usually want to see their logo on the web page.
|
|
| 56 | - *
|
|
| 57 | - * @return the sponsors' logos; always non-<code>null</code> but possibly empty
|
|
| 58 | - */
|
|
| 59 | - Iterable<URL> getSponsorImageURLs();
|
|
| 60 | -
|
|
| 61 | - /**
|
|
| 62 | - * @deprecated
|
|
| 63 | - * An optional logo image; may return <code>null</code>.
|
|
| 64 | - */
|
|
| 65 | - URL getLogoImageURL();
|
|
| 66 | -
|
|
| 67 | - /**
|
|
| 68 | - * @deprecated
|
|
| 69 | - * Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to video resources that can be
|
|
| 70 | - * used to represent the event, e.g., on a web page.
|
|
| 71 | - *
|
|
| 72 | - * @return a non-<code>null</code> value which may be empty
|
|
| 73 | - */
|
|
| 74 | - Iterable<URL> getVideoURLs();
|
|
| 75 | -
|
|
| 76 | - /**
|
|
| 77 | - * @return the URL of the event's official web site, or <code>null</code> if such a site does not exist or its URL
|
|
| 78 | - * is not known
|
|
| 79 | - */
|
|
| 80 | - URL getOfficialWebsiteURL();
|
|
| 81 | -
|
|
| 82 | - void setOfficialWebsiteURL(URL officialWebsiteURL);
|
|
| 83 | -
|
|
| 84 | - /**
|
|
| 85 | - * @return the URL of an external web site containing sailor related information like protests, official results, etc.
|
|
| 86 | - * or <code>null</code> if such a site does not exist or its URL is not known.
|
|
| 87 | - */
|
|
| 88 | - URL getSailorsInfoWebsiteURL();
|
|
| 89 | -
|
|
| 90 | - void setSailorsInfoWebsiteURL(URL sailorsInfoWebsiteURL);
|
|
| 91 | -
|
|
| 92 | - Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups();
|
|
| 93 | -
|
|
| 94 | - /**
|
|
| 95 | - * Sets and converts all event images and videos from the old URL based format to the new richer format
|
|
| 96 | - * */
|
|
| 97 | - boolean setMediaURLs(Iterable<URL> imageURLs, Iterable<URL> sponsorImageURLs, Iterable<URL> videoURLs, URL logoImageURL, Map<URL, ImageSize> imageSizes);
|
|
| 98 | -}
|
|
| 1 | +package com.sap.sailing.domain.base; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | +import java.util.Map; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.domain.common.Renamable; |
|
| 7 | +import com.sap.sse.common.Named; |
|
| 8 | +import com.sap.sse.common.TimePoint; |
|
| 9 | +import com.sap.sse.common.WithID; |
|
| 10 | +import com.sap.sse.common.media.ImageSize; |
|
| 11 | +import com.sap.sse.shared.media.WithMedia; |
|
| 12 | + |
|
| 13 | +/** |
|
| 14 | + * Base interface for an Event consisting of all static information, which might be shared |
|
| 15 | + * by the server and an Android application. |
|
| 16 | + */ |
|
| 17 | +public interface EventBase extends Named, WithDescription, Renamable, WithID, WithMedia { |
|
| 18 | + |
|
| 19 | + void setDescription(String description); |
|
| 20 | + |
|
| 21 | + /** |
|
| 22 | + * @return a non-<code>null</code> venue for this event |
|
| 23 | + */ |
|
| 24 | + Venue getVenue(); |
|
| 25 | + |
|
| 26 | + /** |
|
| 27 | + * @return the start date of the event |
|
| 28 | + */ |
|
| 29 | + TimePoint getStartDate(); |
|
| 30 | + |
|
| 31 | + void setStartDate(TimePoint startDate); |
|
| 32 | + |
|
| 33 | + /** |
|
| 34 | + * @return the end date of the event |
|
| 35 | + */ |
|
| 36 | + TimePoint getEndDate(); |
|
| 37 | + |
|
| 38 | + void setEndDate(TimePoint startDate); |
|
| 39 | + |
|
| 40 | + boolean isPublic(); |
|
| 41 | + |
|
| 42 | + void setPublic(boolean isPublic); |
|
| 43 | + |
|
| 44 | + /** |
|
| 45 | + * @deprecated |
|
| 46 | + * Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to image resources that can be |
|
| 47 | + * used to represent the event, e.g., on a web page. |
|
| 48 | + * |
|
| 49 | + * @return a non-<code>null</code> value which may be empty |
|
| 50 | + */ |
|
| 51 | + Iterable<URL> getImageURLs(); |
|
| 52 | + |
|
| 53 | + /** |
|
| 54 | + * @deprecated |
|
| 55 | + * An event may have zero or more sponsors, each of which usually want to see their logo on the web page. |
|
| 56 | + * |
|
| 57 | + * @return the sponsors' logos; always non-<code>null</code> but possibly empty |
|
| 58 | + */ |
|
| 59 | + Iterable<URL> getSponsorImageURLs(); |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * @deprecated |
|
| 63 | + * An optional logo image; may return <code>null</code>. |
|
| 64 | + */ |
|
| 65 | + URL getLogoImageURL(); |
|
| 66 | + |
|
| 67 | + /** |
|
| 68 | + * @deprecated |
|
| 69 | + * Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to video resources that can be |
|
| 70 | + * used to represent the event, e.g., on a web page. |
|
| 71 | + * |
|
| 72 | + * @return a non-<code>null</code> value which may be empty |
|
| 73 | + */ |
|
| 74 | + Iterable<URL> getVideoURLs(); |
|
| 75 | + |
|
| 76 | + /** |
|
| 77 | + * @return the URL of the event's official web site, or <code>null</code> if such a site does not exist or its URL |
|
| 78 | + * is not known |
|
| 79 | + */ |
|
| 80 | + URL getOfficialWebsiteURL(); |
|
| 81 | + |
|
| 82 | + void setOfficialWebsiteURL(URL officialWebsiteURL); |
|
| 83 | + |
|
| 84 | + /** |
|
| 85 | + * @return the URL of an external web site containing sailor related information like protests, official results, etc. |
|
| 86 | + * or <code>null</code> if such a site does not exist or its URL is not known. |
|
| 87 | + */ |
|
| 88 | + URL getSailorsInfoWebsiteURL(); |
|
| 89 | + |
|
| 90 | + void setSailorsInfoWebsiteURL(URL sailorsInfoWebsiteURL); |
|
| 91 | + |
|
| 92 | + Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups(); |
|
| 93 | + |
|
| 94 | + /** |
|
| 95 | + * Sets and converts all event images and videos from the old URL based format to the new richer format |
|
| 96 | + * */ |
|
| 97 | + boolean setMediaURLs(Iterable<URL> imageURLs, Iterable<URL> sponsorImageURLs, Iterable<URL> videoURLs, URL logoImageURL, Map<URL, ImageSize> imageSizes); |
|
| 98 | +} |
java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java
| ... | ... | @@ -15,15 +15,15 @@ import com.sap.sailing.domain.base.Venue; |
| 15 | 15 | import com.sap.sse.common.TimePoint; |
| 16 | 16 | import com.sap.sse.common.Util; |
| 17 | 17 | import com.sap.sse.common.Util.Pair; |
| 18 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 19 | -import com.sap.sse.common.media.ImageDescriptorImpl; |
|
| 20 | 18 | import com.sap.sse.common.media.ImageSize; |
| 21 | -import com.sap.sse.common.media.MediaDescriptor; |
|
| 22 | 19 | import com.sap.sse.common.media.MediaTagConstants; |
| 23 | -import com.sap.sse.common.media.MediaUtils; |
|
| 24 | 20 | import com.sap.sse.common.media.MimeType; |
| 25 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 26 | -import com.sap.sse.common.media.VideoDescriptorImpl; |
|
| 21 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 22 | +import com.sap.sse.shared.media.MediaDescriptor; |
|
| 23 | +import com.sap.sse.shared.media.MediaUtils; |
|
| 24 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 25 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 26 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 27 | 27 | |
| 28 | 28 | public abstract class EventBaseImpl implements EventBase { |
| 29 | 29 | private static final long serialVersionUID = -5749964088848611074L; |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java
| ... | ... | @@ -28,6 +28,7 @@ import com.sap.sailing.domain.common.PassingInstruction; |
| 28 | 28 | import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
| 29 | 29 | import com.sap.sailing.domain.common.impl.DegreePosition;
|
| 30 | 30 | import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
| 31 | +import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
|
| 31 | 32 | import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
| 32 | 33 | import com.sap.sailing.domain.markpassingcalculation.impl.WaypointPositionAndDistanceCache;
|
| 33 | 34 | import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
|
| ... | ... | @@ -127,6 +128,33 @@ public class WaypointPositionAndDistanceCacheTest { |
| 127 | 128 | assertEquals(5, recalculations); // one for each waypoint, one for the distance; second request recalculates except start/finish position
|
| 128 | 129 | }
|
| 129 | 130 | |
| 131 | + /**
|
|
| 132 | + * A white-box text for bug 3364: when multiple cache entries exist in the map, invalidating a cache entry can cause a
|
|
| 133 | + * ConcurrentModificationException.
|
|
| 134 | + */
|
|
| 135 | + @Test
|
|
| 136 | + public void testInvalidateByNewMarkPositionWithMultipleMarkPositionsInCache() {
|
|
| 137 | + assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
|
| 138 | + trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
|
| 139 | + new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution.divide(10)))),
|
|
| 140 | + now.plus(timeRangeResolution.divide(10)))); // does not affect the cache interval
|
|
| 141 | + trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
|
| 142 | + new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution.times(2)))),
|
|
| 143 | + now.plus(timeRangeResolution.times(2))));
|
|
| 144 | + trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
|
| 145 | + new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution.times(3)))),
|
|
| 146 | + now.plus(timeRangeResolution.times(3))));
|
|
| 147 | + assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
|
| 148 | + assertEquals(60+new NauticalMileDistance(20).scale(timeRangeResolution.divide(Duration.ONE_HOUR)).getNauticalMiles(), cache.getApproximateDistance(start, windwardWaypoint, now.plus(timeRangeResolution)).getNauticalMiles(), 0.01);
|
|
| 149 | + assertEquals(60+new NauticalMileDistance(20).scale(timeRangeResolution.times(2).divide(Duration.ONE_HOUR)).getNauticalMiles(), cache.getApproximateDistance(start, windwardWaypoint, now.plus(timeRangeResolution.times(2))).getNauticalMiles(), 0.01);
|
|
| 150 | + trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
|
| 151 | + new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution.minus(1)))),
|
|
| 152 | + now.plus(timeRangeResolution.minus(1)))); // cause cache invalidation with several entries in the map
|
|
| 153 | + recalculations = 0;
|
|
| 154 | + assertEquals(60+new NauticalMileDistance(20).scale(timeRangeResolution.divide(Duration.ONE_HOUR)).getNauticalMiles(), cache.getApproximateDistance(start, windwardWaypoint, now.plus(timeRangeResolution)).getNauticalMiles(), 0.01);
|
|
| 155 | + assertEquals(2, recalculations); // distance calculation also requires position calculation, therefore 2, not 1
|
|
| 156 | + }
|
|
| 157 | +
|
|
| 130 | 158 | @Test
|
| 131 | 159 | public void testNewMarkPositionAffectingEntryOppositeOrder() {
|
| 132 | 160 | assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
| ... | ... | @@ -140,10 +168,13 @@ public class WaypointPositionAndDistanceCacheTest { |
| 140 | 168 | |
| 141 | 169 | @Test
|
| 142 | 170 | public void testNewMarkPositionNotAffectingEntry() {
|
| 143 | - assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
|
| 144 | 171 | trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
| 145 | 172 | new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution))),
|
| 146 | - now.plus(timeRangeResolution))); // does not affect the cache interval
|
|
| 173 | + now.plus(timeRangeResolution)));
|
|
| 174 | + assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
|
| 175 | + trackedRace.getOrCreateTrack(windward).add(new GPSFixImpl(new DegreePosition(1, 0).translateGreatCircle(
|
|
| 176 | + new DegreeBearingImpl(0), new KnotSpeedImpl(20).travel(now, now.plus(timeRangeResolution.times(2)))),
|
|
| 177 | + now.plus(timeRangeResolution.times(2)))); // only affects back to now.plus(timeRangeResolution) but not all the way back to now
|
|
| 147 | 178 | assertEquals(60, cache.getApproximateDistance(start, windwardWaypoint, now).getNauticalMiles(), 0.01);
|
| 148 | 179 | assertEquals(60, cache.getApproximateDistance(windwardWaypoint, start, now).getNauticalMiles(), 0.01);
|
| 149 | 180 | assertEquals(3, recalculations); // one for the position of each waypoint, one for the distance; second / third request from cache
|
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/impl/WaypointPositionAndDistanceCache.java
| ... | ... | @@ -2,6 +2,7 @@ package com.sap.sailing.domain.markpassingcalculation.impl; |
| 2 | 2 | |
| 3 | 3 | import java.util.ArrayList;
|
| 4 | 4 | import java.util.Collections;
|
| 5 | +import java.util.Iterator;
|
|
| 5 | 6 | import java.util.List;
|
| 6 | 7 | import java.util.Map;
|
| 7 | 8 | import java.util.Map.Entry;
|
| ... | ... | @@ -194,13 +195,14 @@ public class WaypointPositionAndDistanceCache { |
| 194 | 195 | if (map != null) {
|
| 195 | 196 | final SortedMap<TimePoint, Position> tailMap = map.tailMap(roundToResolution(affectedTimeRange.from()));
|
| 196 | 197 | synchronized (map) {
|
| 197 | - for (Entry<TimePoint, Position> e : tailMap.entrySet()) {
|
|
| 198 | + for (Iterator<Entry<TimePoint, Position>> i=tailMap.entrySet().iterator(); i.hasNext(); ) {
|
|
| 199 | + final Entry<TimePoint, Position> e = i.next();
|
|
| 198 | 200 | final TimePoint timePoint = e.getKey();
|
| 199 | 201 | if (timePoint.after(affectedTimeRange.to())) {
|
| 200 | 202 | break;
|
| 201 | 203 | }
|
| 202 | 204 | assert timePoint.equals(roundToResolution(timePoint));
|
| 203 | - map.remove(timePoint);
|
|
| 205 | + i.remove();
|
|
| 204 | 206 | synchronized (waypoints) {
|
| 205 | 207 | for (Waypoint otherWaypoint : waypoints) {
|
| 206 | 208 | ControlPoint otherControlPoint = otherWaypoint.getControlPoint();
|
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java
| ... | ... | @@ -388,7 +388,7 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl |
| 388 | 388 | } |
| 389 | 389 | lockForRead(); |
| 390 | 390 | try { |
| 391 | - Util.Pair<FixType, FixType> fixesForPositionEstimation = getFixesForPositionEstimation(fix.getTimePoint(), /* inclusive */ true); |
|
| 391 | + Util.Pair<FixType, FixType> fixesForPositionEstimation = getFixesForPositionEstimation(fix.getTimePoint(), /* inclusive */ false); |
|
| 392 | 392 | final TimePoint start; |
| 393 | 393 | if (fix.equals(fixesForPositionEstimation.getA())) { |
| 394 | 394 | if (getLastFixBefore(fix.getTimePoint()) == null) { |
java/com.sap.sailing.feature.p2build/raceanalysis.product
| ... | ... | @@ -50,6 +50,7 @@ |
| 50 | 50 | <plugin id="com.sap.sailing.monitoring" autoStart="true" startLevel="6" />
|
| 51 | 51 | <plugin id="com.sap.sailing.news" autoStart="true" startLevel="3" />
|
| 52 | 52 | <plugin id="com.sap.sailing.polars" autoStart="true" startLevel="4" />
|
| 53 | + <plugin id="com.sap.sailing.polars.datamining" autoStart="true" startLevel="4" />
|
|
| 53 | 54 | <plugin id="com.sap.sailing.resultimport" autoStart="true" startLevel="3" />
|
| 54 | 55 | <plugin id="com.sap.sailing.sailwave.resultimport" autoStart="true" startLevel="3" />
|
| 55 | 56 | <plugin id="com.sap.sailing.server" autoStart="true" startLevel="4" />
|
java/com.sap.sailing.gwt.ui/Calendar.html
| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | +<body>
|
|
| 2 | +Dummy file used to count calendar-based access to Solutions place
|
|
| 3 | +</body> |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF
| ... | ... | @@ -49,9 +49,10 @@ Require-Bundle: com.sap.sailing.domain, |
| 49 | 49 | org.apache.shiro.core;bundle-version="1.2.2", |
| 50 | 50 | com.sap.sse.gwt.theme, |
| 51 | 51 | com.sap.sailing.news, |
| 52 | - com.sap.sailing.polars.datamining.shared;bundle-version="1.0.0", |
|
| 52 | + com.sap.sailing.polars.datamining.shared, |
|
| 53 | 53 | com.sap.sailing.polars.datamining, |
| 54 | - com.sap.sse.datamining.annotations;bundle-version="1.0.0" |
|
| 54 | + com.sap.sse.datamining.annotations, |
|
| 55 | + com.sap.sse.shared.android |
|
| 55 | 56 | Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator |
| 56 | 57 | Bundle-ActivationPolicy: lazy |
| 57 | 58 | Import-Package: javax.servlet;version="3.1.0", |
java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling (Run-Mode only).launch
| ... | ... | @@ -1,60 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | -<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
|
| 3 | -<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
|
| 4 | -<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
|
| 5 | -<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
|
| 6 | -<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
|
| 7 | -<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
|
| 8 | -<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
|
|
| 9 | -</listAttribute>
|
|
| 10 | -<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
|
| 11 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
|
| 12 | -<listEntry value="/com.sap.sailing.gwt.ui"/>
|
|
| 13 | -</listAttribute>
|
|
| 14 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
|
| 15 | -<listEntry value="4"/>
|
|
| 16 | -</listAttribute>
|
|
| 17 | -<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
| 18 | -<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
|
| 19 | -<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
|
| 20 | -</listAttribute>
|
|
| 21 | -<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
|
| 22 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
|
| 23 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/resources" path="3" type="2"/> "/>
|
|
| 24 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
|
| 25 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
|
| 26 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
|
| 27 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
|
| 28 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
|
| 29 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server/src" path="3" type="2"/> "/>
|
|
| 30 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter/src" path="3" type="2"/> "/>
|
|
| 31 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.expeditionconnector/src" path="3" type="2"/> "/>
|
|
| 32 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/src" path="3" type="2"/> "/>
|
|
| 33 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/resources" path="3" type="2"/> "/>
|
|
| 34 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.udpconnector/src" path="3" type="2"/> "/>
|
|
| 35 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.mongodb/src" path="3" type="2"/> "/>
|
|
| 36 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter/src" path="3" type="2"/> "/>
|
|
| 37 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.persistence/src" path="3" type="2"/> "/>
|
|
| 38 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter.persistence/src" path="3" type="2"/> "/>
|
|
| 39 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter.persistence/src" path="3" type="2"/> "/>
|
|
| 40 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
|
| 41 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.geocoding/src" path="3" type="2"/> "/>
|
|
| 42 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.datamining.shared/src" path="3" type="2"/> "/>
|
|
| 43 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.common/src" path="3" type="2"/> "/>
|
|
| 44 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.datamining.shared/src" path="3" type="2"/> "/>
|
|
| 45 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt/src" path="3" type="2"/> "/>
|
|
| 46 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
|
| 47 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/>
|
|
| 48 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/>
|
|
| 49 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.operationaltransformation/src" path="3" type="2"/> "/>
|
|
| 50 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.replication/src" path="3" type="2"/> "/>
|
|
| 51 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.common/src" path="3" type="2"/> "/>
|
|
| 52 | -</listAttribute>
|
|
| 53 | -<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
|
| 54 | -<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
|
| 55 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
|
| 56 | -<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
|
| 57 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.ui.Search -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart.html com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.VideoPopup"/>
|
|
| 58 | -<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
|
| 59 | -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m -Xdebug -Xrunjdwp:transport=dt_socket,address=7999,server=y"/>
|
|
| 60 | -</launchConfiguration>
|
java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | <listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
| 18 | 18 | <listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
| 19 | 19 | <listEntry value="com.sap.sailing.gwt.home.Home"/>
|
| 20 | -<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
|
| 20 | +<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
|
| 21 | 21 | </listAttribute>
|
| 22 | 22 | <booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
| 23 | 23 | <stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
| ... | ... | @@ -73,7 +73,7 @@ |
| 73 | 73 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
| 74 | 74 | <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
| 75 | 75 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
| 76 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
|
|
| 76 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
|
|
| 77 | 77 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
| 78 | 78 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
|
| 79 | 79 | </launchConfiguration>
|
java/com.sap.sailing.gwt.ui/SailingGWT.launch
| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | <listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
| 17 | 17 | <listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
| 18 | 18 | <listEntry value="com.sap.sailing.gwt.home.Home"/>
|
| 19 | -<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
|
| 19 | +<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
|
| 20 | 20 | </listAttribute>
|
| 21 | 21 | <stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
| 22 | 22 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
| ... | ... | @@ -70,7 +70,7 @@ |
| 70 | 70 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
| 71 | 71 | <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
| 72 | 72 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
| 73 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
|
|
| 73 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
|
|
| 74 | 74 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
| 75 | 75 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/>
|
| 76 | 76 | </launchConfiguration>
|
java/com.sap.sailing.gwt.ui/Simulator.css
| ... | ... | @@ -396,3 +396,716 @@ input.magnifier { |
| 396 | 396 | -moz-border-radius: 5px; border: 1px solid #177980;} |
| 397 | 397 | -o-border-radius: 5px; border: 1px solid #177980;} |
| 398 | 398 | -ms-border-radius: 5px; border: 1px solid #177980;} |
| 399 | + |
|
| 400 | + |
|
| 401 | + |
|
| 402 | + |
|
| 403 | + |
|
| 404 | + |
|
| 405 | + |
|
| 406 | + |
|
| 407 | + |
|
| 408 | + |
|
| 409 | + |
|
| 410 | + |
|
| 411 | + |
|
| 412 | + |
|
| 413 | + |
|
| 414 | + |
|
| 415 | + |
|
| 416 | + |
|
| 417 | + /** Add css rules here for your application. */ |
|
| 418 | +/* |
|
| 419 | + body #calendar:after |
|
| 420 | + content: " "; |
|
| 421 | + display: block; |
|
| 422 | + height: 0; |
|
| 423 | + clear: both; |
|
| 424 | + visibility: hidden; |
|
| 425 | +*/ |
|
| 426 | + |
|
| 427 | + |
|
| 428 | + * { |
|
| 429 | + font-family: 'Open Sans', sans-serif; |
|
| 430 | + font-size: 12px; |
|
| 431 | +} |
|
| 432 | + |
|
| 433 | + |
|
| 434 | +iframe { |
|
| 435 | + display: block; |
|
| 436 | + width: 100%; |
|
| 437 | + height: 100%; |
|
| 438 | + border: none; |
|
| 439 | + overflow-y: auto; |
|
| 440 | + overflow-x: hidden; |
|
| 441 | +} |
|
| 442 | + |
|
| 443 | +.clear { |
|
| 444 | + clear: both; |
|
| 445 | + font-size: 1px; |
|
| 446 | + height: 0px; |
|
| 447 | + line-height: 0px; |
|
| 448 | + margin: -1px 0 0; |
|
| 449 | + width: 100%; |
|
| 450 | +} |
|
| 451 | + |
|
| 452 | +.cover { |
|
| 453 | + left: -1000px; |
|
| 454 | + overflow: hidden; |
|
| 455 | + position: absolute; |
|
| 456 | + top: -1000px; |
|
| 457 | +} |
|
| 458 | + |
|
| 459 | +body { |
|
| 460 | + background: white; |
|
| 461 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 462 | + line-height: 1; |
|
| 463 | + font-size: 14px; |
|
| 464 | + font-weight: 400; |
|
| 465 | + margin: 0; |
|
| 466 | + |
|
| 467 | +} |
|
| 468 | + |
|
| 469 | +table td, select, button { |
|
| 470 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 471 | + line-height: 1; |
|
| 472 | + font-size: 14px; |
|
| 473 | +} |
|
| 474 | + |
|
| 475 | +.contentOuterPanel { |
|
| 476 | + background: #dddcdc; |
|
| 477 | + margin: 0 12px 0 12px; |
|
| 478 | + padding: 12px; |
|
| 479 | +} |
|
| 480 | + |
|
| 481 | + |
|
| 482 | + |
|
| 483 | +/** Example rules used by the template application (remove for your app) */ |
|
| 484 | +h1 { |
|
| 485 | + font-size: 2em; |
|
| 486 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 487 | + font-weight: 700; |
|
| 488 | + color: #777777; |
|
| 489 | + margin: 40px 0px 70px; |
|
| 490 | + text-align: center; |
|
| 491 | +} |
|
| 492 | + |
|
| 493 | +table { |
|
| 494 | + border-collapse: separate; |
|
| 495 | +} |
|
| 496 | + |
|
| 497 | +.CombinedWindPanelParentDiv { |
|
| 498 | + padding-top: 34px; |
|
| 499 | + padding-left: 10px; |
|
| 500 | +} |
|
| 501 | + |
|
| 502 | +.TrueNorthIndicatorPanelParentDiv { |
|
| 503 | + padding-top: 10px; |
|
| 504 | + padding-left: 10px; |
|
| 505 | +} |
|
| 506 | + |
|
| 507 | +.MapSimulationLegendParentDiv { |
|
| 508 | + padding-bottom: 10px; |
|
| 509 | + padding-right: 10px; |
|
| 510 | + pointer-events: none; |
|
| 511 | +} |
|
| 512 | + |
|
| 513 | +.MapSimulationLegend { |
|
| 514 | + pointer-events: all; |
|
| 515 | +} |
|
| 516 | + |
|
| 517 | +.RaceMap-HeaderPanel { |
|
| 518 | + height: 60px; |
|
| 519 | + width: 100%; |
|
| 520 | + background-color: #333; |
|
| 521 | + opacity: .5; |
|
| 522 | +} |
|
| 523 | + |
|
| 524 | +.leaderboardLabel { |
|
| 525 | + border-bottom: 2px solid #007dc0; |
|
| 526 | + padding: 0 0 6px 0; |
|
| 527 | + font-weight: 700; |
|
| 528 | +} |
|
| 529 | + |
|
| 530 | +.refreshAndSettings { |
|
| 531 | + background: #f2f2f2; |
|
| 532 | + border-bottom: 2px solid #fff; |
|
| 533 | + border-top: 2px solid #fff; |
|
| 534 | + height: 30px; |
|
| 535 | +} |
|
| 536 | + |
|
| 537 | +.refreshAndSettings table td { |
|
| 538 | + padding: 0 10px 0 0; |
|
| 539 | +} |
|
| 540 | + |
|
| 541 | +.refreshAndSettings table table td { |
|
| 542 | + padding: 0 0 0 0; |
|
| 543 | +} |
|
| 544 | + |
|
| 545 | +.race-name { |
|
| 546 | + line-height: 1.0; |
|
| 547 | +} |
|
| 548 | + |
|
| 549 | +.openColumn { |
|
| 550 | + position: relative; |
|
| 551 | + vertical-align: middle; |
|
| 552 | +} |
|
| 553 | + |
|
| 554 | +img.openColumn { |
|
| 555 | + display: block; |
|
| 556 | + margin: 3px auto 3px auto !important; |
|
| 557 | +} |
|
| 558 | + |
|
| 559 | +.breadcrumbPanel { |
|
| 560 | + height: 30px; |
|
| 561 | + margin: 0 12px 13px 12px; |
|
| 562 | +} |
|
| 563 | + |
|
| 564 | +.mainPanel { |
|
| 565 | + width: 100%; |
|
| 566 | +} |
|
| 567 | + |
|
| 568 | +.raceBoardNavigation { |
|
| 569 | + float: left; |
|
| 570 | + margin: 9px 0 0 12px; |
|
| 571 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 572 | + font-weight: 300; |
|
| 573 | +} |
|
| 574 | + |
|
| 575 | +.raceBoardControls { |
|
| 576 | + float: right; |
|
| 577 | + margin: 9px 0 0 12px; |
|
| 578 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 579 | + font-weight: 300; |
|
| 580 | +} |
|
| 581 | + |
|
| 582 | +.raceBoardNavigation-navigationitem { |
|
| 583 | + color: #dddcdc; |
|
| 584 | + text-transform: uppercase; |
|
| 585 | + font-weight: 500; |
|
| 586 | + margin: 0 12px 0 0; |
|
| 587 | + padding: 0 0 5px 0; |
|
| 588 | +} |
|
| 589 | + |
|
| 590 | +.raceBoardNavigation-navigationitem:hover { |
|
| 591 | + border-bottom: 4px solid #f0ab00; |
|
| 592 | + color: #dddcdc; |
|
| 593 | + text-decoration: none; |
|
| 594 | +} |
|
| 595 | + |
|
| 596 | +.raceBoardNavigation-navigationitem:active { |
|
| 597 | + border-bottom: 4px solid #f0ab00; |
|
| 598 | + color: #dddcdc; |
|
| 599 | + text-decoration: none; |
|
| 600 | +} |
|
| 601 | + |
|
| 602 | +.competitorInfo-Canvas { |
|
| 603 | + pointer-events: none; |
|
| 604 | +} |
|
| 605 | + |
|
| 606 | +.gwt-DialogBox { |
|
| 607 | + z-index: 20; |
|
| 608 | +} |
|
| 609 | + |
|
| 610 | +.abstractChartPanel-importantMessageOfChart { |
|
| 611 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 612 | + font-weight: 600; |
|
| 613 | + font-size: 20px; |
|
| 614 | + height: 70px; |
|
| 615 | + margin: 0 auto; |
|
| 616 | + padding: 49px 0 0 80px; |
|
| 617 | + width: 300px; |
|
| 618 | + color: #7c7c7c; |
|
| 619 | + background: url(images/important-message.png) left center no-repeat; |
|
| 620 | +} |
|
| 621 | + |
|
| 622 | +.breadcrumbPanel-NextArrow { |
|
| 623 | + display: none; |
|
| 624 | +} |
|
| 625 | + |
|
| 626 | +.errorLabel { |
|
| 627 | + color: #FF0000; |
|
| 628 | +} |
|
| 629 | + |
|
| 630 | +.raceBoardNavigation-settingsButtonPanel { |
|
| 631 | + float: right; |
|
| 632 | + margin: 9px 12px 0 0; |
|
| 633 | +} |
|
| 634 | + |
|
| 635 | +.raceBoardNavigation-settingsButton { |
|
| 636 | + background: url(images/settings_white.png), |
|
| 637 | + url(images/btn-cta-orangeleft.png); |
|
| 638 | + background-position: center, center 0; |
|
| 639 | + background-repeat: no-repeat, repeat-x; |
|
| 640 | + width: 27px; |
|
| 641 | + height: 23px; |
|
| 642 | + margin: 0 12px 0 1px; |
|
| 643 | + -webkit-border-radius: 0px 3px 3px 0px; |
|
| 644 | + -moz-border-radius: 0px 3px 3px 0px; |
|
| 645 | + -o-border-radius: 0px 3px 3px 0px; |
|
| 646 | + -ms-border-radius: 0px 3px 3px 0px; |
|
| 647 | + border-radius: 0px 3px 3px 0px; |
|
| 648 | +} |
|
| 649 | + |
|
| 650 | +.raceBoardNavigation-settingsButton:hover { |
|
| 651 | + background-image: url(images/settings_white.png), |
|
| 652 | + url(images/btn-cta-orangeleft.png); |
|
| 653 | + background-position: center, center -30px; |
|
| 654 | + background-repeat: no-repeat, repeat-x; |
|
| 655 | + cursor: pointer; |
|
| 656 | +} |
|
| 657 | + |
|
| 658 | +.raceBoardNavigation-filterButton:hover { |
|
| 659 | + background-image: url(images/filter_white.png), |
|
| 660 | + url(images/btn-cta-orangeleft.png); |
|
| 661 | + background-position: center, center -30px; |
|
| 662 | + background-repeat: no-repeat, repeat-x; |
|
| 663 | + cursor: pointer; |
|
| 664 | +} |
|
| 665 | + |
|
| 666 | +.raceBoardNavigation-innerElement { |
|
| 667 | + background: url("images/btn-cta-orangeleft.png") repeat-x scroll center |
|
| 668 | + 0 transparent; |
|
| 669 | + color: #FFFFFF; |
|
| 670 | + cursor: pointer; |
|
| 671 | + font-family: 'Open Sans', Verdana, Arial, sans-serif; |
|
| 672 | + font-weight: 600; |
|
| 673 | + font-size: 14px; |
|
| 674 | + margin: 0 0 0 0; |
|
| 675 | + padding: 2px 7px 2px 3px; |
|
| 676 | + height: 18px; |
|
| 677 | + display: inline-block; |
|
| 678 | + text-decoration: none; |
|
| 679 | + border-radius: 5px 0 0 5px; |
|
| 680 | + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); |
|
| 681 | + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25); |
|
| 682 | + border-bottom: 1px solid rgba(0, 0, 0, 0.25); |
|
| 683 | +} |
|
| 684 | + |
|
| 685 | +.raceBoardNavigation-innerElement:active { |
|
| 686 | + top: 1px; |
|
| 687 | + position: relative; |
|
| 688 | +} |
|
| 689 | + |
|
| 690 | +.raceBoardNavigation-innerElement:hover { |
|
| 691 | + background: url("images/btn-cta-orangeleft.png") repeat-x scroll center |
|
| 692 | + -30px transparent; |
|
| 693 | + cursor: pointer; |
|
| 694 | +} |
|
| 695 | + |
|
| 696 | +.raceBoardNavigation-innerElement label { |
|
| 697 | + cursor: pointer; |
|
| 698 | +} |
|
| 699 | + |
|
| 700 | +.raceBoardNavigation-standaloneElement { |
|
| 701 | + background: url("images/btn-cta-orangeleft.png") repeat-x scroll center |
|
| 702 | + 0 transparent; |
|
| 703 | + color: #FFFFFF; |
|
| 704 | + cursor: pointer; |
|
| 705 | + font-family: 'Open Sans', Verdana, Arial, sans-serif; |
|
| 706 | + font-weight: 600; |
|
| 707 | + font-size: 14px; |
|
| 708 | + margin: 0 0 0 0; |
|
| 709 | + padding: 2px 7px 2px 3px; |
|
| 710 | + height: 23px; |
|
| 711 | + display: inline-block; |
|
| 712 | + text-decoration: none; |
|
| 713 | + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); |
|
| 714 | + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25); |
|
| 715 | + border-bottom: 1px solid rgba(0, 0, 0, 0.25); |
|
| 716 | + border-radius: 5px 5px 5px 5px; |
|
| 717 | + |
|
| 718 | +} |
|
| 719 | + |
|
| 720 | +.raceBoardNavigation-standaloneElement:active { |
|
| 721 | + top: 1px; |
|
| 722 | + position: relative; |
|
| 723 | +} |
|
| 724 | + |
|
| 725 | +.raceBoardNavigation-standaloneElement:hover { |
|
| 726 | + background: url("images/btn-cta-orangeleft.png") repeat-x scroll center |
|
| 727 | + -30px transparent; |
|
| 728 | + cursor: pointer; |
|
| 729 | +} |
|
| 730 | + |
|
| 731 | +.raceBoardNavigation-standaloneElement label { |
|
| 732 | + cursor: pointer; |
|
| 733 | +} |
|
| 734 | + |
|
| 735 | +.timePanelButton { |
|
| 736 | + float: left; |
|
| 737 | + margin: 0 0 0 5px; |
|
| 738 | +} |
|
| 739 | + |
|
| 740 | +.timePanelButton-SlowDown { |
|
| 741 | + background-color: red !important; |
|
| 742 | +} |
|
| 743 | + |
|
| 744 | +.timePanelButton-SpeedUp { |
|
| 745 | + background-color: green !important; |
|
| 746 | +} |
|
| 747 | + |
|
| 748 | +.playPauseButton { |
|
| 749 | + padding: 0; |
|
| 750 | + float: left; |
|
| 751 | + width: 32px; |
|
| 752 | + height: 28px; |
|
| 753 | + background: url(images/viewicons/@1x/img/SAP_RV_Play_INACTIVE.png) |
|
| 754 | + center no-repeat; |
|
| 755 | + cursor: pointer; |
|
| 756 | + border: 1px solid #cecece; |
|
| 757 | + border-radius: 4px; |
|
| 758 | + outline: 0; |
|
| 759 | +} |
|
| 760 | + |
|
| 761 | +.playPauseButton:hover { |
|
| 762 | + cursor: pointer; |
|
| 763 | + background-color: #cecece; |
|
| 764 | +} |
|
| 765 | + |
|
| 766 | +.playPauseButtonPause { |
|
| 767 | + background: url(images/viewicons/@2x/img/SAP_RV_Pause_INACTIVE.png) 2px |
|
| 768 | + 0 no-repeat; |
|
| 769 | + outline: 0; |
|
| 770 | + background-size: contain; |
|
| 771 | +} |
|
| 772 | + |
|
| 773 | +.playPauseButtonPause:hover { |
|
| 774 | + cursor: pointer; |
|
| 775 | +} |
|
| 776 | + |
|
| 777 | +.backToLivePlayButton { |
|
| 778 | + width: 42px; |
|
| 779 | + height: 38px; |
|
| 780 | + font-size: 8px; |
|
| 781 | + white-space: normal; |
|
| 782 | + border-radius: 4px; |
|
| 783 | + border: none; |
|
| 784 | + |
|
| 785 | + margin-right: 23px; |
|
| 786 | + margin-top: 5px; |
|
| 787 | + margin-bottom: 5px; |
|
| 788 | + z-index: 1; |
|
| 789 | +} |
|
| 790 | + |
|
| 791 | +.backToLivePlayButton-Inactive { |
|
| 792 | + color: #6dc021; |
|
| 793 | + background-color: white; |
|
| 794 | + font-weight: bold; |
|
| 795 | +} |
|
| 796 | + |
|
| 797 | +.backToLivePlayButton-Active { |
|
| 798 | + background-color: #6dc021; |
|
| 799 | + color: white; |
|
| 800 | + font-weight: normal; |
|
| 801 | +} |
|
| 802 | + |
|
| 803 | +.backToLivePlayButton:hover { |
|
| 804 | + border: 2px solid gray; |
|
| 805 | +} |
|
| 806 | + |
|
| 807 | +.backToLivePlayButton:focus { |
|
| 808 | + outline: 0 !important; |
|
| 809 | +} |
|
| 810 | + |
|
| 811 | +.dockLayoutPanel div[style="position: absolute; overflow: hidden; left: 0px; right: 0px; bottom: 0px; height: 90px;"] |
|
| 812 | + { |
|
| 813 | + z-index: 10; |
|
| 814 | +} |
|
| 815 | + |
|
| 816 | +.browserOptimizedMessage { |
|
| 817 | + padding: 15px 0px; |
|
| 818 | +} |
|
| 819 | + |
|
| 820 | +.trackingQuality-circle { |
|
| 821 | + width: 8px; |
|
| 822 | + height: 8px; |
|
| 823 | + border-radius: 50%; |
|
| 824 | + float: left; |
|
| 825 | +} |
|
| 826 | + |
|
| 827 | +.circleYellow { |
|
| 828 | + background: #fbba00; |
|
| 829 | +} |
|
| 830 | + |
|
| 831 | +.circleGreen { |
|
| 832 | + background: #8ab54e; |
|
| 833 | +} |
|
| 834 | + |
|
| 835 | +.circleRed { |
|
| 836 | + background: #f01010; |
|
| 837 | +} |
|
| 838 | + |
|
| 839 | +.busyIndicator-Simple { |
|
| 840 | + position: absolute; |
|
| 841 | + top: 0.7em; |
|
| 842 | + right: 7.4em; |
|
| 843 | +} |
|
| 844 | + |
|
| 845 | +.busyIndicator-Circle { |
|
| 846 | + |
|
| 847 | +} |
|
| 848 | + |
|
| 849 | +.raceBoard-TitlePanel { |
|
| 850 | + position: relative; |
|
| 851 | + top: 10px; |
|
| 852 | + z-index: 10; |
|
| 853 | + color: #fff; |
|
| 854 | + margin-left: auto; |
|
| 855 | + margin-right: auto; |
|
| 856 | +} |
|
| 857 | + |
|
| 858 | +.raceBoard-TitlePanel-RaceNameLabel { |
|
| 859 | + font-size: 32px; |
|
| 860 | + font-weight: bold; |
|
| 861 | + padding: 7px; |
|
| 862 | +} |
|
| 863 | + |
|
| 864 | +.raceBoard-Logo { |
|
| 865 | + position: absolute; |
|
| 866 | + top: 6px; |
|
| 867 | + left: 10px; |
|
| 868 | + z-index: 10; |
|
| 869 | + cursor: pointer; |
|
| 870 | +} |
|
| 871 | + |
|
| 872 | +.SideBySideComponentViewer-MainPanel { |
|
| 873 | + top: 12px; |
|
| 874 | +} |
|
| 875 | + |
|
| 876 | +.TimePanel-ShowExtended-Button { |
|
| 877 | + width: 29px; |
|
| 878 | + height: 28px; |
|
| 879 | + float: left; |
|
| 880 | + cursor: pointer; |
|
| 881 | + border-radius: 4px; |
|
| 882 | + border: 1px solid #ececec; |
|
| 883 | +} |
|
| 884 | + |
|
| 885 | +.TimePanel-ShowExtended-Button-Open { |
|
| 886 | + background: white url(images/arrows_bottom_black.png) center no-repeat; |
|
| 887 | +} |
|
| 888 | + |
|
| 889 | +.TimePanel-ShowExtended-Button-Closed { |
|
| 890 | + background: white url(images/arrows_top_black.png) center no-repeat; |
|
| 891 | +} |
|
| 892 | + |
|
| 893 | +.TimePanel-ShowExtended-Button:hover { |
|
| 894 | + background-color: #cecece; |
|
| 895 | +} |
|
| 896 | + |
|
| 897 | +.TimePanel-ShowExtended-Button:focus { |
|
| 898 | + outline: 0 !important; |
|
| 899 | +} |
|
| 900 | + |
|
| 901 | +.RaceBoard-globalNavigation-Link { |
|
| 902 | + display: inline; |
|
| 903 | + margin-right: 3px; |
|
| 904 | +} |
|
| 905 | + |
|
| 906 | +.RaceBoard-globalNavigation-Link a { |
|
| 907 | + color: #fff; |
|
| 908 | + cursor: pointer; |
|
| 909 | +} |
|
| 910 | + |
|
| 911 | +.RaceBoard-globalNavigation-Link+.RaceBoard-globalNavigation-Link:before |
|
| 912 | + { |
|
| 913 | + content: ' \00bb\00a0'; |
|
| 914 | +} |
|
| 915 | + |
|
| 916 | +.TimePanel-settingsButtonStyle { |
|
| 917 | + position: absolute; |
|
| 918 | + right: 0px; |
|
| 919 | + z-index: 1; |
|
| 920 | + border: none; |
|
| 921 | +} |
|
| 922 | + |
|
| 923 | +.TimePanel-settingsButtonStyle:focus { |
|
| 924 | + outline: 0 !important; |
|
| 925 | +} |
|
| 926 | + |
|
| 927 | +.TimePanel-settingsButtonStyle:hover { |
|
| 928 | + border: 1px solid gray; |
|
| 929 | +} |
|
| 930 | + |
|
| 931 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-multiCompetitorRaceChart |
|
| 932 | + { |
|
| 933 | + background-color: white; |
|
| 934 | + background-image: |
|
| 935 | + url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_INACTIVE.png), |
|
| 936 | + url(images/arrows_top_black_small.png); |
|
| 937 | + background-repeat: no-repeat, no-repeat; |
|
| 938 | + background-position: 5% 50%, 95% 50% |
|
| 939 | +} |
|
| 940 | + |
|
| 941 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-multiCompetitorRaceChart |
|
| 942 | + { |
|
| 943 | + background-color: white; |
|
| 944 | + background-image: |
|
| 945 | + url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_GHOSTED.png), |
|
| 946 | + url(images/arrows_bottom_black_small.png); |
|
| 947 | + background-repeat: no-repeat, no-repeat; |
|
| 948 | + background-position: 5% 50%, 95% 50% |
|
| 949 | +} |
|
| 950 | + |
|
| 951 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-windChart { |
|
| 952 | + background-color: white; |
|
| 953 | + background-image: |
|
| 954 | + url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_INACTIVE.png), |
|
| 955 | + url(images/arrows_top_black_small.png); |
|
| 956 | + background-repeat: no-repeat, no-repeat; |
|
| 957 | + background-position: 5% 50%, 95% 50% |
|
| 958 | +} |
|
| 959 | + |
|
| 960 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-windChart { |
|
| 961 | + background-color: white; |
|
| 962 | + background-image: |
|
| 963 | + url(images/viewicons/@1x/img/SAP_RV_CompetitorCharts_GHOSTED.png), |
|
| 964 | + url(images/arrows_bottom_black_small.png); |
|
| 965 | + background-repeat: no-repeat, no-repeat; |
|
| 966 | + background-position: 5% 50%, 95% 50% |
|
| 967 | +} |
|
| 968 | + |
|
| 969 | +.gwt-SplitLayoutPanel-EastToggleButton-Open-leaderboard { |
|
| 970 | + background-color: white; |
|
| 971 | + background-image: |
|
| 972 | + url(images/viewicons/@1x/img/SAP_RV_Leaderboard_GHOSTED.png), |
|
| 973 | + url(images/arrows_top_black_small.png); |
|
| 974 | + background-repeat: no-repeat, no-repeat; |
|
| 975 | + background-position: 4% 50%, 96% 50% |
|
| 976 | +} |
|
| 977 | + |
|
| 978 | +.gwt-SplitLayoutPanel-EastToggleButton-Closed-leaderboard { |
|
| 979 | + background-color: white; |
|
| 980 | + background-image: |
|
| 981 | + url(images/viewicons/@1x/img/SAP_RV_Leaderboard_INACTIVE.png), |
|
| 982 | + url(images/arrows_bottom_black_small.png); |
|
| 983 | + background-repeat: no-repeat, no-repeat; |
|
| 984 | + background-position: 4% 50%, 96% 50% |
|
| 985 | +} |
|
| 986 | + |
|
| 987 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-media, |
|
| 988 | + .gwt-SplitLayoutPanel-NorthSouthToggleButton-Open-media { |
|
| 989 | + background-color: white; |
|
| 990 | + background-image: |
|
| 991 | + url(images/viewicons/@1x/img/SAP_RV_AudioVideo_INACTIVE.png); |
|
| 992 | + background-repeat: no-repeat, no-repeat; |
|
| 993 | + background-position: 10% 50%, 90% 50% |
|
| 994 | +} |
|
| 995 | + |
|
| 996 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-mediaplaying { |
|
| 997 | + background-image: |
|
| 998 | + url(images/viewicons/@1x/img/SAP_RV_AudioVideo_GHOSTED.png); |
|
| 999 | +} |
|
| 1000 | + |
|
| 1001 | +.gwt-SplitLayoutPanel-NorthSouthToggleButton-Small-media { |
|
| 1002 | + background-position: 5% 50%, 100% 50% !important; |
|
| 1003 | + margin-left: 0px !important; |
|
| 1004 | + padding: 2px 35px !important; |
|
| 1005 | +} |
|
| 1006 | + |
|
| 1007 | +@external gwt-ToggleButton-up, gwt-ToggleButton-down, gwt-ToggleButton-up-hovering, gwt-ToggleButton-down-hovering; |
|
| 1008 | +.gwt-ToggleButton-up, .gwt-ToggleButton-up-hovering { |
|
| 1009 | + background: url(images/unlock.png) center no-repeat; |
|
| 1010 | + margin-left: 5px; |
|
| 1011 | +} |
|
| 1012 | + |
|
| 1013 | +.gwt-ToggleButton-down, .gwt-ToggleButton-down-hovering { |
|
| 1014 | + background: url(images/lock.png) center no-repeat; |
|
| 1015 | + margin-left: 5px; |
|
| 1016 | +} |
|
| 1017 | + |
|
| 1018 | +.RegattaRaceInformation-Header { |
|
| 1019 | + font-family: 'Open Sans', Arial, Verdana, sans-serif; |
|
| 1020 | + position: relative; |
|
| 1021 | + left: 140px; |
|
| 1022 | + top: 11px; |
|
| 1023 | +} |
|
| 1024 | + |
|
| 1025 | +.RegattaRaceInformation-Header .RaceName-Label { |
|
| 1026 | + display: inline; |
|
| 1027 | + color: white; |
|
| 1028 | + margin-right: 10px; |
|
| 1029 | + font-size: 36px; |
|
| 1030 | +} |
|
| 1031 | + |
|
| 1032 | +.RegattaRaceInformation-Header .RaceSeriesAndFleet-Label { |
|
| 1033 | + display: inline; |
|
| 1034 | + color: white; |
|
| 1035 | + font-size: 15px; |
|
| 1036 | +} |
|
| 1037 | + |
|
| 1038 | +.RegattaAndRaceTime-Header { |
|
| 1039 | + position: absolute; |
|
| 1040 | + right: 10px; |
|
| 1041 | + top: 13px; |
|
| 1042 | + text-align: right; |
|
| 1043 | + color: white; |
|
| 1044 | +} |
|
| 1045 | + |
|
| 1046 | +.RegattaAndRaceTime-Header .RegattaName-Anchor { |
|
| 1047 | + font-size: 15px; |
|
| 1048 | + color: white; |
|
| 1049 | + text-decoration: none; |
|
| 1050 | + padding-left: 25px; |
|
| 1051 | + background-image: url(images/home.png); |
|
| 1052 | + background-repeat: no-repeat; |
|
| 1053 | + background-size: 17px; |
|
| 1054 | + background-position: 4px 1px; |
|
| 1055 | +} |
|
| 1056 | + |
|
| 1057 | +.RegattaAndRaceTime-Header .RegattaName-Anchor:hover { |
|
| 1058 | + text-decoration: underline; |
|
| 1059 | +} |
|
| 1060 | + |
|
| 1061 | +.RegattaAndRaceTime-Header .RaceTime-Label { |
|
| 1062 | + font-size: 15px; |
|
| 1063 | + margin-top: 5px; |
|
| 1064 | +} |
|
| 1065 | + |
|
| 1066 | +.VideoPopup-Close-Button { |
|
| 1067 | + border: none; |
|
| 1068 | +} |
|
| 1069 | + |
|
| 1070 | +.Media-Select-Button { |
|
| 1071 | + font-size: 15px; |
|
| 1072 | + font-size: 1rem; |
|
| 1073 | + display: inline-block; |
|
| 1074 | + font-weight: 400; |
|
| 1075 | + color: #111; |
|
| 1076 | + border: none; |
|
| 1077 | + padding: 0.5em 0.3em 0.5em 0.8em; |
|
| 1078 | + background-color: #fff; |
|
| 1079 | + -webkit-transition: background-color 0.2s; |
|
| 1080 | + -moz-transition: background-color 0.2s; |
|
| 1081 | + -o-transition: background-color 0.2s; |
|
| 1082 | + -ms-transition: background-color 0.2s; |
|
| 1083 | + transition: background-color 0.2s; |
|
| 1084 | + width: 100%; |
|
| 1085 | + max-width: 25em; |
|
| 1086 | + text-align: left; |
|
| 1087 | + white-space: nowrap; |
|
| 1088 | + overflow: hidden; |
|
| 1089 | + text-overflow: ellipsis; |
|
| 1090 | +} |
|
| 1091 | + |
|
| 1092 | +.Media-Select-Button:hover, .Media-Select-Button:focus { |
|
| 1093 | + background-color: #f0ab00; |
|
| 1094 | +} |
|
| 1095 | + |
|
| 1096 | +.Media-Select-Button-playing { |
|
| 1097 | + color: #999; |
|
| 1098 | +} |
|
| 1099 | + |
|
| 1100 | +.Media-Select-Button-playing:hover, .Media-Select-Button-playing:focus { |
|
| 1101 | + color: #fff; |
|
| 1102 | + background-color: #ccc; |
|
| 1103 | +} |
|
| 1104 | + |
|
| 1105 | +.Media-Select-Popup .dialogMiddleCenterInner { |
|
| 1106 | + padding: 0; |
|
| 1107 | +} |
|
| 1108 | + |
|
| 1109 | +.Media-Select-Popup .Caption { |
|
| 1110 | + padding: 4px 10px; |
|
| 1111 | +} |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/Simulator.html
| ... | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | <link rel="stylesheet" type="text/css" href="/sailing-normalize-3.0.2.cache.css"> |
| 17 | 17 | <link rel="stylesheet" type="text/css" href="/sailing-fontface-1.0.cache.css"> |
| 18 | 18 | <link rel="stylesheet" type="text/css" href="Simulator.css"> |
| 19 | + |
|
| 19 | 20 | |
| 20 | 21 | <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> |
| 21 | 22 |
java/com.sap.sailing.gwt.ui/build.properties
| ... | ... | @@ -50,5 +50,6 @@ bin.includes = META-INF/,\ |
| 50 | 50 | SettingsDialog.css,\ |
| 51 | 51 | EmbeddedMapAndWindChart.css,\ |
| 52 | 52 | EmbeddedMapAndWindChart.html,\ |
| 53 | - com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart/ |
|
| 53 | + com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart/,\ |
|
| 54 | + Calendar.html |
|
| 54 | 55 | output.. = WEB-INF/classes/ |
java/com.sap.sailing.gwt.ui/pom.xml
| ... | ... | @@ -11,19 +11,6 @@ |
| 11 | 11 | <artifactId>com.sap.sailing.gwt.ui</artifactId> |
| 12 | 12 | <packaging>eclipse-plugin</packaging> |
| 13 | 13 | |
| 14 | - <repositories> |
|
| 15 | - <repository> |
|
| 16 | - <id>sonatype</id> |
|
| 17 | - <url>http://oss.sonatype.org/content/repositories/snapshots</url> |
|
| 18 | - <snapshots> |
|
| 19 | - <enabled>true</enabled> |
|
| 20 | - </snapshots> |
|
| 21 | - <releases> |
|
| 22 | - <enabled>false</enabled> |
|
| 23 | - </releases> |
|
| 24 | - </repository> |
|
| 25 | - </repositories> |
|
| 26 | - |
|
| 27 | 14 | <dependencies> |
| 28 | 15 | <!-- The following dependency needs re-declaration with the desired version |
| 29 | 16 | because gwt-maps-api declares it with no version specifier which may be resolved |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/AbstractBasePlace.java
| ... | ... | @@ -46,14 +46,11 @@ public abstract class AbstractBasePlace extends Place { |
| 46 | 46 | public AbstractBasePlace(String url) { |
| 47 | 47 | if (url != null && !url.isEmpty()) { |
| 48 | 48 | this.placeParametersAsToken = url; |
| 49 | - |
|
| 50 | 49 | List<String> list = Arrays.asList(placeParametersAsToken.split("&")); |
| 51 | - |
|
| 52 | 50 | if (list == null || list.size() < 1) { |
| 53 | 51 | logger.warning("Token empty, no-op"); |
| 54 | 52 | return; |
| 55 | 53 | } |
| 56 | - |
|
| 57 | 54 | for (String listItem : list) { |
| 58 | 55 | List<String> nvPair = Arrays.asList(listItem.split("=")); |
| 59 | 56 | if (nvPair == null || nvPair.size() != 2) { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.java
| ... | ... | @@ -17,6 +17,7 @@ public interface TextMessages extends Messages { |
| 17 | 17 | String contact(); |
| 18 | 18 | String sponsoring(); |
| 19 | 19 | String solutions(); |
| 20 | + String blog(); |
|
| 20 | 21 | String german(); |
| 21 | 22 | String english(); |
| 22 | 23 | String fullEventSchedule(); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.properties
| ... | ... | @@ -6,6 +6,7 @@ aboutUs=About us |
| 6 | 6 | contact=Contact |
| 7 | 7 | sponsoring=Sponsoring |
| 8 | 8 | solutions=Solutions |
| 9 | +blog=Blog |
|
| 9 | 10 | german=Deutsch |
| 10 | 11 | english=English |
| 11 | 12 | fullEventSchedule=Full event schedule |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties
| ... | ... | @@ -6,6 +6,7 @@ aboutUs=Über uns |
| 6 | 6 | contact=Kontakt |
| 7 | 7 | sponsoring=Sponsoring |
| 8 | 8 | solutions=Lösungen |
| 9 | +blog=Blog |
|
| 9 | 10 | german=Deutsch |
| 10 | 11 | english=English |
| 11 | 12 | fullEventSchedule=Gesamter Veranstaltungsplan |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties
| ... | ... | @@ -6,6 +6,7 @@ aboutUs=About us |
| 6 | 6 | contact=Contact |
| 7 | 7 | sponsoring=Sponsoring |
| 8 | 8 | solutions=Решения |
| 9 | +blog=Блог |
|
| 9 | 10 | german=Deutsch |
| 10 | 11 | english=English |
| 11 | 12 | fullEventSchedule=Full event schedule |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties
| ... | ... | @@ -4,6 +4,7 @@ aboutUs=关于我们 |
| 4 | 4 | contact=联络 |
| 5 | 5 | sponsoring=赞助商 |
| 6 | 6 | solutions=解决方案 |
| 7 | +blog=博客 |
|
| 7 | 8 | events=比赛 |
| 8 | 9 | german=德语 |
| 9 | 10 | english=英语 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetEventViewAction.java
| ... | ... | @@ -22,8 +22,8 @@ import com.sap.sailing.gwt.home.server.EventActionUtil; |
| 22 | 22 | import com.sap.sailing.gwt.home.server.LeaderboardContext; |
| 23 | 23 | import com.sap.sailing.gwt.home.server.EventActionUtil.LeaderboardCallback; |
| 24 | 24 | import com.sap.sailing.gwt.server.HomeServiceUtil; |
| 25 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 26 | 25 | import com.sap.sse.common.media.MediaTagConstants; |
| 26 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 27 | 27 | |
| 28 | 28 | public class GetEventViewAction implements SailingAction<EventViewDTO>, IsClientCacheable { |
| 29 | 29 | private static final Logger logger = Logger.getLogger(GetEventViewAction.class.getName()); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/eventoverview/GetEventOverviewStageAction.java
| ... | ... | @@ -20,7 +20,7 @@ import com.sap.sse.common.TimePoint; |
| 20 | 20 | import com.sap.sse.common.impl.MillisecondsDurationImpl; |
| 21 | 21 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 22 | 22 | import com.sap.sse.common.media.MediaTagConstants; |
| 23 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 23 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 24 | 24 | |
| 25 | 25 | public class GetEventOverviewStageAction implements SailingAction<ResultWithTTL<EventOverviewStageDTO>>, IsClientCacheable { |
| 26 | 26 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/news/RaceCompetitorNewsEntryDTO.java
| ... | ... | @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.communication.event.news; |
| 2 | 2 | |
| 3 | 3 | import java.util.Date; |
| 4 | 4 | |
| 5 | +import com.google.gwt.core.shared.GwtIncompatible; |
|
| 5 | 6 | import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
| 6 | 7 | import com.sap.sailing.gwt.ui.client.StringMessages; |
| 7 | 8 | |
| ... | ... | @@ -18,6 +19,7 @@ public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { |
| 18 | 19 | private RaceCompetitorNewsEntryDTO() { |
| 19 | 20 | } |
| 20 | 21 | |
| 22 | + @GwtIncompatible |
|
| 21 | 23 | public RaceCompetitorNewsEntryDTO(String leaderboardName, String leaderboardGroupName, |
| 22 | 24 | RegattaAndRaceIdentifier regattaAndRaceIdentifier, String raceTitle, String boatClass, Date timestamp, |
| 23 | 25 | String competitorName, Type type) { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/fakeseries/GetEventSeriesViewAction.java
| ... | ... | @@ -16,8 +16,8 @@ import com.sap.sailing.gwt.home.communication.SailingDispatchContext; |
| 16 | 16 | import com.sap.sailing.gwt.home.communication.event.EventMetadataDTO; |
| 17 | 17 | import com.sap.sailing.gwt.home.communication.fakeseries.EventSeriesViewDTO.EventSeriesState; |
| 18 | 18 | import com.sap.sailing.gwt.server.HomeServiceUtil; |
| 19 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 20 | 19 | import com.sap.sse.common.media.MediaTagConstants; |
| 20 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 21 | 21 | |
| 22 | 22 | public class GetEventSeriesViewAction implements SailingAction<EventSeriesViewDTO>, IsClientCacheable { |
| 23 | 23 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/GetMediaForEventAction.java
| ... | ... | @@ -11,9 +11,9 @@ import com.sap.sailing.gwt.home.communication.SailingDispatchContext; |
| 11 | 11 | import com.sap.sailing.gwt.home.communication.event.EventReferenceDTO; |
| 12 | 12 | import com.sap.sailing.gwt.server.HomeServiceUtil; |
| 13 | 13 | import com.sap.sailing.gwt.ui.shared.media.MediaConstants; |
| 14 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 15 | 14 | import com.sap.sse.common.media.MimeType; |
| 16 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 15 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 16 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 17 | 17 | |
| 18 | 18 | public class GetMediaForEventAction implements SailingAction<MediaDTO>, IsClientCacheable { |
| 19 | 19 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/start/GetStartViewAction.java
| ... | ... | @@ -22,9 +22,9 @@ import com.sap.sailing.gwt.server.RecentEventsCalculator; |
| 22 | 22 | import com.sap.sailing.gwt.ui.shared.media.MediaConstants; |
| 23 | 23 | import com.sap.sse.common.Util; |
| 24 | 24 | import com.sap.sse.common.Util.Pair; |
| 25 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 26 | 25 | import com.sap.sse.common.media.MimeType; |
| 27 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 26 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 27 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 28 | 28 | |
| 29 | 29 | public class GetStartViewAction implements SailingAction<StartViewDTO>, IsClientCacheable { |
| 30 | 30 | private static final int MAX_RECENT_EVENTS = 3; |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/header/Header.ui.xml
| 31 | 31 | index 8cd735b..6159afa |
| 32 | --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/header/Header.ui.xml |
|
| 32 | +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/header/Header.ui.xml |
|
| ... | ... | @@ -22,8 +22,10 @@ |
| 22 | 22 | styleName="{local_res.css.sitenavigation_link}" text="{i18n.home}" /> |
| 23 | 23 | <g:Anchor ui:field="eventsPageLink" |
| 24 | 24 | styleName="{local_res.css.sitenavigation_link}" text="{i18n.events}" /> |
| 25 | - <g:Anchor ui:field="solutionsPageLink" |
|
| 25 | + <g:Anchor ui:field="solutionsPageLink" |
|
| 26 | 26 | styleName="{local_res.css.sitenavigation_link}" text="{i18n_ubi.solutions}" /> |
| 27 | + <g:Anchor href="http://blog.sapsailing.com" |
|
| 28 | + styleName="{local_res.css.sitenavigation_link}" text="{i18n_ubi.blog}" /> |
|
| 27 | 29 | <!-- |
| 28 | 30 | <g:Anchor ui:field="sponsoringPageLink" |
| 29 | 31 | styleName="{local_res.css.sitenavigation_link}" text="{i18n.sponsoring}" /> |
| ... | ... | @@ -37,4 +39,4 @@ |
| 37 | 39 | </nav> |
| 38 | 40 | </div> |
| 39 | 41 | </g:HTMLPanel> |
| 40 | -</ui:UiBinder> |
|
| ... | ... | \ No newline at end of file |
| 0 | +</ui:UiBinder> |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/old/leaderboard/OldLeaderboard.ui.xml
| ... | ... | @@ -22,14 +22,16 @@ |
| 22 | 22 | </div> |
| 23 | 23 | |
| 24 | 24 | <div class="{res.mediaCss.grid}"> |
| 25 | - <div class="{res.mediaCss.small12} {res.mediaCss.columns} {local_res.css.letItScroll}"> |
|
| 26 | - <table class="{local_res.css.regattaleaderboard_table}"> |
|
| 27 | - <tr> |
|
| 28 | - <td> |
|
| 29 | - <g:HTMLPanel ui:field="oldLeaderboardPanel"></g:HTMLPanel> |
|
| 30 | - </td> |
|
| 31 | - </tr> |
|
| 32 | - </table> |
|
| 25 | + <div class="{res.mediaCss.small12} {res.mediaCss.columns}"> |
|
| 26 | + <div class="{local_res.css.letItScroll}"> |
|
| 27 | + <table class="{local_res.css.regattaleaderboard_table}"> |
|
| 28 | + <tr> |
|
| 29 | + <td> |
|
| 30 | + <g:HTMLPanel ui:field="oldLeaderboardPanel"></g:HTMLPanel> |
|
| 31 | + </td> |
|
| 32 | + </tr> |
|
| 33 | + </table> |
|
| 34 | + </div> |
|
| 33 | 35 | </div> |
| 34 | 36 | </div> |
| 35 | 37 | </g:HTMLPanel> |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/old/multileaderboard/OldMultiLeaderboard.ui.xml
| ... | ... | @@ -21,14 +21,16 @@ |
| 21 | 21 | </div> |
| 22 | 22 | |
| 23 | 23 | <div class="{res.mediaCss.grid}"> |
| 24 | - <div class="{res.mediaCss.small12} {res.mediaCss.columns} {local_res.css.letItScroll}"> |
|
| 25 | - <table class="{local_res.css.regattaleaderboard_table}"> |
|
| 26 | - <tr> |
|
| 27 | - <td> |
|
| 28 | - <g:HTMLPanel ui:field="oldMultiLeaderboardPanel"></g:HTMLPanel> |
|
| 29 | - </td> |
|
| 30 | - </tr> |
|
| 31 | - </table> |
|
| 24 | + <div class="{res.mediaCss.small12} {res.mediaCss.columns}"> |
|
| 25 | + <div class="{local_res.css.letItScroll}"> |
|
| 26 | + <table class="{local_res.css.regattaleaderboard_table}"> |
|
| 27 | + <tr> |
|
| 28 | + <td> |
|
| 29 | + <g:HTMLPanel ui:field="oldMultiLeaderboardPanel"></g:HTMLPanel> |
|
| 30 | + </td> |
|
| 31 | + </tr> |
|
| 32 | + </table> |
|
| 33 | + </div> |
|
| 32 | 34 | </div> |
| 33 | 35 | </div> |
| 34 | 36 | </g:HTMLPanel> |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/solutions/Solutions.java
| ... | ... | @@ -80,7 +80,7 @@ public class Solutions extends Composite { |
| 80 | 80 | |
| 81 | 81 | sapInSailingNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SapInSailing); |
| 82 | 82 | sailingAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingAnalytics); |
| 83 | - raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommiteeApp); |
|
| 83 | + raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommitteeApp); |
|
| 84 | 84 | postRaceAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.PostRaceAnalytics); |
| 85 | 85 | trainingDiaryNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.TrainingDiary); |
| 86 | 86 | sailingSimulatorNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingSimulator); |
| ... | ... | @@ -115,7 +115,7 @@ public class Solutions extends Composite { |
| 115 | 115 | |
| 116 | 116 | @UiHandler("raceAnchor") |
| 117 | 117 | public void scrollToRace(ClickEvent e) { |
| 118 | - scrollToView(SolutionsNavigationTabs.RaceCommiteeApp); |
|
| 118 | + scrollToView(SolutionsNavigationTabs.RaceCommitteeApp); |
|
| 119 | 119 | handleClickEventWithLocalNavigation(e, raceCommitteeAppNavigation); |
| 120 | 120 | } |
| 121 | 121 | |
| ... | ... | @@ -148,14 +148,17 @@ public class Solutions extends Composite { |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | private void scrollToView(SolutionsNavigationTabs navigationTab) { |
| 151 | - switch (navigationTab) { |
|
| 151 | + if (navigationTab == null) { |
|
| 152 | + sapInSailingDiv.scrollIntoView(); |
|
| 153 | + } else { |
|
| 154 | + switch (navigationTab) { |
|
| 152 | 155 | case SapInSailing: |
| 153 | 156 | sapInSailingDiv.scrollIntoView(); |
| 154 | 157 | break; |
| 155 | 158 | case SailingAnalytics: |
| 156 | 159 | sailingAnalyticsDiv.scrollIntoView(); |
| 157 | 160 | break; |
| 158 | - case RaceCommiteeApp: |
|
| 161 | + case RaceCommitteeApp: |
|
| 159 | 162 | raceDiv.scrollIntoView(); |
| 160 | 163 | break; |
| 161 | 164 | case PostRaceAnalytics: |
| ... | ... | @@ -167,6 +170,7 @@ public class Solutions extends Composite { |
| 167 | 170 | case SailingSimulator: |
| 168 | 171 | simulatorDiv.scrollIntoView(); |
| 169 | 172 | break; |
| 173 | + } |
|
| 170 | 174 | } |
| 171 | 175 | } |
| 172 | 176 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/header/Header.java
| ... | ... | @@ -56,7 +56,7 @@ public class Header extends Composite { |
| 56 | 56 | addNavigation(placeNavigator.getHomeNavigation(), StringMessages.INSTANCE.home()); |
| 57 | 57 | addNavigation(placeNavigator.getEventsNavigation(), StringMessages.INSTANCE.events()); |
| 58 | 58 | addNavigation(placeNavigator.getSolutionsNavigation(), TextMessages.INSTANCE.solutions()); |
| 59 | - |
|
| 59 | + addUrl("http://blog.sapsailing.com", TextMessages.INSTANCE.blog()); |
|
| 60 | 60 | dropdownHandler = new DropdownHandler(dropdownTriggerUi, dropdownContainerUi); |
| 61 | 61 | |
| 62 | 62 | Event.sinkEvents(searchUi, Event.ONCLICK); |
| ... | ... | @@ -79,7 +79,6 @@ public class Header extends Composite { |
| 79 | 79 | private void addNavigation(final PlaceNavigation<?> placeNavigation, String name) { |
| 80 | 80 | HeaderNavigationItem navigationItem = new HeaderNavigationItem(name, placeNavigation.getTargetUrl()); |
| 81 | 81 | navigationItem.addClickHandler(new ClickHandler() { |
| 82 | - |
|
| 83 | 82 | @Override |
| 84 | 83 | public void onClick(ClickEvent event) { |
| 85 | 84 | if(LinkUtil.handleLinkClick(event.getNativeEvent().<Event>cast())) { |
| ... | ... | @@ -92,6 +91,11 @@ public class Header extends Composite { |
| 92 | 91 | dropdownListUi.add(navigationItem); |
| 93 | 92 | } |
| 94 | 93 | |
| 94 | + private void addUrl(String url, String name) { |
|
| 95 | + HeaderNavigationItem navigationItem = new HeaderNavigationItem(name, url); |
|
| 96 | + dropdownListUi.add(navigationItem); |
|
| 97 | + } |
|
| 98 | + |
|
| 95 | 99 | public void setLocationTitle(String locationTitle) { |
| 96 | 100 | locationTitleUi.setInnerText(locationTitle); |
| 97 | 101 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/solutions/SolutionsPlace.java
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.gwt.home.shared.places.solutions; |
| 2 | 2 | |
| 3 | +import com.google.gwt.core.shared.GWT; |
|
| 4 | +import com.google.gwt.http.client.Request; |
|
| 5 | +import com.google.gwt.http.client.RequestBuilder; |
|
| 6 | +import com.google.gwt.http.client.RequestCallback; |
|
| 7 | +import com.google.gwt.http.client.RequestException; |
|
| 8 | +import com.google.gwt.http.client.Response; |
|
| 3 | 9 | import com.google.gwt.place.shared.PlaceTokenizer; |
| 4 | 10 | import com.sap.sailing.gwt.common.client.AbstractBasePlace; |
| 5 | 11 | import com.sap.sailing.gwt.common.client.i18n.TextMessages; |
| ... | ... | @@ -9,20 +15,61 @@ import com.sap.sailing.gwt.home.shared.app.HasMobileVersion; |
| 9 | 15 | public class SolutionsPlace extends AbstractBasePlace implements HasLocationTitle, HasMobileVersion { |
| 10 | 16 | |
| 11 | 17 | public enum SolutionsNavigationTabs { |
| 12 | - SapInSailing, SailingAnalytics, RaceCommiteeApp, PostRaceAnalytics, TrainingDiary, SailingSimulator |
|
| 18 | + SapInSailing, SailingAnalytics, RaceCommitteeApp, PostRaceAnalytics, TrainingDiary, SailingSimulator |
|
| 13 | 19 | }; |
| 14 | 20 | private final SolutionsNavigationTabs navigationTab; |
| 15 | - private final static String PARAM_NAVIGATION_TAB = "navigationTab"; |
|
| 21 | + private final static String PARAM_NAVIGATION_TAB = "navigationTab"; |
|
| 22 | + private final static String CALENDAR_ACCESS_COUNT_URL = "/gwt/Calendar.html"; |
|
| 23 | + private final boolean invokedFromCalendar; |
|
| 16 | 24 | |
| 17 | 25 | public SolutionsPlace(String url) { |
| 18 | - super(url); |
|
| 19 | - String paramNavTab = getParameter(PARAM_NAVIGATION_TAB); |
|
| 20 | - navigationTab = paramNavTab != null ? SolutionsNavigationTabs.valueOf(paramNavTab) : null; |
|
| 26 | + super(url.split("\\?")[0]); // if the fragment holds another "?" check if it's the "Calendar marker" c=1 |
|
| 27 | + final String[] splitUrl = url.split("\\?"); |
|
| 28 | + if (splitUrl.length > 1) { |
|
| 29 | + final String calendarMarker = splitUrl[1]; |
|
| 30 | + invokedFromCalendar = calendarMarker.equals("c=1"); |
|
| 31 | + } else { |
|
| 32 | + invokedFromCalendar = false; |
|
| 33 | + } |
|
| 34 | + if (invokedFromCalendar) { |
|
| 35 | + navigationTab = SolutionsNavigationTabs.SapInSailing; |
|
| 36 | + makeLoggedCountableCalendarRequest(); |
|
| 37 | + } else { |
|
| 38 | + final String paramNavTab = getParameter(PARAM_NAVIGATION_TAB); |
|
| 39 | + SolutionsNavigationTabs preliminaryNavTab; |
|
| 40 | + try { |
|
| 41 | + preliminaryNavTab = paramNavTab != null ? SolutionsNavigationTabs.valueOf(paramNavTab) : null; |
|
| 42 | + } catch (IllegalArgumentException e) { |
|
| 43 | + preliminaryNavTab = SolutionsNavigationTabs.SapInSailing; |
|
| 44 | + } |
|
| 45 | + navigationTab = preliminaryNavTab; |
|
| 46 | + } |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + private void makeLoggedCountableCalendarRequest() { |
|
| 50 | + final RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, CALENDAR_ACCESS_COUNT_URL); |
|
| 51 | + try { |
|
| 52 | + requestBuilder.sendRequest(/* requestData */ null, new RequestCallback() { |
|
| 53 | + @Override |
|
| 54 | + public void onResponseReceived(Request request, Response response) { |
|
| 55 | + // nothing to do; it's just to make calendar-based access server-countable |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + @Override |
|
| 59 | + public void onError(Request request, Throwable exception) { |
|
| 60 | + // nothing to do; it's just to make calendar-based access server-countable; it failed... |
|
| 61 | + GWT.log("Warning: couldn't access calendar link counter", exception); |
|
| 62 | + } |
|
| 63 | + }); |
|
| 64 | + } catch (RequestException e) { |
|
| 65 | + GWT.log("Warning: couldn't access calendar link counter", e); |
|
| 66 | + } |
|
| 21 | 67 | } |
| 22 | 68 | |
| 23 | 69 | public SolutionsPlace(SolutionsNavigationTabs navigationTab) { |
| 24 | 70 | super(PARAM_NAVIGATION_TAB, navigationTab.name()); |
| 25 | 71 | this.navigationTab = navigationTab; |
| 72 | + this.invokedFromCalendar = false; |
|
| 26 | 73 | } |
| 27 | 74 | |
| 28 | 75 | public SolutionsNavigationTabs getNavigationTab() { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java
| ... | ... | @@ -44,12 +44,12 @@ import com.sap.sse.common.TimePoint; |
| 44 | 44 | import com.sap.sse.common.Util; |
| 45 | 45 | import com.sap.sse.common.Util.Pair; |
| 46 | 46 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 47 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 48 | -import com.sap.sse.common.media.MediaDescriptor; |
|
| 49 | 47 | import com.sap.sse.common.media.MediaTagConstants; |
| 50 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 51 | 48 | import com.sap.sse.gwt.client.media.ImageDTO; |
| 52 | 49 | import com.sap.sse.gwt.client.media.VideoDTO; |
| 50 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 51 | +import com.sap.sse.shared.media.MediaDescriptor; |
|
| 52 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 53 | 53 | |
| 54 | 54 | public final class HomeServiceUtil { |
| 55 | 55 | public interface EventVisitor { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractCompetitorRegistrationsDialog.java
| ... | ... | @@ -36,26 +36,31 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 36 | 36 | private boolean editable; |
| 37 | 37 | private String boatClass; |
| 38 | 38 | |
| 39 | + protected String leaderboardName; |
|
| 40 | + |
|
| 39 | 41 | /** |
| 40 | 42 | * @param boatClass |
| 41 | - * The <code>boatClass</code> parameter describes the default shown boat class for new competitors. The <code>boatClass</code> parameter is <code>null</code>, |
|
| 42 | - * if you want to edit a competitor or there is no boat class for the new competitor. |
|
| 43 | + * The <code>boatClass</code> parameter describes the default shown boat class for new competitors. The |
|
| 44 | + * <code>boatClass</code> parameter is <code>null</code>, if you want to edit a competitor or there is no |
|
| 45 | + * boat class for the new competitor. |
|
| 43 | 46 | */ |
| 44 | 47 | public AbstractCompetitorRegistrationsDialog(final SailingServiceAsync sailingService, |
| 45 | 48 | final StringMessages stringMessages, final ErrorReporter errorReporter, boolean editable, |
| 46 | - DialogCallback<Set<CompetitorDTO>> callback, String boatClass) { |
|
| 47 | - super(stringMessages.registerCompetitors(), /*messsage*/ null, stringMessages.save(), stringMessages.cancel(), /*validator*/ null, callback); |
|
| 49 | + DialogCallback<Set<CompetitorDTO>> callback, String leaderboardName, String boatClass) { |
|
| 50 | + super(stringMessages.registerCompetitors(), /* messsage */null, stringMessages.save(), stringMessages.cancel(), /* validator */ |
|
| 51 | + null, callback); |
|
| 48 | 52 | this.stringMessages = stringMessages; |
| 49 | 53 | this.sailingService = sailingService; |
| 50 | - this.errorReporter = errorReporter; |
|
| 54 | + this.errorReporter = errorReporter; |
|
| 51 | 55 | this.editable = editable; |
| 56 | + this.leaderboardName = leaderboardName; |
|
| 52 | 57 | this.boatClass = boatClass; |
| 53 | 58 | } |
| 54 | - |
|
| 59 | + |
|
| 55 | 60 | @Override |
| 56 | 61 | protected Widget getAdditionalWidget() { |
| 57 | 62 | FlowPanel mainPanel = new FlowPanel(); |
| 58 | - |
|
| 63 | + |
|
| 59 | 64 | Button addCompetitorButton = new Button(stringMessages.add(stringMessages.competitor())); |
| 60 | 65 | addCompetitorButton.addClickHandler(new ClickHandler() { |
| 61 | 66 | @Override |
| ... | ... | @@ -63,7 +68,7 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 63 | 68 | openAddCompetitorDialog(); |
| 64 | 69 | } |
| 65 | 70 | }); |
| 66 | - |
|
| 71 | + |
|
| 67 | 72 | Button editCompetitorButton = new Button(stringMessages.edit(stringMessages.competitor())); |
| 68 | 73 | editCompetitorButton.addClickHandler(new ClickHandler() { |
| 69 | 74 | @Override |
| ... | ... | @@ -72,11 +77,25 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 72 | 77 | } |
| 73 | 78 | }); |
| 74 | 79 | |
| 80 | + final Button inviteCompetitorsButton = new Button(stringMessages.inviteSelectedCompetitors()); |
|
| 81 | + inviteCompetitorsButton.addClickHandler(new ClickHandler() { |
|
| 82 | + @Override |
|
| 83 | + public void onClick(ClickEvent event) { |
|
| 84 | + Set<CompetitorDTO> competitors = registeredCompetitorsTable.getSelectionModel().getSelectedSet(); |
|
| 85 | + |
|
| 86 | + CompetitorInvitationHelper helper = new CompetitorInvitationHelper(sailingService, stringMessages, |
|
| 87 | + errorReporter); |
|
| 88 | + helper.inviteCompetitors(competitors, leaderboardName); |
|
| 89 | + } |
|
| 90 | + }); |
|
| 91 | + |
|
| 75 | 92 | HorizontalPanel competitorRegistrationPanel = new HorizontalPanel(); |
| 76 | 93 | CaptionPanel allCompetitorsPanel = new CaptionPanel(stringMessages.competitorPool()); |
| 77 | 94 | CaptionPanel registeredCompetitorsPanel = new CaptionPanel(stringMessages.registeredCompetitors()); |
| 78 | - allCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ true, /* enablePager */ true); |
|
| 79 | - registeredCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ true, /* enablePager */ true); |
|
| 95 | + allCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ |
|
| 96 | + true, /* enablePager */true); |
|
| 97 | + registeredCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ |
|
| 98 | + true, /* enablePager */true); |
|
| 80 | 99 | allCompetitorsPanel.add(allCompetitorsTable); |
| 81 | 100 | registeredCompetitorsPanel.add(registeredCompetitorsTable); |
| 82 | 101 | VerticalPanel movePanel = new VerticalPanel(); |
| ... | ... | @@ -102,16 +121,17 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 102 | 121 | competitorRegistrationPanel.add(movePanel); |
| 103 | 122 | competitorRegistrationPanel.setCellVerticalAlignment(movePanel, HasVerticalAlignment.ALIGN_MIDDLE); |
| 104 | 123 | competitorRegistrationPanel.add(allCompetitorsPanel); |
| 105 | - |
|
| 124 | + |
|
| 106 | 125 | refreshCompetitors(); |
| 107 | - |
|
| 126 | + |
|
| 108 | 127 | mainPanel.add(addCompetitorButton); |
| 109 | 128 | mainPanel.add(editCompetitorButton); |
| 129 | + mainPanel.add(inviteCompetitorsButton); |
|
| 110 | 130 | mainPanel.add(competitorRegistrationPanel); |
| 111 | 131 | |
| 112 | 132 | return mainPanel; |
| 113 | 133 | } |
| 114 | - |
|
| 134 | + |
|
| 115 | 135 | void move(CompetitorTableWrapper<?> from, CompetitorTableWrapper<?> to, Collection<CompetitorDTO> toMove) { |
| 116 | 136 | if (!toMove.isEmpty()) { |
| 117 | 137 | List<CompetitorDTO> newFromList = new ArrayList<>(); |
| ... | ... | @@ -130,7 +150,6 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 130 | 150 | move(from, to, from.getSelectionModel().getSelectedSet()); |
| 131 | 151 | } |
| 132 | 152 | |
| 133 | - |
|
| 134 | 153 | private void openAddCompetitorDialog() { |
| 135 | 154 | new CompetitorEditDialog(stringMessages, new CompetitorDTOImpl(), |
| 136 | 155 | new DataEntryDialog.DialogCallback<CompetitorDTO>() { |
| ... | ... | @@ -154,37 +173,40 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 154 | 173 | } |
| 155 | 174 | }, boatClass).show(); |
| 156 | 175 | } |
| 157 | - |
|
| 176 | + |
|
| 158 | 177 | private void openEditCompetitorDialog() { |
| 159 | - //get currently selected competitor |
|
| 160 | - if (registeredCompetitorsTable.getSelectionModel().getSelectedSet().size() != 1){ |
|
| 178 | + // get currently selected competitor |
|
| 179 | + if (registeredCompetitorsTable.getSelectionModel().getSelectedSet().size() != 1) { |
|
| 161 | 180 | // show some warning |
| 162 | 181 | } else { |
| 163 | - final CompetitorDTO competitorToEdit = registeredCompetitorsTable.getSelectionModel().getSelectedSet().iterator().next(); |
|
| 182 | + final CompetitorDTO competitorToEdit = registeredCompetitorsTable.getSelectionModel().getSelectedSet() |
|
| 183 | + .iterator().next(); |
|
| 164 | 184 | new CompetitorEditDialog(stringMessages, competitorToEdit, |
| 165 | 185 | new DataEntryDialog.DialogCallback<CompetitorDTO>() { |
| 166 | - @Override |
|
| 167 | - public void ok(CompetitorDTO competitor) { |
|
| 168 | - sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback<CompetitorDTO>() { |
|
| 169 | 186 | @Override |
| 170 | - public void onFailure(Throwable caught) { |
|
| 171 | - errorReporter.reportError("Error trying to add competitor: " + caught.getMessage()); |
|
| 187 | + public void ok(CompetitorDTO competitor) { |
|
| 188 | + sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback<CompetitorDTO>() { |
|
| 189 | + @Override |
|
| 190 | + public void onFailure(Throwable caught) { |
|
| 191 | + errorReporter.reportError("Error trying to add competitor: " + caught.getMessage()); |
|
| 192 | + } |
|
| 193 | + |
|
| 194 | + @Override |
|
| 195 | + public void onSuccess(CompetitorDTO updatedCompetitor) { |
|
| 196 | + int editedCompetitorIndex = registeredCompetitorsTable.getDataProvider().getList() |
|
| 197 | + .indexOf(competitorToEdit); |
|
| 198 | + registeredCompetitorsTable.getDataProvider().getList().remove(competitorToEdit); |
|
| 199 | + registeredCompetitorsTable.getDataProvider().getList() |
|
| 200 | + .add(editedCompetitorIndex, updatedCompetitor); |
|
| 201 | + registeredCompetitorsTable.getDataProvider().refresh(); |
|
| 202 | + } |
|
| 203 | + }); |
|
| 172 | 204 | } |
| 173 | 205 | |
| 174 | 206 | @Override |
| 175 | - public void onSuccess(CompetitorDTO updatedCompetitor) { |
|
| 176 | - int editedCompetitorIndex = registeredCompetitorsTable.getDataProvider().getList().indexOf(competitorToEdit); |
|
| 177 | - registeredCompetitorsTable.getDataProvider().getList().remove(competitorToEdit); |
|
| 178 | - registeredCompetitorsTable.getDataProvider().getList().add(editedCompetitorIndex, updatedCompetitor); |
|
| 179 | - registeredCompetitorsTable.getDataProvider().refresh(); |
|
| 207 | + public void cancel() { |
|
| 180 | 208 | } |
| 181 | - }); |
|
| 182 | - } |
|
| 183 | - |
|
| 184 | - @Override |
|
| 185 | - public void cancel() { |
|
| 186 | - } |
|
| 187 | - }, /* boatClass */ null).show(); |
|
| 209 | + }, /* boatClass */null).show(); |
|
| 188 | 210 | } |
| 189 | 211 | } |
| 190 | 212 | |
| ... | ... | @@ -195,13 +217,13 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia |
| 195 | 217 | public void onSuccess(Iterable<CompetitorDTO> result) { |
| 196 | 218 | setRegisteredCompetitors(); |
| 197 | 219 | } |
| 198 | - |
|
| 220 | + |
|
| 199 | 221 | @Override |
| 200 | 222 | public void onFailure(Throwable reason) { |
| 201 | 223 | } |
| 202 | 224 | }); |
| 203 | 225 | } |
| 204 | - |
|
| 226 | + |
|
| 205 | 227 | protected abstract void setRegisteredCompetitors(); |
| 206 | 228 | |
| 207 | 229 | @Override |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java
| ... | ... | @@ -113,6 +113,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements |
| 113 | 113 | /* RACES */
|
| 114 | 114 | |
| 115 | 115 | final TabLayoutPanel racesTabPanel = panel.addVerticalTab(getStringMessages().trackedRaces(), "RacesPanel");
|
| 116 | + racesTabPanel.ensureDebugId("RacesPanel");
|
|
| 116 | 117 | TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(sailingService, this,
|
| 117 | 118 | this, getStringMessages());
|
| 118 | 119 | trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
|
| ... | ... | @@ -121,6 +122,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements |
| 121 | 122 | regattasDisplayers.add(trackedRacesManagementPanel);
|
| 122 | 123 | |
| 123 | 124 | final CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, getStringMessages(), this);
|
| 125 | + competitorPanel.ensureDebugId("CompetitorPanel");
|
|
| 124 | 126 | panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<CompetitorPanel>(competitorPanel) {
|
| 125 | 127 | @Override
|
| 126 | 128 | public void refreshAfterBecomingVisible() {
|
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorEditDialog.java
| ... | ... | @@ -81,10 +81,12 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> { |
| 81 | 81 | return result; |
| 82 | 82 | } |
| 83 | 83 | }, /* animationEnabled */true, callback); |
| 84 | + this.ensureDebugId("CompetitorEditDialog"); |
|
| 84 | 85 | this.stringMessages = stringMessages; |
| 85 | 86 | this.competitorToEdit = competitorToEdit; |
| 86 | 87 | |
| 87 | 88 | this.boatClassName = createSuggestBox(BoatClassMasterdata.getAllBoatClassNames(/* includeAlternativeNames */ true)); |
| 89 | + boatClassName.ensureDebugId("BoatClassNameSuggestBox"); |
|
| 88 | 90 | int i=0; |
| 89 | 91 | List<String> boatClassNamesList = new ArrayList<String>(); |
| 90 | 92 | for (BoatClassMasterdata t : BoatClassMasterdata.values()) { |
| ... | ... | @@ -97,6 +99,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> { |
| 97 | 99 | boatClassName.setValue(boatClass); // widgets have to accept null values here |
| 98 | 100 | } |
| 99 | 101 | this.name = createTextBox(competitorToEdit.getName()); |
| 102 | + name.ensureDebugId("NameTextBox"); |
|
| 100 | 103 | this.email = createTextBox(competitorToEdit.getEmail()); |
| 101 | 104 | this.displayColorTextBox = createTextBox(competitorToEdit.getColor() == null ? "" : competitorToEdit.getColor().getAsHtml()); |
| 102 | 105 | this.threeLetterIocCountryCode = createListBox(/* isMultipleSelect */ false); |
| ... | ... | @@ -127,6 +130,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> { |
| 127 | 130 | } |
| 128 | 131 | } |
| 129 | 132 | this.sailId = createTextBox(competitorToEdit.getSailID()); |
| 133 | + sailId.ensureDebugId("SailIdTextBox"); |
|
| 130 | 134 | this.flagImageURL = new URLFieldWithFileUpload(stringMessages); |
| 131 | 135 | this.flagImageURL.setURL(competitorToEdit.getFlagImageURL()); |
| 132 | 136 | this.imageUrlAndUploadComposite = new URLFieldWithFileUpload(stringMessages); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorInvitationHelper.java
| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | +package com.sap.sailing.gwt.ui.adminconsole; |
|
| 2 | + |
|
| 3 | +import java.util.Set; |
|
| 4 | + |
|
| 5 | +import com.google.gwt.i18n.client.LocaleInfo; |
|
| 6 | +import com.google.gwt.user.client.Window; |
|
| 7 | +import com.google.gwt.user.client.rpc.AsyncCallback; |
|
| 8 | +import com.sap.sailing.domain.common.dto.CompetitorDTO; |
|
| 9 | +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; |
|
| 10 | +import com.sap.sailing.gwt.ui.client.StringMessages; |
|
| 11 | +import com.sap.sailing.gwt.ui.shared.EventDTO; |
|
| 12 | +import com.sap.sse.common.Util.Pair; |
|
| 13 | +import com.sap.sse.gwt.client.ErrorReporter; |
|
| 14 | +import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; |
|
| 15 | + |
|
| 16 | +public class CompetitorInvitationHelper { |
|
| 17 | + |
|
| 18 | + private StringMessages stringMessages; |
|
| 19 | + private SailingServiceAsync sailingService; |
|
| 20 | + private ErrorReporter errorReporter; |
|
| 21 | + |
|
| 22 | + public CompetitorInvitationHelper(SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter errorReporter) { |
|
| 23 | + this.stringMessages = stringMessages; |
|
| 24 | + this.sailingService = sailingService; |
|
| 25 | + this.errorReporter = errorReporter; |
|
| 26 | + } |
|
| 27 | + |
|
| 28 | + public void inviteCompetitors(Set<CompetitorDTO> competitors, String leaderboardName) { |
|
| 29 | + if (competitors.size() == 0){ |
|
| 30 | + Window.alert(stringMessages.selectAtLeastOneCompetitorForInvitation()); |
|
| 31 | + } else { |
|
| 32 | + boolean emailProvidedForAll = isEmailProvidedForAll(competitors); |
|
| 33 | + |
|
| 34 | + if (emailProvidedForAll) { |
|
| 35 | + openChooseEventDialogAndSendMails(competitors, leaderboardName); |
|
| 36 | + } else { |
|
| 37 | + Window.alert(stringMessages.notAllCompetitorsProvideEmail()); |
|
| 38 | + } |
|
| 39 | + } |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + private boolean isEmailProvidedForAll(Iterable<CompetitorDTO> allCompetitors) { |
|
| 43 | + for (CompetitorDTO competitor : allCompetitors) { |
|
| 44 | + if (!competitor.hasEmail()) { |
|
| 45 | + return false; |
|
| 46 | + } |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + return true; |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | + private void openChooseEventDialogAndSendMails(final Set<CompetitorDTO> competitors, final String leaderboardName) { |
|
| 53 | + new SelectEventAndHostnameDialog(sailingService, stringMessages, errorReporter, leaderboardName, new DialogCallback<Pair<EventDTO, String>>() { |
|
| 54 | + |
|
| 55 | + @Override |
|
| 56 | + public void ok(Pair<EventDTO, String> result) { |
|
| 57 | + sailingService.inviteCompetitorsForTrackingViaEmail(result.getB(), result.getA(), leaderboardName, |
|
| 58 | + competitors, getLocaleInfo(), new AsyncCallback<Void>() { |
|
| 59 | + |
|
| 60 | + @Override |
|
| 61 | + public void onFailure(Throwable caught) { |
|
| 62 | + Window.alert(stringMessages.sendingMailsFailed() + caught.getMessage()); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + @Override |
|
| 66 | + public void onSuccess(Void result) { |
|
| 67 | + Window.alert(stringMessages.sendingMailsSuccessful()); |
|
| 68 | + } |
|
| 69 | + }); |
|
| 70 | + } |
|
| 71 | + |
|
| 72 | + @Override |
|
| 73 | + public void cancel() { |
|
| 74 | + |
|
| 75 | + } |
|
| 76 | + }).show(); |
|
| 77 | + } |
|
| 78 | + |
|
| 79 | + |
|
| 80 | + private String getLocaleInfo() { |
|
| 81 | + return LocaleInfo.getCurrentLocale().getLocaleName(); |
|
| 82 | + } |
|
| 83 | +} |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java
| ... | ... | @@ -8,7 +8,6 @@ import java.util.Set; |
| 8 | 8 | import com.google.gwt.cell.client.FieldUpdater; |
| 9 | 9 | import com.google.gwt.event.dom.client.ClickEvent; |
| 10 | 10 | import com.google.gwt.event.dom.client.ClickHandler; |
| 11 | -import com.google.gwt.i18n.client.LocaleInfo; |
|
| 12 | 11 | import com.google.gwt.user.client.Window; |
| 13 | 12 | import com.google.gwt.user.client.rpc.AsyncCallback; |
| 14 | 13 | import com.google.gwt.user.client.ui.Button; |
| ... | ... | @@ -22,9 +21,7 @@ import com.sap.sailing.domain.common.dto.CompetitorDTO; |
| 22 | 21 | import com.sap.sailing.domain.common.dto.CompetitorDTOImpl; |
| 23 | 22 | import com.sap.sailing.gwt.ui.client.SailingServiceAsync; |
| 24 | 23 | import com.sap.sailing.gwt.ui.client.StringMessages; |
| 25 | -import com.sap.sailing.gwt.ui.shared.EventDTO; |
|
| 26 | 24 | import com.sap.sse.common.Util; |
| 27 | -import com.sap.sse.common.Util.Pair; |
|
| 28 | 25 | import com.sap.sse.gwt.client.ErrorReporter; |
| 29 | 26 | import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; |
| 30 | 27 | |
| ... | ... | @@ -81,6 +78,7 @@ public class CompetitorPanel extends SimplePanel { |
| 81 | 78 | }); |
| 82 | 79 | buttonPanel.add(allowReloadButton); |
| 83 | 80 | Button addCompetitorButton = new Button(stringMessages.add()); |
| 81 | + addCompetitorButton.ensureDebugId("AddCompetitorButton"); |
|
| 84 | 82 | addCompetitorButton.addClickHandler(new ClickHandler() { |
| 85 | 83 | @Override |
| 86 | 84 | public void onClick(ClickEvent event) { |
| ... | ... | @@ -108,27 +106,8 @@ public class CompetitorPanel extends SimplePanel { |
| 108 | 106 | public void onClick(ClickEvent event) { |
| 109 | 107 | Set<CompetitorDTO> competitors = competitorSelectionModel.getSelectedSet(); |
| 110 | 108 | |
| 111 | - if (competitors.size() == 0){ |
|
| 112 | - Window.alert(stringMessages.selectAtLeastOneCompetitorForInvitation()); |
|
| 113 | - } else { |
|
| 114 | - boolean emailProvidedForAll = isEmailProvidedForAll(competitors); |
|
| 115 | - |
|
| 116 | - if (emailProvidedForAll) { |
|
| 117 | - openChooseEventDialogAndSendMails(competitors); |
|
| 118 | - } else { |
|
| 119 | - Window.alert(stringMessages.notAllCompetitorsProvideEmail()); |
|
| 120 | - } |
|
| 121 | - } |
|
| 122 | - } |
|
| 123 | - |
|
| 124 | - private boolean isEmailProvidedForAll(Iterable<CompetitorDTO> allCompetitors) { |
|
| 125 | - for (CompetitorDTO competitor : allCompetitors) { |
|
| 126 | - if (!competitor.hasEmail()) { |
|
| 127 | - return false; |
|
| 128 | - } |
|
| 129 | - } |
|
| 130 | - |
|
| 131 | - return true; |
|
| 109 | + CompetitorInvitationHelper helper = new CompetitorInvitationHelper(sailingService, stringMessages, errorReporter); |
|
| 110 | + helper.inviteCompetitors(competitors, leaderboardName); |
|
| 132 | 111 | } |
| 133 | 112 | }); |
| 134 | 113 | buttonPanel.add(inviteCompetitorsButton); |
| ... | ... | @@ -188,7 +167,7 @@ public class CompetitorPanel extends SimplePanel { |
| 188 | 167 | } |
| 189 | 168 | |
| 190 | 169 | private void openEditCompetitorDialog(CompetitorDTO competitor) { |
| 191 | - new CompetitorEditDialog(stringMessages, competitor, new DialogCallback<CompetitorDTO>() { |
|
| 170 | + final CompetitorEditDialog dialog = new CompetitorEditDialog(stringMessages, competitor, new DialogCallback<CompetitorDTO>() { |
|
| 192 | 171 | @Override |
| 193 | 172 | public void ok(CompetitorDTO competitor) { |
| 194 | 173 | sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback<CompetitorDTO>() { |
| ... | ... | @@ -207,38 +186,9 @@ public class CompetitorPanel extends SimplePanel { |
| 207 | 186 | @Override |
| 208 | 187 | public void cancel() { |
| 209 | 188 | } |
| 210 | - }, /* boat class to be used from CompetitorDTO */ null).show(); |
|
| 211 | - } |
|
| 212 | - |
|
| 213 | - private String getLocaleInfo() { |
|
| 214 | - return LocaleInfo.getCurrentLocale().getLocaleName(); |
|
| 215 | - } |
|
| 216 | - |
|
| 217 | - private void openChooseEventDialogAndSendMails(final Set<CompetitorDTO> competitors) { |
|
| 218 | - new SelectEventAndHostnameDialog(sailingService, stringMessages, errorReporter, leaderboardName, new DialogCallback<Pair<EventDTO, String>>() { |
|
| 219 | - |
|
| 220 | - @Override |
|
| 221 | - public void ok(Pair<EventDTO, String> result) { |
|
| 222 | - sailingService.inviteCompetitorsForTrackingViaEmail(result.getB(), result.getA(), leaderboardName, |
|
| 223 | - competitors, getLocaleInfo(), new AsyncCallback<Void>() { |
|
| 224 | - |
|
| 225 | - @Override |
|
| 226 | - public void onFailure(Throwable caught) { |
|
| 227 | - Window.alert(stringMessages.sendingMailsFailed() + caught.getMessage()); |
|
| 228 | - } |
|
| 229 | - |
|
| 230 | - @Override |
|
| 231 | - public void onSuccess(Void result) { |
|
| 232 | - Window.alert(stringMessages.sendingMailsSuccessful()); |
|
| 233 | - } |
|
| 234 | - }); |
|
| 235 | - } |
|
| 236 | - |
|
| 237 | - @Override |
|
| 238 | - public void cancel() { |
|
| 239 | - |
|
| 240 | - } |
|
| 241 | - }).show(); |
|
| 189 | + }, /* boat class to be used from CompetitorDTO */ null); |
|
| 190 | + dialog.ensureDebugId("CompetitorEditDialog"); |
|
| 191 | + dialog.show(); |
|
| 242 | 192 | } |
| 243 | 193 | |
| 244 | 194 | public void refreshCompetitorList() { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java
| ... | ... | @@ -209,6 +209,7 @@ public class CompetitorTableWrapper<S extends SelectionModel<CompetitorDTO>> ext |
| 209 | 209 | table.addColumn(imageColumn, stringMessages.image()); |
| 210 | 210 | table.addColumn(competitorEMailColumn, stringMessages.email()); |
| 211 | 211 | table.addColumn(competitorIdColumn, stringMessages.id()); |
| 212 | + table.ensureDebugId("CompetitorsTable"); |
|
| 212 | 213 | } |
| 213 | 214 | |
| 214 | 215 | public Iterable<CompetitorDTO> getAllCompetitors() { |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCompetitorRegistrationDialog.java
| ... | ... | @@ -18,8 +18,7 @@ public class RaceLogCompetitorRegistrationDialog extends AbstractCompetitorRegis |
| 18 | 18 | public RaceLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, StringMessages stringMessages, |
| 19 | 19 | ErrorReporter errorReporter, boolean editable, String leaderboardName, String raceColumnName, String fleetName, |
| 20 | 20 | com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback<Set<CompetitorDTO>> callback) { |
| 21 | - super(sailingService, stringMessages, errorReporter, editable, callback, boatClass); |
|
| 22 | - this.leaderboardName = leaderboardName; |
|
| 21 | + super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass); |
|
| 23 | 22 | this.raceColumnName = raceColumnName; |
| 24 | 23 | this.fleetName = fleetName; |
| 25 | 24 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCourseManagementWidget.java
| ... | ... | @@ -126,6 +126,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { |
| 126 | 126 | @Override |
| 127 | 127 | public void onSuccess(RaceCourseDTO result) { |
| 128 | 128 | updateWaypointsAndControlPoints(result); |
| 129 | + marks.refresh(result.getMarks()); |
|
| 129 | 130 | } |
| 130 | 131 | |
| 131 | 132 | @Override |
| ... | ... | @@ -133,18 +134,5 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { |
| 133 | 134 | errorReporter.reportError("Could not load course: " + caught.getMessage()); |
| 134 | 135 | } |
| 135 | 136 | }); |
| 136 | - |
|
| 137 | - sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName, |
|
| 138 | - new AsyncCallback<Iterable<MarkDTO>>() { |
|
| 139 | - @Override |
|
| 140 | - public void onSuccess(Iterable<MarkDTO> result) { |
|
| 141 | - marks.refresh(result); |
|
| 142 | - } |
|
| 143 | - |
|
| 144 | - @Override |
|
| 145 | - public void onFailure(Throwable caught) { |
|
| 146 | - errorReporter.reportError("Could not load marks: " + caught.getMessage()); |
|
| 147 | - } |
|
| 148 | - }); |
|
| 149 | 137 | } |
| 150 | 138 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogCompetitorRegistrationDialog.java
| ... | ... | @@ -11,13 +11,10 @@ import com.sap.sse.gwt.client.ErrorReporter; |
| 11 | 11 | |
| 12 | 12 | public class RegattaLogCompetitorRegistrationDialog extends AbstractCompetitorRegistrationsDialog { |
| 13 | 13 | |
| 14 | - private String leaderboardName; |
|
| 15 | - |
|
| 16 | 14 | public RegattaLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, StringMessages stringMessages, |
| 17 | 15 | ErrorReporter errorReporter, boolean editable, String leaderboardName, |
| 18 | 16 | com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback<Set<CompetitorDTO>> callback) { |
| 19 | - super(sailingService, stringMessages, errorReporter, editable, callback, boatClass); |
|
| 20 | - this.leaderboardName = leaderboardName; |
|
| 17 | + super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass); |
|
| 21 | 18 | } |
| 22 | 19 | |
| 23 | 20 | @Override |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
| ... | ... | @@ -464,7 +464,6 @@ actionAddEvent=Add Event |
| 464 | 464 | publicationUrl=Publication URL |
| 465 | 465 | suppress=Suppress |
| 466 | 466 | isPublic=Is public |
| 467 | -suppress=Suppress |
|
| 468 | 467 | unsuppress=Unsuppress |
| 469 | 468 | suppressedCompetitors=Suppressed Competitors |
| 470 | 469 | mediaPanel=Audio & Video |
| ... | ... | @@ -533,7 +532,6 @@ knotsValue={0,number,#0.0} kts |
| 533 | 532 | knotsRange={0,number,#0.0} - {1,number,#0.0} kts |
| 534 | 533 | scoringSchemeHighPointFirstGetsOne=High Point, winner gets 1 point |
| 535 | 534 | scoringSchemeHighPointFirstGetsTen=High Point, winner gets 10 points |
| 536 | -knotsUnit=kts |
|
| 537 | 535 | generatePolarSheet=Generate Polar Sheet |
| 538 | 536 | polars=Polar Diagrams |
| 539 | 537 | polarSheetChart=Polar Sheet |
| ... | ... | @@ -587,7 +585,6 @@ courseAreas=Course areas |
| 587 | 585 | courseArea=Course area |
| 588 | 586 | pleaseEnterNonEmptyCourseArea=Please enter a course area. |
| 589 | 587 | pleaseSelectACourseArea=Please select a course area. |
| 590 | -radiusInMeters=Radius (m) |
|
| 591 | 588 | lastUpperFlag=Upper flag |
| 592 | 589 | lastLowerFlag=Lower flag |
| 593 | 590 | cannotAddRacesToRegattaLeaderboardButOnlyToRegatta=This is a regatta leaderboard. You can only add races to this leaderboard directly in the regatta definition. |
| ... | ... | @@ -767,7 +764,6 @@ startAt=Start at |
| 767 | 764 | finishAt=Finish at |
| 768 | 765 | protestEndsAt=Protest ends at |
| 769 | 766 | unknown=Unknown |
| 770 | -earlyStarters=Early starters |
|
| 771 | 767 | raceLog=Race log |
| 772 | 768 | regattaLog=Regatta log |
| 773 | 769 | refreshRaceLog=Refresh race log |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
| ... | ... | @@ -465,7 +465,6 @@ actionAddEvent=Veranstaltung hinzufügen |
| 465 | 465 | publicationUrl=URL für die Veröffentlichung |
| 466 | 466 | suppress=Entfernen |
| 467 | 467 | isPublic=Öffentlich zugänglich |
| 468 | -suppress=Entfernen |
|
| 469 | 468 | unsuppress=Wieder hinzufügen |
| 470 | 469 | suppressedCompetitors=Unterdrückte Wettkampfteilnehmer |
| 471 | 470 | mediaPanel=Audio & Video |
| ... | ... | @@ -763,7 +762,6 @@ startAt=Start |
| 763 | 762 | finishAt=Rennende |
| 764 | 763 | protestEndsAt=Protestzeit endet |
| 765 | 764 | unknown=Unbekannt |
| 766 | -earlyStarters=Frühstarter |
|
| 767 | 765 | raceLog=RaceLog |
| 768 | 766 | regattaLog=RegattaLog |
| 769 | 767 | refreshRaceLog=RaceLog neu laden |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
| ... | ... | @@ -448,7 +448,6 @@ actionAddEvent=Добавить событие |
| 448 | 448 | publicationUrl=URL-адрес для публикации |
| 449 | 449 | suppress=скрыть |
| 450 | 450 | isPublic=является открытым |
| 451 | -suppress=скрыть |
|
| 452 | 451 | unsuppress=Отобразить |
| 453 | 452 | suppressedCompetitors=Скрытые участники |
| 454 | 453 | mediaPanel=Аудио и Видео |
| ... | ... | @@ -567,7 +566,6 @@ courseAreas=Зоны курса |
| 567 | 566 | courseArea=Зона курса |
| 568 | 567 | pleaseEnterNonEmptyCourseArea=Пожалуйста, выведите зону курса. |
| 569 | 568 | pleaseSelectACourseArea=Пожалуйста, выберите зону курса. |
| 570 | -radiusInMeters=Радиус (м) |
|
| 571 | 569 | lastUpperFlag=Верхний флажок |
| 572 | 570 | lastLowerFlag=Нижний флажок |
| 573 | 571 | cannotAddRacesToRegattaLeaderboardButOnlyToRegatta=Это таблица лидеров регаты. Вы можете добавлять гонки в эту таблицу лидеров только непосредственно в определении регаты. |
| ... | ... | @@ -748,7 +746,6 @@ startAt=Старт в |
| 748 | 746 | finishAt=Финиш в |
| 749 | 747 | protestEndsAt=Срок подачи протеста завершается в |
| 750 | 748 | unknown=Неизвестно |
| 751 | -earlyStarters=Совершивших фальшстарт |
|
| 752 | 749 | raceLog=Запись о гонке |
| 753 | 750 | regattaLog=Regatta log |
| 754 | 751 | refreshRaceLog=Обновить запись о гонке |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/GalleryImageHolder.java
| ... | ... | @@ -10,7 +10,7 @@ import com.google.gwt.event.shared.HandlerRegistration; |
| 10 | 10 | import com.google.gwt.uibinder.client.UiBinder; |
| 11 | 11 | import com.google.gwt.uibinder.client.UiField; |
| 12 | 12 | import com.google.gwt.user.client.ui.Widget; |
| 13 | -import com.sap.sailing.gwt.home.communication.media.SailingImageDTO; |
|
| 13 | +import com.sap.sse.gwt.client.media.ImageDTO; |
|
| 14 | 14 | |
| 15 | 15 | public class GalleryImageHolder extends Widget implements HasClickHandlers { |
| 16 | 16 | |
| ... | ... | @@ -22,7 +22,7 @@ public class GalleryImageHolder extends Widget implements HasClickHandlers { |
| 22 | 22 | @UiField |
| 23 | 23 | DivElement imageHolderUi; |
| 24 | 24 | |
| 25 | - public GalleryImageHolder(SailingImageDTO video) { |
|
| 25 | + public GalleryImageHolder(ImageDTO video) { |
|
| 26 | 26 | setElement(uiBinder.createAndBindUi(this)); |
| 27 | 27 | imageHolderUi.getStyle().setBackgroundImage("url(\"" + video.getSourceRef() + "\")"); |
| 28 | 28 |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/VideoThumbnail.java
| ... | ... | @@ -11,9 +11,9 @@ import com.google.gwt.event.shared.HandlerRegistration; |
| 11 | 11 | import com.google.gwt.uibinder.client.UiBinder; |
| 12 | 12 | import com.google.gwt.uibinder.client.UiField; |
| 13 | 13 | import com.google.gwt.user.client.ui.Widget; |
| 14 | -import com.sap.sailing.gwt.home.communication.media.SailingVideoDTO; |
|
| 15 | 14 | import com.sap.sailing.gwt.ui.common.client.YoutubeApi; |
| 16 | 15 | import com.sap.sse.common.media.MediaSubType; |
| 16 | +import com.sap.sse.gwt.client.media.VideoDTO; |
|
| 17 | 17 | |
| 18 | 18 | public class VideoThumbnail extends Widget implements HasClickHandlers { |
| 19 | 19 | |
| ... | ... | @@ -28,7 +28,7 @@ public class VideoThumbnail extends Widget implements HasClickHandlers { |
| 28 | 28 | @UiField |
| 29 | 29 | ImageElement thumbnailUi; |
| 30 | 30 | |
| 31 | - public VideoThumbnail(SailingVideoDTO video) { |
|
| 31 | + public VideoThumbnail(VideoDTO video) { |
|
| 32 | 32 | setElement(uiBinder.createAndBindUi(this)); |
| 33 | 33 | getElement().addClassName("videoThumbnail"); |
| 34 | 34 | captionUi.setInnerText(video.getTitle()); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPassingsPanel.java
| ... | ... | @@ -61,8 +61,7 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 61 | 61 | private final ErrorReporter errorReporter; |
| 62 | 62 | private final StringMessages stringMessages; |
| 63 | 63 | private final CompetitorSelectionProvider competitorSelectionModel; |
| 64 | - private String leaderboardName; |
|
| 65 | - private RaceColumnDTO column; |
|
| 64 | + private LeaderboardDTO leaderboard; |
|
| 66 | 65 | |
| 67 | 66 | private CompetitorDTO competitor; |
| 68 | 67 | |
| ... | ... | @@ -166,7 +165,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 166 | 165 | removeFixedMarkPassingsButton.addClickHandler(new ClickHandler() { |
| 167 | 166 | @Override |
| 168 | 167 | public void onClick(ClickEvent event) { |
| 169 | - sailingService.updateFixedMarkPassing(leaderboardName, column, column.getFleet(raceIdentifier), |
|
| 168 | + final RaceColumnDTO column = getColumn(); |
|
| 169 | + sailingService.updateFixedMarkPassing(getLeaderboardName(), column, column.getFleet(raceIdentifier), |
|
| 170 | 170 | waypointSelectionModel.getSelectedObject().getA(), null, competitor, new AsyncCallback<Void>() { |
| 171 | 171 | @Override |
| 172 | 172 | public void onFailure(Throwable caught) { |
| ... | ... | @@ -184,7 +184,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 184 | 184 | setTimeAsMarkPassingsButton.addClickHandler(new ClickHandler() { |
| 185 | 185 | @Override |
| 186 | 186 | public void onClick(ClickEvent event) { |
| 187 | - sailingService.updateFixedMarkPassing(leaderboardName, column, column.getFleet(raceIdentifier), |
|
| 187 | + final RaceColumnDTO column = getColumn(); |
|
| 188 | + sailingService.updateFixedMarkPassing(getLeaderboardName(), column, column.getFleet(raceIdentifier), |
|
| 188 | 189 | waypointSelectionModel.getSelectedObject().getA(), timer.getTime(), competitor, |
| 189 | 190 | new AsyncCallback<Void>() { |
| 190 | 191 | @Override |
| ... | ... | @@ -205,7 +206,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 205 | 206 | suppressPassingsButton.addClickHandler(new ClickHandler() { |
| 206 | 207 | @Override |
| 207 | 208 | public void onClick(ClickEvent event) { |
| 208 | - sailingService.updateSuppressedMarkPassings(leaderboardName, column, |
|
| 209 | + final RaceColumnDTO column = getColumn(); |
|
| 210 | + sailingService.updateSuppressedMarkPassings(getLeaderboardName(), column, |
|
| 209 | 211 | column.getFleet(raceIdentifier), waypointSelectionModel.getSelectedObject().getA(), |
| 210 | 212 | competitor, new AsyncCallback<Void>() { |
| 211 | 213 | @Override |
| ... | ... | @@ -225,7 +227,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 225 | 227 | removeSuppressedPassingButton.addClickHandler(new ClickHandler() { |
| 226 | 228 | @Override |
| 227 | 229 | public void onClick(ClickEvent event) { |
| 228 | - sailingService.updateSuppressedMarkPassings(leaderboardName, column, |
|
| 230 | + final RaceColumnDTO column = getColumn(); |
|
| 231 | + sailingService.updateSuppressedMarkPassings(getLeaderboardName(), column, |
|
| 229 | 232 | column.getFleet(raceIdentifier), null, competitor, |
| 230 | 233 | new AsyncCallback<Void>() { |
| 231 | 234 | @Override |
| ... | ... | @@ -311,7 +314,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 311 | 314 | waypointList.getList().clear(); |
| 312 | 315 | waypointList.getList().addAll(newMarkPassings); |
| 313 | 316 | // Get current edits |
| 314 | - sailingService.getCompetitorRaceLogMarkPassingData(leaderboardName, column, |
|
| 317 | + final RaceColumnDTO column = getColumn(); |
|
| 318 | + sailingService.getCompetitorRaceLogMarkPassingData(getLeaderboardName(), column, |
|
| 315 | 319 | column.getFleet(raceIdentifier), competitor, new AsyncCallback<Map<Integer, Date>>() { |
| 316 | 320 | @Override |
| 317 | 321 | public void onFailure(Throwable caught) { |
| ... | ... | @@ -385,15 +389,8 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 385 | 389 | refreshWaypoints(); |
| 386 | 390 | } |
| 387 | 391 | |
| 388 | - public void setLeaderboardNameAndColumn(LeaderboardDTO leaderboard) { |
|
| 389 | - if (leaderboard != null) { |
|
| 390 | - leaderboardName = leaderboard.name; |
|
| 391 | - for (RaceColumnDTO columnDTO : leaderboard.getRaceList()) { |
|
| 392 | - if (columnDTO.containsRace(raceIdentifier)) { |
|
| 393 | - column = columnDTO; |
|
| 394 | - } |
|
| 395 | - } |
|
| 396 | - } |
|
| 392 | + public void setLeaderboard(LeaderboardDTO leaderboard) { |
|
| 393 | + this.leaderboard = leaderboard; |
|
| 397 | 394 | } |
| 398 | 395 | |
| 399 | 396 | @Override |
| ... | ... | @@ -438,4 +435,20 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component<Ab |
| 438 | 435 | public void filteredCompetitorsListChanged(Iterable<CompetitorDTO> filteredCompetitors) { |
| 439 | 436 | } |
| 440 | 437 | |
| 438 | + private String getLeaderboardName() { |
|
| 439 | + return leaderboard.name; |
|
| 440 | + } |
|
| 441 | + |
|
| 442 | + private RaceColumnDTO getColumn() { |
|
| 443 | + RaceColumnDTO result = null; |
|
| 444 | + if (leaderboard != null) { |
|
| 445 | + for (RaceColumnDTO columnDTO : leaderboard.getRaceList()) { |
|
| 446 | + if (columnDTO.containsRace(raceIdentifier)) { |
|
| 447 | + result = columnDTO; |
|
| 448 | + break; |
|
| 449 | + } |
|
| 450 | + } |
|
| 451 | + } |
|
| 452 | + return result; |
|
| 453 | + } |
|
| 441 | 454 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java
| ... | ... | @@ -221,7 +221,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi |
| 221 | 221 | components.add(windChart);
|
| 222 | 222 | editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier,
|
| 223 | 223 | stringMessages, competitorSelectionProvider, errorReporter, timer);
|
| 224 | - editMarkPassingPanel.setLeaderboardNameAndColumn(leaderboardPanel.getLeaderboard());
|
|
| 224 | + editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
|
|
| 225 | 225 | editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
|
| 226 | 226 | components.add(editMarkPassingPanel);
|
| 227 | 227 | boolean autoSelectMedia = getConfiguration().isAutoSelectMedia();
|
| ... | ... | @@ -345,7 +345,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi |
| 345 | 345 | @Override
|
| 346 | 346 | public void updatedLeaderboard(LeaderboardDTO leaderboard) {
|
| 347 | 347 | leaderboardAndMapViewer.setLeftComponentWidth(leaderboardPanel.getContentPanel().getOffsetWidth());
|
| 348 | - editMarkPassingPanel.setLeaderboardNameAndColumn(leaderboard);
|
|
| 348 | + editMarkPassingPanel.setLeaderboard(leaderboard);
|
|
| 349 | 349 | }
|
| 350 | 350 | |
| 351 | 351 | @Override
|
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
| ... | ... | @@ -444,12 +444,7 @@ import com.sap.sse.common.Util.Triple; |
| 444 | 444 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 445 | 445 | import com.sap.sse.common.impl.TimeRangeImpl; |
| 446 | 446 | import com.sap.sse.common.mail.MailException; |
| 447 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 448 | -import com.sap.sse.common.media.ImageDescriptorImpl; |
|
| 449 | -import com.sap.sse.common.media.MediaUtils; |
|
| 450 | 447 | import com.sap.sse.common.media.MimeType; |
| 451 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 452 | -import com.sap.sse.common.media.VideoDescriptorImpl; |
|
| 453 | 448 | import com.sap.sse.filestorage.FileStorageService; |
| 454 | 449 | import com.sap.sse.filestorage.InvalidPropertiesException; |
| 455 | 450 | import com.sap.sse.gwt.client.ServerInfoDTO; |
| ... | ... | @@ -465,6 +460,11 @@ import com.sap.sse.replication.ReplicationMasterDescriptor; |
| 465 | 460 | import com.sap.sse.replication.ReplicationService; |
| 466 | 461 | import com.sap.sse.replication.impl.ReplicaDescriptor; |
| 467 | 462 | import com.sap.sse.security.SessionUtils; |
| 463 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 464 | +import com.sap.sse.shared.media.MediaUtils; |
|
| 465 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 466 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 467 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 468 | 468 | import com.sap.sse.util.ServiceTrackerFactory; |
| 469 | 469 | import com.sapsailing.xrr.structureimport.eventimport.RegattaJSON; |
| 470 | 470 | |
| ... | ... | @@ -1946,7 +1946,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 1946 | 1946 | result.totalLegsCount = trackedRace.getRace().getCourse().getLegs().size(); |
| 1947 | 1947 | result.currentLegNumber = trackedRace.getLastLegStarted(dateAsTimePoint); |
| 1948 | 1948 | result.marks = new HashSet<MarkDTO>(); |
| 1949 | - result.course = convertToRaceCourseDTO(trackedRace.getRace().getCourse(), trackedRace, dateAsTimePoint); |
|
| 1949 | + result.course = convertToRaceCourseDTO(trackedRace.getRace().getCourse(), new TrackedRaceMarkPositionFinder(trackedRace), dateAsTimePoint); |
|
| 1950 | 1950 | // now make sure we don't duplicate the MarkDTO objects but instead use the ones from the RaceCourseDTO |
| 1951 | 1951 | // object and amend them with the Position |
| 1952 | 1952 | result.waypointPositions = new ArrayList<>(); |
| ... | ... | @@ -2020,7 +2020,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 2020 | 2020 | for (Waypoint waypoint : course.getWaypoints()) { |
| 2021 | 2021 | ControlPointDTO controlPointDTO = controlPointCache.get(waypoint.getControlPoint().getId()); |
| 2022 | 2022 | if (controlPointDTO == null) { |
| 2023 | - controlPointDTO = convertToControlPointDTO(waypoint.getControlPoint(), trackedRace, dateAsTimePoint); |
|
| 2023 | + controlPointDTO = convertToControlPointDTO(waypoint.getControlPoint(), new TrackedRaceMarkPositionFinder(trackedRace), dateAsTimePoint); |
|
| 2024 | 2024 | controlPointCache.put(waypoint.getControlPoint().getId(), controlPointDTO); |
| 2025 | 2025 | } |
| 2026 | 2026 | WaypointDTO waypointDTO = new WaypointDTO(waypoint.getName(), controlPointDTO, |
| ... | ... | @@ -2031,20 +2031,44 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 2031 | 2031 | return new RaceCourseDTO(waypointDTOs, allMarks); |
| 2032 | 2032 | } |
| 2033 | 2033 | |
| 2034 | - private ControlPointDTO convertToControlPointDTO(ControlPoint controlPoint, TrackedRace trackedRace, TimePoint timePoint) { |
|
| 2034 | + class TrackedRaceMarkPositionFinder implements MarkPositionFinder{ |
|
| 2035 | + private TrackedRace trackedRace; |
|
| 2036 | + |
|
| 2037 | + public TrackedRaceMarkPositionFinder(TrackedRace trackedRace) { |
|
| 2038 | + this.trackedRace = trackedRace; |
|
| 2039 | + } |
|
| 2040 | + |
|
| 2041 | + @Override |
|
| 2042 | + public Position find(Mark mark, TimePoint at) { |
|
| 2043 | + final TimePoint timePointToUse = trackedRace == null ? null : |
|
| 2044 | + at == null ? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis()) : at; |
|
| 2045 | + final Position result; |
|
| 2046 | + if (timePointToUse == null) { |
|
| 2047 | + result = null; |
|
| 2048 | + } else { |
|
| 2049 | + result = trackedRace.getOrCreateTrack(mark).getEstimatedPosition(timePointToUse, /* extrapolate */ false); |
|
| 2050 | + } |
|
| 2051 | + return result; |
|
| 2052 | + } |
|
| 2053 | + } |
|
| 2054 | + |
|
| 2055 | + private interface MarkPositionFinder { |
|
| 2056 | + Position find(Mark mark, TimePoint at); |
|
| 2057 | + } |
|
| 2058 | + |
|
| 2059 | + private ControlPointDTO convertToControlPointDTO(ControlPoint controlPoint, MarkPositionFinder positionFinder, TimePoint timePoint) { |
|
| 2035 | 2060 | ControlPointDTO result; |
| 2036 | - final TimePoint timePointToUse = trackedRace == null ? null : |
|
| 2037 | - timePoint == null ? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis()) : timePoint; |
|
| 2061 | + |
|
| 2038 | 2062 | if (controlPoint instanceof ControlPointWithTwoMarks) { |
| 2039 | 2063 | final Mark left = ((ControlPointWithTwoMarks) controlPoint).getLeft(); |
| 2040 | - final Position leftPos = timePointToUse == null ? null : trackedRace.getOrCreateTrack(left).getEstimatedPosition(timePointToUse, /* extrapolate */ false); |
|
| 2064 | + final Position leftPos = positionFinder.find(left, timePoint); |
|
| 2041 | 2065 | final Mark right = ((ControlPointWithTwoMarks) controlPoint).getRight(); |
| 2042 | - final Position rightPos = timePointToUse == null ? null : trackedRace.getOrCreateTrack(right).getEstimatedPosition(timePointToUse, /* extrapolate */ false); |
|
| 2066 | + final Position rightPos = positionFinder.find(right, timePoint); |
|
| 2043 | 2067 | result = new GateDTO(controlPoint.getId().toString(), controlPoint.getName(), convertToMarkDTO(left, leftPos), convertToMarkDTO(right, rightPos)); |
| 2044 | 2068 | } else { |
| 2045 | - final Position posOfFirst = timePointToUse == null ? null : trackedRace.getOrCreateTrack(controlPoint.getMarks().iterator().next()). |
|
| 2046 | - getEstimatedPosition(timePointToUse, /* extrapolate */ false); |
|
| 2047 | - result = new MarkDTO(controlPoint.getId().toString(), controlPoint.getName(), posOfFirst == null ? -1 : posOfFirst.getLatDeg(), posOfFirst == null ? -1 : posOfFirst.getLngDeg()); |
|
| 2069 | + Mark mark = controlPoint.getMarks().iterator().next(); |
|
| 2070 | + final Position position = positionFinder.find(mark, timePoint); |
|
| 2071 | + result = convertToMarkDTO(mark, position); |
|
| 2048 | 2072 | } |
| 2049 | 2073 | return result; |
| 2050 | 2074 | } |
| ... | ... | @@ -5156,10 +5180,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 5156 | 5180 | * the mark positions and attach to the {@link MarkDTO}s. If <code>null<c/code>, the current time point |
| 5157 | 5181 | * will be used as default. |
| 5158 | 5182 | */ |
| 5159 | - private WaypointDTO convertToWaypointDTO(Waypoint waypoint, Map<Serializable, ControlPointDTO> controlPointCache, TrackedRace trackedRace, TimePoint timePoint) { |
|
| 5183 | + private WaypointDTO convertToWaypointDTO(Waypoint waypoint, Map<Serializable, ControlPointDTO> controlPointCache, MarkPositionFinder positionFinder, TimePoint timePoint) { |
|
| 5160 | 5184 | ControlPointDTO cp = controlPointCache.get(waypoint.getControlPoint().getId()); |
| 5161 | 5185 | if (cp == null) { |
| 5162 | - cp = convertToControlPointDTO(waypoint.getControlPoint(), trackedRace, timePoint); |
|
| 5186 | + cp = convertToControlPointDTO(waypoint.getControlPoint(), positionFinder, timePoint); |
|
| 5163 | 5187 | controlPointCache.put(waypoint.getControlPoint().getId(), cp); |
| 5164 | 5188 | } |
| 5165 | 5189 | return new WaypointDTO(waypoint.getName(), cp, waypoint.getPassingInstructions()); |
| ... | ... | @@ -5175,13 +5199,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 5175 | 5199 | * the mark positions and attach to the {@link MarkDTO}s. If <code>null<c/code>, the current time point |
| 5176 | 5200 | * will be used as default. |
| 5177 | 5201 | */ |
| 5178 | - private RaceCourseDTO convertToRaceCourseDTO(CourseBase course, TrackedRace trackedRace, TimePoint timePoint) { |
|
| 5202 | + private RaceCourseDTO convertToRaceCourseDTO(CourseBase course, MarkPositionFinder positionFinder, TimePoint timePoint) { |
|
| 5179 | 5203 | final RaceCourseDTO result; |
| 5180 | 5204 | if (course != null) { |
| 5181 | 5205 | List<WaypointDTO> waypointDTOs = new ArrayList<WaypointDTO>(); |
| 5182 | 5206 | Map<Serializable, ControlPointDTO> controlPointCache = new HashMap<>(); |
| 5183 | 5207 | for (Waypoint waypoint : course.getWaypoints()) { |
| 5184 | - waypointDTOs.add(convertToWaypointDTO(waypoint, controlPointCache, trackedRace, timePoint)); |
|
| 5208 | + waypointDTOs.add(convertToWaypointDTO(waypoint, controlPointCache, positionFinder, timePoint)); |
|
| 5185 | 5209 | } |
| 5186 | 5210 | result = new RaceCourseDTO(waypointDTOs); |
| 5187 | 5211 | } else { |
| ... | ... | @@ -5191,13 +5215,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S |
| 5191 | 5215 | } |
| 5192 | 5216 | |
| 5193 | 5217 | @Override |
| 5194 | - public RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName) { |
|
| 5195 | - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); |
|
| 5218 | + public RaceCourseDTO getLastCourseDefinitionInRaceLog(final String leaderboardName, String raceColumnName, String fleetName) { |
|
| 5219 | + final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); |
|
| 5196 | 5220 | CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze(); |
| 5197 | 5221 | if (lastPublishedCourse == null) { |
| 5198 | 5222 | lastPublishedCourse = new CourseDataImpl(""); |
| 5199 | 5223 | } |
| 5200 | - return convertToRaceCourseDTO(lastPublishedCourse, /* trackedRace */ null, /* timePoint */ null); |
|
| 5224 | + return convertToRaceCourseDTO(lastPublishedCourse, new MarkPositionFinder() { |
|
| 5225 | + @Override |
|
| 5226 | + public Position find(Mark mark, TimePoint at) { |
|
| 5227 | + return getService().getMarkPosition(mark, (LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), at, raceLog); |
|
| 5228 | + } |
|
| 5229 | + }, /* timePoint */ MillisecondsTimePoint.now()); |
|
| 5201 | 5230 | } |
| 5202 | 5231 | |
| 5203 | 5232 | @Override |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/SimulatorMainPanel.java
| ... | ... | @@ -310,25 +310,38 @@ public class SimulatorMainPanel extends SimplePanel { |
| 310 | 310 | int secondsTimeStep = (int) windParams.getTimeStep().asSeconds(); |
| 311 | 311 | timer.setPlaySpeedFactor(secondsTimeStep); |
| 312 | 312 | timePanel = new TimePanel<TimePanelSettings>(timer, timeRangeProvider, stringMessages, false); |
| 313 | - |
|
| 314 | 313 | busyIndicator = new SimpleBusyIndicator(false, 0.8f); |
| 315 | - |
|
| 316 | - simulatorMap = new SimulatorMap(simulatorSvc, stringMessages, errorReporter, xRes, yRes, border, streamletPars, timer, timePanel, |
|
| 317 | - windParams, busyIndicator, mode, this, showMapControls, new IdentityCoordinateSystem()); |
|
| 314 | + simulatorMap = new SimulatorMap(simulatorSvc, stringMessages, errorReporter, xRes, yRes, border, streamletPars, |
|
| 315 | + timer, timePanel, windParams, busyIndicator, mode, this, showMapControls, |
|
| 316 | + new IdentityCoordinateSystem()); |
|
| 318 | 317 | simulatorMap.setSize("100%", "100%"); |
| 319 | - |
|
| 320 | 318 | this.rightPanel.add(this.simulatorMap); |
| 321 | - |
|
| 322 | 319 | createOptionsPanelTop(); |
| 323 | 320 | createOptionsPanel(); |
| 324 | - |
|
| 325 | 321 | fullTimePanel = this.createTimePanel(); |
| 326 | 322 | |
| 323 | + final Button toggleButton = timePanel.getAdvancedToggleButton(); |
|
| 324 | + toggleButton.addClickHandler(new ClickHandler() { |
|
| 325 | + @Override |
|
| 326 | + public void onClick(ClickEvent event) { |
|
| 327 | + boolean advancedModeShown = timePanel.toggleAdvancedMode(); |
|
| 328 | + if (advancedModeShown) { |
|
| 329 | + mainPanel.setWidgetSize(fullTimePanel, 96); |
|
| 330 | + toggleButton.removeStyleDependentName("Closed"); |
|
| 331 | + toggleButton.addStyleDependentName("Open"); |
|
| 332 | + } else { |
|
| 333 | + mainPanel.setWidgetSize(fullTimePanel, 67); |
|
| 334 | + toggleButton.addStyleDependentName("Closed"); |
|
| 335 | + toggleButton.removeStyleDependentName("Open"); |
|
| 336 | + } |
|
| 337 | + } |
|
| 338 | + }); |
|
| 339 | + |
|
| 327 | 340 | mainPanel = new DockLayoutPanel(Unit.PX); |
| 328 | 341 | |
| 329 | 342 | mainPanel.setSize("100%", "100%"); |
| 330 | 343 | mainPanel.addWest(leftPanel, 470); |
| 331 | - mainPanel.addSouth(fullTimePanel, 90); |
|
| 344 | + mainPanel.addSouth(fullTimePanel, 67); |
|
| 332 | 345 | mainPanel.setWidgetHidden(fullTimePanel, true); |
| 333 | 346 | |
| 334 | 347 | createMapOptionsPanel(); // add map-options to mainPanel-North |
| ... | ... | @@ -340,21 +353,21 @@ public class SimulatorMainPanel extends SimplePanel { |
| 340 | 353 | } |
| 341 | 354 | |
| 342 | 355 | public native void setMapInstance(Object mapInstance) /*-{ |
| 343 | - $wnd.swarmMap = mapInstance; |
|
| 356 | + $wnd.swarmMap = mapInstance; |
|
| 344 | 357 | }-*/; |
| 345 | 358 | |
| 346 | 359 | public native void setCanvasProjectionInstance(Object instance) /*-{ |
| 347 | - $wnd.swarmCanvasProjection = instance; |
|
| 348 | - }-*/; |
|
| 360 | + $wnd.swarmCanvasProjection = instance; |
|
| 361 | + }-*/; |
|
| 349 | 362 | |
| 350 | 363 | public native void startStreamlets() /*-{ |
| 351 | - if ($wnd.swarmAnimator) { |
|
| 352 | - $wnd.swarmUpdData = true; |
|
| 353 | - $wnd.updateStreamlets($wnd.swarmUpdData); |
|
| 354 | - } else { |
|
| 355 | - $wnd.initStreamlets($wnd.swarmMap); |
|
| 356 | - } |
|
| 357 | - }-*/; |
|
| 364 | + if ($wnd.swarmAnimator) { |
|
| 365 | + $wnd.swarmUpdData = true; |
|
| 366 | + $wnd.updateStreamlets($wnd.swarmUpdData); |
|
| 367 | + } else { |
|
| 368 | + $wnd.initStreamlets($wnd.swarmMap); |
|
| 369 | + } |
|
| 370 | + }-*/; |
|
| 358 | 371 | |
| 359 | 372 | public void setDefaultTimeSettings() { |
| 360 | 373 | Date defaultNow = new Date(); |
java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF
| ... | ... | @@ -27,7 +27,8 @@ Require-Bundle: com.sap.sailing.domain, |
| 27 | 27 | com.sap.sse.operationaltransformation, |
| 28 | 28 | com.sap.sse.replication, |
| 29 | 29 | com.sap.sse, |
| 30 | - com.sap.sse.filestorage |
|
| 30 | + com.sap.sse.filestorage, |
|
| 31 | + com.sap.sse.shared.android |
|
| 31 | 32 | Import-Package: com.sap.sailing.domain.common, |
| 32 | 33 | com.sap.sailing.domain.common.impl, |
| 33 | 34 | com.sap.sailing.domain.common.racelog, |
java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java
| ... | ... | @@ -1,836 +1,836 @@ |
| 1 | -package com.sap.sailing.mongodb.test;
|
|
| 2 | -
|
|
| 3 | -import static org.junit.Assert.assertEquals;
|
|
| 4 | -import static org.junit.Assert.assertFalse;
|
|
| 5 | -import static org.junit.Assert.assertNotNull;
|
|
| 6 | -import static org.junit.Assert.assertNotSame;
|
|
| 7 | -import static org.junit.Assert.assertNull;
|
|
| 8 | -import static org.junit.Assert.assertSame;
|
|
| 9 | -import static org.junit.Assert.assertTrue;
|
|
| 10 | -
|
|
| 11 | -import java.io.Serializable;
|
|
| 12 | -import java.net.MalformedURLException;
|
|
| 13 | -import java.net.URL;
|
|
| 14 | -import java.net.UnknownHostException;
|
|
| 15 | -import java.util.ArrayList;
|
|
| 16 | -import java.util.Arrays;
|
|
| 17 | -import java.util.Calendar;
|
|
| 18 | -import java.util.Collections;
|
|
| 19 | -import java.util.Iterator;
|
|
| 20 | -import java.util.List;
|
|
| 21 | -import java.util.Locale;
|
|
| 22 | -import java.util.UUID;
|
|
| 23 | -import java.util.logging.Logger;
|
|
| 24 | -
|
|
| 25 | -import org.junit.Test;
|
|
| 26 | -
|
|
| 27 | -import com.mongodb.MongoException;
|
|
| 28 | -import com.sap.sailing.domain.base.BoatClass;
|
|
| 29 | -import com.sap.sailing.domain.base.Competitor;
|
|
| 30 | -import com.sap.sailing.domain.base.Course;
|
|
| 31 | -import com.sap.sailing.domain.base.CourseArea;
|
|
| 32 | -import com.sap.sailing.domain.base.DomainFactory;
|
|
| 33 | -import com.sap.sailing.domain.base.Event;
|
|
| 34 | -import com.sap.sailing.domain.base.Fleet;
|
|
| 35 | -import com.sap.sailing.domain.base.RaceColumn;
|
|
| 36 | -import com.sap.sailing.domain.base.RaceColumnInSeries;
|
|
| 37 | -import com.sap.sailing.domain.base.RaceDefinition;
|
|
| 38 | -import com.sap.sailing.domain.base.Regatta;
|
|
| 39 | -import com.sap.sailing.domain.base.Series;
|
|
| 40 | -import com.sap.sailing.domain.base.Venue;
|
|
| 41 | -import com.sap.sailing.domain.base.Waypoint;
|
|
| 42 | -import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl;
|
|
| 43 | -import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
|
| 44 | -import com.sap.sailing.domain.base.impl.CourseImpl;
|
|
| 45 | -import com.sap.sailing.domain.base.impl.EventImpl;
|
|
| 46 | -import com.sap.sailing.domain.base.impl.FleetImpl;
|
|
| 47 | -import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
|
|
| 48 | -import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
|
| 49 | -import com.sap.sailing.domain.base.impl.RegattaImpl;
|
|
| 50 | -import com.sap.sailing.domain.base.impl.SeriesImpl;
|
|
| 51 | -import com.sap.sailing.domain.base.impl.VenueImpl;
|
|
| 52 | -import com.sap.sailing.domain.common.MaxPointsReason;
|
|
| 53 | -import com.sap.sailing.domain.common.RaceIdentifier;
|
|
| 54 | -import com.sap.sailing.domain.common.RankingMetrics;
|
|
| 55 | -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
|
| 56 | -import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
|
| 57 | -import com.sap.sailing.domain.common.ScoringSchemeType;
|
|
| 58 | -import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
|
| 59 | -import com.sap.sailing.domain.leaderboard.EventResolver;
|
|
| 60 | -import com.sap.sailing.domain.leaderboard.Leaderboard;
|
|
| 61 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
|
| 62 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver;
|
|
| 63 | -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
|
| 64 | -import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
|
| 65 | -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
|
| 66 | -import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
|
| 67 | -import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
|
| 68 | -import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
|
| 69 | -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
|
| 70 | -import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
|
| 71 | -import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
|
| 72 | -import com.sap.sailing.domain.persistence.PersistenceFactory;
|
|
| 73 | -import com.sap.sailing.domain.persistence.impl.CollectionNames;
|
|
| 74 | -import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
|
| 75 | -import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
|
|
| 76 | -import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
|
| 77 | -import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
|
| 78 | -import com.sap.sailing.domain.ranking.TimeOnTimeAndDistanceRankingMetric;
|
|
| 79 | -import com.sap.sailing.domain.test.AbstractLeaderboardTest;
|
|
| 80 | -import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithFixedRank;
|
|
| 81 | -import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
|
| 82 | -import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
|
| 83 | -import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
|
| 84 | -import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
|
| 85 | -import com.sap.sailing.server.RacingEventService;
|
|
| 86 | -import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
|
| 87 | -import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
|
| 88 | -import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardMaxPointsReason;
|
|
| 89 | -import com.sap.sse.common.Color;
|
|
| 90 | -import com.sap.sse.common.TimePoint;
|
|
| 91 | -import com.sap.sse.common.Util;
|
|
| 92 | -import com.sap.sse.common.impl.MillisecondsTimePoint;
|
|
| 93 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 94 | -import com.sap.sse.common.media.ImageDescriptorImpl;
|
|
| 95 | -import com.sap.sse.common.media.MediaTagConstants;
|
|
| 96 | -import com.sap.sse.common.media.MimeType;
|
|
| 97 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 98 | -import com.sap.sse.common.media.VideoDescriptorImpl;
|
|
| 99 | -
|
|
| 100 | -public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest {
|
|
| 101 | - private static final Logger logger = Logger.getLogger(TestStoringAndLoadingEventsAndRegattas.class.getName());
|
|
| 102 | -
|
|
| 103 | - private final TimePoint eventStartDate;
|
|
| 104 | - private final TimePoint eventEndDate;
|
|
| 105 | - private final TimePoint regattaStartDate;
|
|
| 106 | - private final TimePoint regattaEndDate;
|
|
| 107 | -
|
|
| 108 | - public TestStoringAndLoadingEventsAndRegattas() throws UnknownHostException, MongoException {
|
|
| 109 | - super();
|
|
| 110 | -
|
|
| 111 | - Calendar cal = Calendar.getInstance();
|
|
| 112 | -
|
|
| 113 | - cal.set(2012, 12, 1);
|
|
| 114 | - eventStartDate = new MillisecondsTimePoint(cal.getTimeInMillis());
|
|
| 115 | - cal.set(2012, 12, 5);
|
|
| 116 | - eventEndDate = new MillisecondsTimePoint(cal.getTimeInMillis());
|
|
| 117 | -
|
|
| 118 | - cal.set(2012, 12, 2);
|
|
| 119 | - regattaStartDate = new MillisecondsTimePoint(cal.getTimeInMillis());
|
|
| 120 | - cal.set(2012, 12, 3);
|
|
| 121 | - regattaEndDate = new MillisecondsTimePoint(cal.getTimeInMillis());
|
|
| 122 | - }
|
|
| 123 | -
|
|
| 124 | - private LeaderboardGroup createLeaderboardGroup(String name) {
|
|
| 125 | - return new LeaderboardGroupImpl(name, "Description for "+name, /* displayName */ null, /* displayInReverseOrder */ false, Collections.<Leaderboard>emptyList());
|
|
| 126 | - }
|
|
| 127 | -
|
|
| 128 | - @Test
|
|
| 129 | - public void testLoadStoreSimpleEventWithLinkToLeaderboardGroups() throws MalformedURLException {
|
|
| 130 | - final String eventName = "Event Name";
|
|
| 131 | - final String eventDescription = "Event Description";
|
|
| 132 | - final String venueName = "Venue Name";
|
|
| 133 | - final String[] courseAreaNames = new String[] { "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrott" };
|
|
| 134 | - final URL officialWebsiteURL = new URL("http://official.website.com");
|
|
| 135 | - final URL sailorsInfoWebsiteURL = new URL("http://sailorsinfo.website.com");
|
|
| 136 | - final Venue venue = new VenueImpl(venueName);
|
|
| 137 | -
|
|
| 138 | - for (String courseAreaName : courseAreaNames) {
|
|
| 139 | - CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
|
|
| 140 | - venue.addCourseArea(courseArea);
|
|
| 141 | - }
|
|
| 142 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 143 | - final Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
|
|
| 144 | - final LeaderboardGroup lg1 = createLeaderboardGroup("lg1");
|
|
| 145 | - final LeaderboardGroup lg2 = createLeaderboardGroup("lg2");
|
|
| 146 | - event.addLeaderboardGroup(lg1);
|
|
| 147 | - event.addLeaderboardGroup(lg2);
|
|
| 148 | - event.setDescription(eventDescription);
|
|
| 149 | - event.setOfficialWebsiteURL(officialWebsiteURL);
|
|
| 150 | - event.setSailorsInfoWebsiteURL(sailorsInfoWebsiteURL);
|
|
| 151 | - mof.storeEvent(event);
|
|
| 152 | -
|
|
| 153 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 154 | - final Event loadedEvent = dof.loadEvent(eventName);
|
|
| 155 | - dof.loadLeaderboardGroupLinksForEvents(new EventResolver() {
|
|
| 156 | - @Override
|
|
| 157 | - public Event getEvent(Serializable id) {
|
|
| 158 | - return id.equals(loadedEvent.getId()) ? loadedEvent : null;
|
|
| 159 | - }
|
|
| 160 | - }, new LeaderboardGroupResolver() {
|
|
| 161 | - @Override
|
|
| 162 | - public LeaderboardGroup getLeaderboardGroupByName(String leaderboardGroupName) {
|
|
| 163 | - return leaderboardGroupName.equals(lg1.getName()) ? lg1 : leaderboardGroupName.equals(lg2.getName()) ? lg2 : null;
|
|
| 164 | - }
|
|
| 165 | -
|
|
| 166 | - @Override
|
|
| 167 | - public LeaderboardGroup getLeaderboardGroupByID(UUID leaderboardGroupID) {
|
|
| 168 | - return leaderboardGroupID.equals(lg1.getId()) ? lg1 : leaderboardGroupID.equals(lg2.getId()) ? lg2 : null;
|
|
| 169 | - }
|
|
| 170 | - });
|
|
| 171 | - assertNotNull(loadedEvent);
|
|
| 172 | - assertEquals(eventName, loadedEvent.getName());
|
|
| 173 | - assertEquals(eventDescription, loadedEvent.getDescription());
|
|
| 174 | - assertEquals(event.getOfficialWebsiteURL(), loadedEvent.getOfficialWebsiteURL());
|
|
| 175 | - assertEquals(event.getSailorsInfoWebsiteURL(), loadedEvent.getSailorsInfoWebsiteURL());
|
|
| 176 | - assertEquals(2, Util.size(loadedEvent.getLeaderboardGroups()));
|
|
| 177 | - Iterator<LeaderboardGroup> lgIter = loadedEvent.getLeaderboardGroups().iterator();
|
|
| 178 | - assertSame(lg1, lgIter.next());
|
|
| 179 | - assertSame(lg2, lgIter.next());
|
|
| 180 | - final Venue loadedVenue = loadedEvent.getVenue();
|
|
| 181 | - assertNotNull(loadedVenue);
|
|
| 182 | - assertEquals(venueName, loadedVenue.getName());
|
|
| 183 | - assertEquals(courseAreaNames.length, Util.size(loadedVenue.getCourseAreas()));
|
|
| 184 | - int i=0;
|
|
| 185 | - for (CourseArea loadedCourseArea : loadedVenue.getCourseAreas()) {
|
|
| 186 | - assertEquals(courseAreaNames[i++], loadedCourseArea.getName());
|
|
| 187 | - }
|
|
| 188 | - }
|
|
| 189 | -
|
|
| 190 | - @Test
|
|
| 191 | - public void testLoadStoreSimpleEventAndRegattaWithCourseArea() {
|
|
| 192 | - final String eventName = "Event Name";
|
|
| 193 | - final String venueName = "Venue Name";
|
|
| 194 | - final String courseAreaName = "Alpha";
|
|
| 195 | - final Venue venue = new VenueImpl(venueName);
|
|
| 196 | - CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
|
|
| 197 | - venue.addCourseArea(courseArea);
|
|
| 198 | -
|
|
| 199 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 200 | - Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
|
|
| 201 | - mof.storeEvent(event);
|
|
| 202 | -
|
|
| 203 | - final String regattaBaseName = "Kieler Woche";
|
|
| 204 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 205 | - Regatta regatta = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
|
|
| 206 | - regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), courseArea, OneDesignRankingMetric::new);
|
|
| 207 | - mof.storeRegatta(regatta);
|
|
| 208 | -
|
|
| 209 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 210 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 211 | - assertNotNull(loadedRegatta);
|
|
| 212 | - assertEquals(regatta.getName(), loadedRegatta.getName());
|
|
| 213 | - assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries()));
|
|
| 214 | - assertNotNull(loadedRegatta.getDefaultCourseArea());
|
|
| 215 | - assertEquals(loadedRegatta.getDefaultCourseArea().getId(), courseArea.getId());
|
|
| 216 | - assertEquals(loadedRegatta.getDefaultCourseArea().getName(), courseArea.getName());
|
|
| 217 | - assertEquals(loadedRegatta.getStartDate(), regattaStartDate);
|
|
| 218 | - assertEquals(loadedRegatta.getEndDate(), regattaEndDate);
|
|
| 219 | - }
|
|
| 220 | -
|
|
| 221 | - @Test
|
|
| 222 | - public void testLoadStoreSimpleEventWithImages() throws MalformedURLException {
|
|
| 223 | - final URL imageURL = new URL("http://some.host/with/some/file2.jpg");
|
|
| 224 | - final String copyright = "copyright by Alex";
|
|
| 225 | - final String imageTitle = "My image title";
|
|
| 226 | - final String imageSubtitle = "My image subtitle";
|
|
| 227 | - final Integer imageWidth = 500;
|
|
| 228 | - final Integer imageHeight = 300;
|
|
| 229 | - final TimePoint createdAt = MillisecondsTimePoint.now();
|
|
| 230 | - final String eventName = "Event Name";
|
|
| 231 | - final String venueName = "Venue Name";
|
|
| 232 | - final String courseAreaName = "Alpha";
|
|
| 233 | - final Venue venue = new VenueImpl(venueName);
|
|
| 234 | - CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
|
|
| 235 | - venue.addCourseArea(courseArea);
|
|
| 236 | -
|
|
| 237 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 238 | - Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
|
|
| 239 | -
|
|
| 240 | - ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt);
|
|
| 241 | - image1.setCopyright(copyright);
|
|
| 242 | - image1.setSize(imageWidth, imageHeight);
|
|
| 243 | - image1.setTitle(imageTitle);
|
|
| 244 | - image1.setSubtitle(imageSubtitle);
|
|
| 245 | - image1.addTag("Tag1");
|
|
| 246 | - image1.addTag("Tag2");
|
|
| 247 | - image1.addTag("Tag3");
|
|
| 248 | - event.addImage(image1);
|
|
| 249 | -
|
|
| 250 | - ImageDescriptor image2 = new ImageDescriptorImpl(new URL("http://some.host/with/some/file2.jpg"), MillisecondsTimePoint.now());
|
|
| 251 | - image2.setCopyright("copyright");
|
|
| 252 | - event.addImage(image2);
|
|
| 253 | -
|
|
| 254 | - mof.storeEvent(event);
|
|
| 255 | -
|
|
| 256 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 257 | - final Event loadedEvent = dof.loadEvent(eventName);
|
|
| 258 | - assertEquals(2, Util.size(loadedEvent.getImages()));
|
|
| 259 | - ImageDescriptor loadedImage1 = loadedEvent.getImages().iterator().next();
|
|
| 260 | - assertNotNull(loadedImage1);
|
|
| 261 | - assertEquals(imageURL, loadedImage1.getURL());
|
|
| 262 | - assertEquals(copyright, loadedImage1.getCopyright());
|
|
| 263 | - assertEquals(copyright, loadedImage1.getCopyright());
|
|
| 264 | - assertEquals(imageTitle, loadedImage1.getTitle());
|
|
| 265 | - assertEquals(imageSubtitle, loadedImage1.getSubtitle());
|
|
| 266 | - assertEquals(createdAt, loadedImage1.getCreatedAtDate());
|
|
| 267 | - assertEquals(imageWidth, loadedImage1.getWidthInPx());
|
|
| 268 | - assertEquals(imageHeight, loadedImage1.getHeightInPx());
|
|
| 269 | - assertEquals(3, Util.size(loadedImage1.getTags()));
|
|
| 270 | - }
|
|
| 271 | -
|
|
| 272 | - @Test
|
|
| 273 | - public void testLoadStoreSimpleEventWithVideos() throws MalformedURLException {
|
|
| 274 | - final URL videoURL = new URL("http://some.host/with/some/video.mpg");
|
|
| 275 | - final URL videoThumbnailURL = new URL("http://some.host/with/some/video_thumbnail.jpg");
|
|
| 276 | - final Locale locale = Locale.GERMAN;
|
|
| 277 | - final Integer videoLengthInSeconds = 2 * 60 * 60 * 1000; // 2h
|
|
| 278 | - final MimeType mimeType = MimeType.mp4;
|
|
| 279 | - final String copyright = "copyright by Don";
|
|
| 280 | - final String videoTitle = "My video title";
|
|
| 281 | - final String videoSubtitle = "My video subtitle";
|
|
| 282 | - final TimePoint createdAt = MillisecondsTimePoint.now();
|
|
| 283 | - final String eventName = "Event Name";
|
|
| 284 | - final String venueName = "Venue Name";
|
|
| 285 | - final String courseAreaName = "Alpha";
|
|
| 286 | - final Venue venue = new VenueImpl(venueName);
|
|
| 287 | - CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName);
|
|
| 288 | - venue.addCourseArea(courseArea);
|
|
| 289 | -
|
|
| 290 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 291 | - Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
|
|
| 292 | -
|
|
| 293 | - VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, mimeType, createdAt);
|
|
| 294 | - video1.setCopyright(copyright);
|
|
| 295 | - video1.setTitle(videoTitle);
|
|
| 296 | - video1.setLocale(locale);
|
|
| 297 | - video1.setSubtitle(videoSubtitle);
|
|
| 298 | - video1.setThumbnailURL(videoThumbnailURL);
|
|
| 299 | - video1.setLengthInSeconds(videoLengthInSeconds);
|
|
| 300 | - video1.addTag("Tag1");
|
|
| 301 | - video1.addTag("Tag2");
|
|
| 302 | - video1.addTag("Tag3");
|
|
| 303 | - event.addVideo(video1);
|
|
| 304 | -
|
|
| 305 | - VideoDescriptor video2 = new VideoDescriptorImpl(new URL("http://some.host/with/some/file2.ogg"), MimeType.ogg, MillisecondsTimePoint.now());
|
|
| 306 | - video2.setCopyright("copyright");
|
|
| 307 | - event.addVideo(video2);
|
|
| 308 | -
|
|
| 309 | - mof.storeEvent(event);
|
|
| 310 | -
|
|
| 311 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 312 | - final Event loadedEvent = dof.loadEvent(eventName);
|
|
| 313 | - assertEquals(2, Util.size(loadedEvent.getVideos()));
|
|
| 314 | - VideoDescriptor loadedVideo1 = loadedEvent.getVideos().iterator().next();
|
|
| 315 | - assertNotNull(loadedVideo1);
|
|
| 316 | - assertEquals(videoURL, loadedVideo1.getURL());
|
|
| 317 | - assertEquals(videoThumbnailURL, loadedVideo1.getThumbnailURL());
|
|
| 318 | - assertEquals(videoLengthInSeconds, loadedVideo1.getLengthInSeconds());
|
|
| 319 | - assertEquals(copyright, loadedVideo1.getCopyright());
|
|
| 320 | - assertEquals(locale, loadedVideo1.getLocale());
|
|
| 321 | - assertEquals(videoTitle, loadedVideo1.getTitle());
|
|
| 322 | - assertEquals(videoSubtitle, loadedVideo1.getSubtitle());
|
|
| 323 | - assertEquals(createdAt, loadedVideo1.getCreatedAtDate());
|
|
| 324 | - assertEquals(3, Util.size(loadedVideo1.getTags()));
|
|
| 325 | - }
|
|
| 326 | -
|
|
| 327 | - @SuppressWarnings("deprecation")
|
|
| 328 | - @Test
|
|
| 329 | - /**
|
|
| 330 | - * We expected that the migration code creates also an image URL for each image we create.
|
|
| 331 | - * Images with the 'Sponsor' tag should create a corresponding sponsor image URL
|
|
| 332 | - * Videos should create a video URL.
|
|
| 333 | - */
|
|
| 334 | - public void testLoadStoreSimpleEventWithImageAndVideoURLMigration() throws MalformedURLException {
|
|
| 335 | - final URL imageURL = new URL("http://some.host/with/some/bla.jpg");
|
|
| 336 | - final URL sponsorImageURL = new URL("http://some.host/with/some/sponsor.jpg");
|
|
| 337 | - final URL videoURL = new URL("http://some.host/with/some/video.mpg");
|
|
| 338 | - final TimePoint createdAt = MillisecondsTimePoint.now();
|
|
| 339 | - final String eventName = "Event Name";
|
|
| 340 | - final Venue venue = new VenueImpl("My Venue");
|
|
| 341 | - CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), "Alfa");
|
|
| 342 | - venue.addCourseArea(courseArea);
|
|
| 343 | -
|
|
| 344 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 345 | - Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID());
|
|
| 346 | -
|
|
| 347 | - ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt);
|
|
| 348 | - image1.addTag(MediaTagConstants.GALLERY);
|
|
| 349 | - event.addImage(image1);
|
|
| 350 | -
|
|
| 351 | - ImageDescriptor image2 = new ImageDescriptorImpl(sponsorImageURL, createdAt);
|
|
| 352 | - event.addImage(image2);
|
|
| 353 | - image2.addTag(MediaTagConstants.SPONSOR);
|
|
| 354 | -
|
|
| 355 | - VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, MimeType.mp4, createdAt);
|
|
| 356 | - event.addVideo(video1);
|
|
| 357 | -
|
|
| 358 | - mof.storeEvent(event);
|
|
| 359 | -
|
|
| 360 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 361 | - final Event loadedEvent = dof.loadEvent(eventName);
|
|
| 362 | - assertEquals(2, Util.size(loadedEvent.getImages()));
|
|
| 363 | - assertEquals(1, Util.size(loadedEvent.getVideos()));
|
|
| 364 | - assertEquals(1, Util.size(loadedEvent.getImageURLs()));
|
|
| 365 | - assertEquals(1, Util.size(loadedEvent.getSponsorImageURLs()));
|
|
| 366 | - assertEquals(1, Util.size(loadedEvent.getVideoURLs()));
|
|
| 367 | - }
|
|
| 368 | -
|
|
| 369 | -
|
|
| 370 | - @Test
|
|
| 371 | - public void testLoadStoreRegattaConfiguration() {
|
|
| 372 | -
|
|
| 373 | - RegattaConfigurationImpl configuration = new RegattaConfigurationImpl();
|
|
| 374 | - configuration.setDefaultRacingProcedureType(RacingProcedureType.BASIC);
|
|
| 375 | -
|
|
| 376 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("ESS40", false);
|
|
| 377 | - Regatta regatta = createRegattaAndAddRaceColumns(1, 1, RegattaImpl.getDefaultName("RR", boatClass.getName()), boatClass,
|
|
| 378 | - regattaStartDate, regattaEndDate, false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT), OneDesignRankingMetric::new);
|
|
| 379 | - regatta.setRegattaConfiguration(configuration);
|
|
| 380 | -
|
|
| 381 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 382 | - mof.storeRegatta(regatta);
|
|
| 383 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 384 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), null);
|
|
| 385 | -
|
|
| 386 | - assertNotNull(loadedRegatta.getRegattaConfiguration());
|
|
| 387 | - assertEquals(RacingProcedureType.BASIC, loadedRegatta.getRegattaConfiguration().getDefaultRacingProcedureType());
|
|
| 388 | - }
|
|
| 389 | -
|
|
| 390 | - @Test
|
|
| 391 | - public void testLoadStoreSimpleRegattaLeaderboard() {
|
|
| 392 | - RacingEventService res = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
|
|
| 393 | - .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE);
|
|
| 394 | - final int numberOfQualifyingRaces = 5;
|
|
| 395 | - final int numberOfFinalRaces = 7;
|
|
| 396 | - final String regattaBaseName = "Kieler Woche";
|
|
| 397 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 398 | - Regatta regattaProxy = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
|
|
| 399 | - regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new);
|
|
| 400 | - final String regattaName = regattaProxy.getName();
|
|
| 401 | - Regatta regatta = res.createRegatta(regattaName, regattaProxy.getBoatClass().getName(), regattaStartDate, regattaEndDate,
|
|
| 402 | - "123", regattaProxy.getSeries(), regattaProxy.isPersistent(), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, /* useStartTimeInference */ true, OneDesignRankingMetric::new);
|
|
| 403 | - addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
|
|
| 404 | - res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), null, new int[] { 3, 5 });
|
|
| 405 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 406 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 407 | - assertNotNull(loadedRegatta);
|
|
| 408 | - assertEquals(regatta.getName(), loadedRegatta.getName());
|
|
| 409 | - assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries()));
|
|
| 410 | -
|
|
| 411 | - Leaderboard loadedLeaderboard = dof.loadLeaderboard(regatta.getName(), res);
|
|
| 412 | - assertNotNull(loadedLeaderboard);
|
|
| 413 | - assertTrue(loadedLeaderboard instanceof RegattaLeaderboard);
|
|
| 414 | - RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard;
|
|
| 415 | - assertSame(regatta, loadedRegattaLeaderboard.getRegatta());
|
|
| 416 | - }
|
|
| 417 | -
|
|
| 418 | - @Test
|
|
| 419 | - public void testLoadStoreRegattaLeaderboardWithScoreCorrections() {
|
|
| 420 | - // for some reason the dropping of collections doesn't work reliably on Linux... explicitly drop those collections that we depend on
|
|
| 421 | - getMongoService().getDB().getCollection(CollectionNames.LEADERBOARDS.name()).drop();
|
|
| 422 | - getMongoService().getDB().getCollection(CollectionNames.REGATTAS.name()).drop();
|
|
| 423 | - Competitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner");
|
|
| 424 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 425 | - final DynamicTrackedRegatta[] trackedRegatta = new DynamicTrackedRegatta[1];
|
|
| 426 | - final DynamicTrackedRace q2YellowTrackedRace = new MockedTrackedRaceWithFixedRank(hasso, /* rank */ 1, /* started */ false, boatClass) {
|
|
| 427 | - private static final long serialVersionUID = 1234L;
|
|
| 428 | - @Override
|
|
| 429 | - public RegattaAndRaceIdentifier getRaceIdentifier() {
|
|
| 430 | - return new RegattaNameAndRaceName("Kieler Woche (29ERXX)", "Yellow Race 2");
|
|
| 431 | - }
|
|
| 432 | - @Override
|
|
| 433 | - public DynamicTrackedRegatta getTrackedRegatta() {
|
|
| 434 | - return trackedRegatta[0];
|
|
| 435 | - }
|
|
| 436 | - };
|
|
| 437 | - RacingEventService res = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace);
|
|
| 438 | - final int numberOfQualifyingRaces = 5;
|
|
| 439 | - final int numberOfFinalRaces = 7;
|
|
| 440 | - final String regattaBaseName = "Kieler Woche";
|
|
| 441 | -
|
|
| 442 | - Regatta regattaProxy = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new);
|
|
| 443 | - Regatta regatta = res.createRegatta(regattaProxy.getName(), regattaProxy.getBoatClass().getName(), regattaProxy.getStartDate(), regattaProxy.getEndDate(),
|
|
| 444 | - "123", regattaProxy.getSeries(), regattaProxy.isPersistent(), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, /* useStartTimeInference */ true, OneDesignRankingMetric::new);
|
|
| 445 | - trackedRegatta[0] = new DynamicTrackedRegattaImpl(regatta);
|
|
| 446 | - addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
|
|
| 447 | - logColumnsInRegatta(regatta);
|
|
| 448 | - RegattaLeaderboard regattaLeaderboard = res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), null, new int[] { 3, 5 });
|
|
| 449 | - assertSame(regatta, regattaLeaderboard.getRegatta());
|
|
| 450 | - final RaceColumnInSeries q2 = regatta.getSeriesByName("Qualifying").getRaceColumnByName("Q2");
|
|
| 451 | - final Fleet yellow = q2.getFleetByName("Yellow");
|
|
| 452 | - logColumnsInRegatta(regatta);
|
|
| 453 | - logColumnsInRegattaLeaderboard(regattaLeaderboard);
|
|
| 454 | - assertNotNull(regattaLeaderboard.getRaceColumnByName(q2.getName()));
|
|
| 455 | - res.apply(new ConnectTrackedRaceToLeaderboardColumn(regattaLeaderboard.getName(), q2.getName(), yellow
|
|
| 456 | - .getName(), q2YellowTrackedRace.getRaceIdentifier()));
|
|
| 457 | - res.apply(new UpdateLeaderboardMaxPointsReason(regattaLeaderboard.getName(), q2.getName(), hasso.getId().toString(),
|
|
| 458 | - MaxPointsReason.DNF, MillisecondsTimePoint.now()));
|
|
| 459 | -
|
|
| 460 | - // load new RacingEventService including regatta and leaderboard
|
|
| 461 | - RacingEventService resForLoading = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace);
|
|
| 462 | - Regatta loadedRegatta = resForLoading.getRegattaByName("Kieler Woche (29ERXX)");
|
|
| 463 | - assertNotNull(loadedRegatta);
|
|
| 464 | - assertEquals(regatta.getName(), loadedRegatta.getName());
|
|
| 465 | - assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries()));
|
|
| 466 | - Leaderboard loadedLeaderboard = resForLoading.getLeaderboardByName(loadedRegatta.getName());
|
|
| 467 | - assertNotNull(loadedLeaderboard);
|
|
| 468 | - assertEquals(((ThresholdBasedResultDiscardingRule) regattaLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces().length,
|
|
| 469 | - ((ThresholdBasedResultDiscardingRule) loadedLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces().length);
|
|
| 470 | - assertTrue(Arrays.equals(((ThresholdBasedResultDiscardingRule) regattaLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces(),
|
|
| 471 | - ((ThresholdBasedResultDiscardingRule) loadedLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces()));
|
|
| 472 | - assertTrue(loadedLeaderboard instanceof RegattaLeaderboard);
|
|
| 473 | - RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard;
|
|
| 474 | - assertSame(loadedRegatta, loadedRegattaLeaderboard.getRegatta());
|
|
| 475 | - // now re-associate the tracked race to let score correction "snap" to competitor:
|
|
| 476 | - final RaceColumnInSeries loadedQ2 = loadedRegatta.getSeriesByName("Qualifying").getRaceColumnByName("Q2");
|
|
| 477 | - final Fleet loadedYellow = loadedQ2.getFleetByName("Yellow");
|
|
| 478 | - // adjust tracked regatta for tracked race:
|
|
| 479 | - trackedRegatta[0] = new DynamicTrackedRegattaImpl(loadedRegatta);
|
|
| 480 | - resForLoading.apply(new ConnectTrackedRaceToLeaderboardColumn(loadedLeaderboard.getName(), loadedQ2.getName(), loadedYellow
|
|
| 481 | - .getName(), q2YellowTrackedRace.getRaceIdentifier()));
|
|
| 482 | - MaxPointsReason hassosLoadedMaxPointsReason = loadedLeaderboard.getScoreCorrection().getMaxPointsReason(hasso, loadedQ2, MillisecondsTimePoint.now());
|
|
| 483 | - assertEquals(MaxPointsReason.DNF, hassosLoadedMaxPointsReason);
|
|
| 484 | - }
|
|
| 485 | -
|
|
| 486 | - private void logColumnsInRegattaLeaderboard(RegattaLeaderboard regattaLeaderboard) {
|
|
| 487 | - StringBuilder rlbrcNames = new StringBuilder();
|
|
| 488 | - for (RaceColumn rlbrc : regattaLeaderboard.getRaceColumns()) {
|
|
| 489 | - rlbrcNames.append("; ");
|
|
| 490 | - rlbrcNames.append(rlbrc.getName());
|
|
| 491 | - }
|
|
| 492 | - logger.info("columns in regatta leaderboard for regatta "+regattaLeaderboard.getRegatta().getName()+" ("+
|
|
| 493 | - regattaLeaderboard.getRegatta().hashCode()+"): "+rlbrcNames);
|
|
| 494 | - logColumnsInRegatta(regattaLeaderboard.getRegatta());
|
|
| 495 | - }
|
|
| 496 | -
|
|
| 497 | - private void logColumnsInRegatta(Regatta regatta) {
|
|
| 498 | - StringBuilder rrcNames = new StringBuilder();
|
|
| 499 | - for (Series series : regatta.getSeries()) {
|
|
| 500 | - for (RaceColumn raceColumn : series.getRaceColumns()) {
|
|
| 501 | - rrcNames.append("; ");
|
|
| 502 | - rrcNames.append(raceColumn.getName());
|
|
| 503 | - }
|
|
| 504 | - }
|
|
| 505 | - logger.info("columns in regatta "+regatta.getName()+" ("+regatta.hashCode()+") : "+rrcNames);
|
|
| 506 | - }
|
|
| 507 | -
|
|
| 508 | - private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace) {
|
|
| 509 | - return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
|
|
| 510 | - .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE) {
|
|
| 511 | - @Override
|
|
| 512 | - public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
|
|
| 513 | - return q2YellowTrackedRace;
|
|
| 514 | - }
|
|
| 515 | - };
|
|
| 516 | - }
|
|
| 517 | -
|
|
| 518 | - @Test
|
|
| 519 | - public void testLoadStoreSimpleRegatta() {
|
|
| 520 | - final int numberOfQualifyingRaces = 5;
|
|
| 521 | - final int numberOfFinalRaces = 7;
|
|
| 522 | - final String regattaBaseName = "Kieler Woche";
|
|
| 523 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true);
|
|
| 524 | - final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName());
|
|
| 525 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName,
|
|
| 526 | - boatClass, regattaStartDate, regattaEndDate, /* persistent */false,
|
|
| 527 | - DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 528 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 529 | - mof.storeRegatta(regatta);
|
|
| 530 | -
|
|
| 531 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 532 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 533 | - assertSame(LowPoint.class, loadedRegatta.getScoringScheme().getClass());
|
|
| 534 | - assertEquals(regattaName, loadedRegatta.getName());
|
|
| 535 | - Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator();
|
|
| 536 | - Series loadedQualifyingSeries = seriesIter.next();
|
|
| 537 | - assertEquals(numberOfQualifyingRaces, Util.size(loadedQualifyingSeries.getRaceColumns()));
|
|
| 538 | - assertEquals(0, loadedQualifyingSeries.getFleetByName("Yellow").compareTo(loadedQualifyingSeries.getFleetByName("Blue")));
|
|
| 539 | - Series loadedFinalSeries = seriesIter.next();
|
|
| 540 | - assertEquals(numberOfFinalRaces, Util.size(loadedFinalSeries.getRaceColumns()));
|
|
| 541 | - assertTrue(loadedFinalSeries.getFleetByName("Silver").compareTo(loadedFinalSeries.getFleetByName("Gold")) > 0);
|
|
| 542 | - Series loadedMedalSeries = seriesIter.next();
|
|
| 543 | - assertEquals(1, Util.size(loadedMedalSeries.getRaceColumns()));
|
|
| 544 | - assertEquals(loadedRegatta.getStartDate(), regattaStartDate);
|
|
| 545 | - assertEquals(loadedRegatta.getEndDate(), regattaEndDate);
|
|
| 546 | - assertEquals(RankingMetrics.ONE_DESIGN, loadedRegatta.getRankingMetricType());
|
|
| 547 | - }
|
|
| 548 | -
|
|
| 549 | - @Test
|
|
| 550 | - public void testLoadStoreRegattaWithHandicapRanking() {
|
|
| 551 | - final int numberOfQualifyingRaces = 5;
|
|
| 552 | - final int numberOfFinalRaces = 7;
|
|
| 553 | - final String regattaBaseName = "Kieler Woche";
|
|
| 554 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true);
|
|
| 555 | - final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName());
|
|
| 556 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName,
|
|
| 557 | - boatClass, regattaStartDate, regattaEndDate, /* persistent */false,
|
|
| 558 | - DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), TimeOnTimeAndDistanceRankingMetric::new);
|
|
| 559 | - assertEquals(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, regatta.getRankingMetricType());
|
|
| 560 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 561 | - mof.storeRegatta(regatta);
|
|
| 562 | -
|
|
| 563 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 564 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 565 | - assertSame(LowPoint.class, loadedRegatta.getScoringScheme().getClass());
|
|
| 566 | - assertEquals(regattaName, loadedRegatta.getName());
|
|
| 567 | - Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator();
|
|
| 568 | - Series loadedQualifyingSeries = seriesIter.next();
|
|
| 569 | - assertEquals(numberOfQualifyingRaces, Util.size(loadedQualifyingSeries.getRaceColumns()));
|
|
| 570 | - assertEquals(0, loadedQualifyingSeries.getFleetByName("Yellow").compareTo(loadedQualifyingSeries.getFleetByName("Blue")));
|
|
| 571 | - Series loadedFinalSeries = seriesIter.next();
|
|
| 572 | - assertEquals(numberOfFinalRaces, Util.size(loadedFinalSeries.getRaceColumns()));
|
|
| 573 | - assertTrue(loadedFinalSeries.getFleetByName("Silver").compareTo(loadedFinalSeries.getFleetByName("Gold")) > 0);
|
|
| 574 | - Series loadedMedalSeries = seriesIter.next();
|
|
| 575 | - assertEquals(1, Util.size(loadedMedalSeries.getRaceColumns()));
|
|
| 576 | - assertEquals(loadedRegatta.getStartDate(), regattaStartDate);
|
|
| 577 | - assertEquals(loadedRegatta.getEndDate(), regattaEndDate);
|
|
| 578 | - assertEquals(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, loadedRegatta.getRankingMetricType());
|
|
| 579 | - }
|
|
| 580 | -
|
|
| 581 | - @Test
|
|
| 582 | - public void testLoadStoreSimpleRegattaWithEmptyStartAndEndDate() {
|
|
| 583 | - final int numberOfQualifyingRaces = 1;
|
|
| 584 | - final int numberOfFinalRaces = 1;
|
|
| 585 | - final String regattaBaseName = "Kieler Woche";
|
|
| 586 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true);
|
|
| 587 | - final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName());
|
|
| 588 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName,
|
|
| 589 | - boatClass, null, null, /* persistent */false,
|
|
| 590 | - DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 591 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 592 | - mof.storeRegatta(regatta);
|
|
| 593 | -
|
|
| 594 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 595 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 596 | - assertEquals(regattaName, loadedRegatta.getName());
|
|
| 597 | - assertEquals(loadedRegatta.getStartDate(), null);
|
|
| 598 | - assertEquals(loadedRegatta.getEndDate(), null);
|
|
| 599 | - }
|
|
| 600 | -
|
|
| 601 | - @Test
|
|
| 602 | - public void testLoadStoreSimpleRegattaWithSeriesScoringScheme() {
|
|
| 603 | - final int numberOfQualifyingRaces = 5;
|
|
| 604 | - final int numberOfFinalRaces = 7;
|
|
| 605 | - final String regattaBaseName = "Kieler Woche";
|
|
| 606 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 607 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()),
|
|
| 608 | - boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 609 | - regatta.getSeriesByName("Qualifying").setResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(new int[] { 1, 2, 3 }));
|
|
| 610 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 611 | - mof.storeRegatta(regatta);
|
|
| 612 | -
|
|
| 613 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 614 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 615 | - assertTrue(Arrays.equals(new int[] { 1, 2, 3 },
|
|
| 616 | - loadedRegatta.getSeriesByName("Qualifying").getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces()));
|
|
| 617 | - }
|
|
| 618 | -
|
|
| 619 | - @Test
|
|
| 620 | - public void testLoadStoreSimpleRegattaWithScoreForMedalStartingWithZero() {
|
|
| 621 | - final int numberOfQualifyingRaces = 5;
|
|
| 622 | - final int numberOfFinalRaces = 7;
|
|
| 623 | - final String regattaBaseName = "Kieler Woche";
|
|
| 624 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 625 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()),
|
|
| 626 | - boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 627 | - regatta.getSeriesByName("Medal").setStartsWithZeroScore(true);
|
|
| 628 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 629 | - mof.storeRegatta(regatta);
|
|
| 630 | -
|
|
| 631 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 632 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 633 | - assertFalse(loadedRegatta.getSeriesByName("Qualifying").isStartsWithZeroScore());
|
|
| 634 | - assertTrue(loadedRegatta.getSeriesByName("Medal").isStartsWithZeroScore());
|
|
| 635 | - }
|
|
| 636 | -
|
|
| 637 | - @Test
|
|
| 638 | - public void testLoadStoreSimpleRegattaWithHighPointScoringScheme() {
|
|
| 639 | - final int numberOfQualifyingRaces = 5;
|
|
| 640 | - final int numberOfFinalRaces = 7;
|
|
| 641 | - final String regattaBaseName = "ESS40 Cardiff 2012";
|
|
| 642 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("ESS40", /* typicallyStartsUpwind */ false);
|
|
| 643 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()),
|
|
| 644 | - boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT), OneDesignRankingMetric::new);
|
|
| 645 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 646 | - mof.storeRegatta(regatta);
|
|
| 647 | -
|
|
| 648 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 649 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 650 | - assertSame(HighPoint.class, loadedRegatta.getScoringScheme().getClass());
|
|
| 651 | - }
|
|
| 652 | -
|
|
| 653 | - @Test
|
|
| 654 | - public void testLoadStoreRegattaWithFleetsEnsuringIdenticalFleetsInSeriesAndRaceColumns() {
|
|
| 655 | - final int numberOfQualifyingRaces = 5;
|
|
| 656 | - final int numberOfFinalRaces = 7;
|
|
| 657 | - final String regattaBaseName = "Kieler Woche";
|
|
| 658 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 659 | - final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName());
|
|
| 660 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces,
|
|
| 661 | - regattaName, boatClass, regattaStartDate, regattaEndDate,
|
|
| 662 | - /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 663 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 664 | - mof.storeRegatta(regatta);
|
|
| 665 | -
|
|
| 666 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 667 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 668 | - assertEquals(regattaName, loadedRegatta.getName());
|
|
| 669 | - Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator();
|
|
| 670 | - Series loadedQualifyingSeries = seriesIter.next();
|
|
| 671 | - int i=1;
|
|
| 672 | - for (RaceColumn raceColumn : loadedQualifyingSeries.getRaceColumns()) {
|
|
| 673 | - assertTrue(raceColumn instanceof RaceColumnInSeriesImpl);
|
|
| 674 | - assertEquals("Q"+i, raceColumn.getName());
|
|
| 675 | - assertTrue(Util.equals(loadedQualifyingSeries.getFleets(), raceColumn.getFleets()));
|
|
| 676 | - i++;
|
|
| 677 | - }
|
|
| 678 | - Series loadedFinalSeries = seriesIter.next();
|
|
| 679 | - i=1;
|
|
| 680 | - for (RaceColumn raceColumn : loadedFinalSeries.getRaceColumns()) {
|
|
| 681 | - assertTrue(raceColumn instanceof RaceColumnInSeriesImpl);
|
|
| 682 | - assertEquals("F"+i, raceColumn.getName());
|
|
| 683 | - assertTrue(Util.equals(loadedFinalSeries.getFleets(), raceColumn.getFleets()));
|
|
| 684 | - i++;
|
|
| 685 | - }
|
|
| 686 | - Series loadedMedalSeries = seriesIter.next();
|
|
| 687 | - for (RaceColumn raceColumn : loadedMedalSeries.getRaceColumns()) {
|
|
| 688 | - assertTrue(raceColumn instanceof RaceColumnInSeriesImpl);
|
|
| 689 | - assertEquals("M", raceColumn.getName());
|
|
| 690 | - assertTrue(Util.equals(loadedMedalSeries.getFleets(), raceColumn.getFleets()));
|
|
| 691 | - }
|
|
| 692 | - }
|
|
| 693 | -
|
|
| 694 | - @Test
|
|
| 695 | - public void testLoadStoreRegattaWithFleetsEnsuringFleetOrdering() {
|
|
| 696 | - final String regattaBaseName = "Kieler Woche";
|
|
| 697 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 698 | - final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName());
|
|
| 699 | - Regatta regatta = createRegatta(regattaName, boatClass, regattaStartDate, regattaEndDate,
|
|
| 700 | - /* persistent */ false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new);
|
|
| 701 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 702 | - mof.storeRegatta(regatta);
|
|
| 703 | -
|
|
| 704 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 705 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 706 | - assertEquals(regattaName, loadedRegatta.getName());
|
|
| 707 | -
|
|
| 708 | - Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator();
|
|
| 709 | - Series loadedQualifyingSeries = seriesIter.next();
|
|
| 710 | -
|
|
| 711 | - Iterator<? extends Fleet> qualiFleetIt = loadedQualifyingSeries.getFleets().iterator();
|
|
| 712 | - Fleet qualiFleet1 = qualiFleetIt.next();
|
|
| 713 | - assertEquals(qualiFleet1.getName(), "Yellow");
|
|
| 714 | - Fleet qualiFleet2 = qualiFleetIt.next();
|
|
| 715 | - assertEquals(qualiFleet2.getName(), "Blue");
|
|
| 716 | -
|
|
| 717 | - Series loadedFinalSeries = seriesIter.next();
|
|
| 718 | - Iterator<? extends Fleet> finalFleetIt = loadedFinalSeries.getFleets().iterator();
|
|
| 719 | - Fleet finalFleet1 = finalFleetIt.next();
|
|
| 720 | - assertEquals(finalFleet1.getName(), "Gold");
|
|
| 721 | - Fleet finalFleet2 = finalFleetIt.next();
|
|
| 722 | - assertEquals(finalFleet2.getName(), "Silver");
|
|
| 723 | - }
|
|
| 724 | -
|
|
| 725 | - @Test
|
|
| 726 | - public void testStorageOfRaceIdentifiersOnRaceColumnInSeries() {
|
|
| 727 | - final int numberOfQualifyingRaces = 5;
|
|
| 728 | - final int numberOfFinalRaces = 7;
|
|
| 729 | - final String regattaBaseName = "Kieler Woche";
|
|
| 730 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
|
| 731 | - Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces,
|
|
| 732 | - RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, regattaStartDate, regattaEndDate,
|
|
| 733 | - /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new);
|
|
| 734 | - Series qualifyingSeries = regatta.getSeries().iterator().next();
|
|
| 735 | - RaceColumn q2 = qualifyingSeries.getRaceColumnByName("Q2");
|
|
| 736 | - final RegattaNameAndRaceName q2TrackedRaceIdentifier = new RegattaNameAndRaceName(regatta.getName(), "Q2 TracTrac");
|
|
| 737 | - q2.setRaceIdentifier(qualifyingSeries.getFleetByName("Yellow"), q2TrackedRaceIdentifier);
|
|
| 738 | - MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
|
|
| 739 | - mof.storeRegatta(regatta);
|
|
| 740 | -
|
|
| 741 | - DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
|
|
| 742 | - Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
|
|
| 743 | - Series loadedQualifyingSeries = loadedRegatta.getSeries().iterator().next();
|
|
| 744 | - RaceColumn loadedQ2 = loadedQualifyingSeries.getRaceColumnByName("Q2");
|
|
| 745 | - RaceIdentifier loadedQ2TrackedRaceIdentifier = loadedQ2.getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Yellow"));
|
|
| 746 | - assertEquals(q2TrackedRaceIdentifier, loadedQ2TrackedRaceIdentifier);
|
|
| 747 | - assertNotSame(q2TrackedRaceIdentifier, loadedQ2TrackedRaceIdentifier);
|
|
| 748 | - assertNull(loadedQualifyingSeries.getRaceColumnByName("Q1").getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Yellow")));
|
|
| 749 | - assertNull(loadedQualifyingSeries.getRaceColumnByName("Q2").getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Blue")));
|
|
| 750 | - }
|
|
| 751 | -
|
|
| 752 | - private Regatta createRegattaAndAddRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces,
|
|
| 753 | - final String regattaName, BoatClass boatClass, TimePoint startDate, TimePoint endDate, boolean persistent,
|
|
| 754 | - ScoringScheme scoringScheme, RankingMetricConstructor rankingMetricConstructor) {
|
|
| 755 | - Regatta regatta = createRegatta(regattaName, boatClass, startDate, endDate, persistent, scoringScheme, null,
|
|
| 756 | - rankingMetricConstructor);
|
|
| 757 | - addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
|
|
| 758 | - return regatta;
|
|
| 759 | - }
|
|
| 760 | -
|
|
| 761 | - private void addRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces, Regatta regatta) {
|
|
| 762 | - List<String> finalRaceColumnNames = new ArrayList<String>();
|
|
| 763 | - for (int i=1; i<=numberOfFinalRaces; i++) {
|
|
| 764 | - finalRaceColumnNames.add("F"+i);
|
|
| 765 | - }
|
|
| 766 | - List<String> qualifyingRaceColumnNames = new ArrayList<String>();
|
|
| 767 | - for (int i=1; i<=numberOfQualifyingRaces; i++) {
|
|
| 768 | - qualifyingRaceColumnNames.add("Q"+i);
|
|
| 769 | - }
|
|
| 770 | - List<String> medalRaceColumnNames = new ArrayList<String>();
|
|
| 771 | - medalRaceColumnNames.add("M");
|
|
| 772 | - addRaceColumnsToSeries(qualifyingRaceColumnNames, regatta.getSeriesByName("Qualifying"));
|
|
| 773 | - addRaceColumnsToSeries(finalRaceColumnNames, regatta.getSeriesByName("Final"));
|
|
| 774 | - addRaceColumnsToSeries(medalRaceColumnNames, regatta.getSeriesByName("Medal"));
|
|
| 775 | - }
|
|
| 776 | -
|
|
| 777 | - private Regatta createRegatta(final String regattaName, BoatClass boatClass, TimePoint startDate,
|
|
| 778 | - TimePoint endDate, boolean persistent, ScoringScheme scoringScheme, CourseArea courseArea,
|
|
| 779 | - RankingMetricConstructor rankingMetricConstructor) {
|
|
| 780 | - List<String> emptyRaceColumnNames = Collections.emptyList();
|
|
| 781 | - List<Series> series = new ArrayList<Series>();
|
|
| 782 | -
|
|
| 783 | - // -------- qualifying series ------------
|
|
| 784 | - List<Fleet> qualifyingFleets = new ArrayList<Fleet>();
|
|
| 785 | - qualifyingFleets.add(new FleetImpl("Yellow"));
|
|
| 786 | - qualifyingFleets.add(new FleetImpl("Blue"));
|
|
| 787 | - Series qualifyingSeries = new SeriesImpl("Qualifying", /* isMedal */false, qualifyingFleets,
|
|
| 788 | - emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
|
|
| 789 | - series.add(qualifyingSeries);
|
|
| 790 | -
|
|
| 791 | - // -------- final series ------------
|
|
| 792 | - List<Fleet> finalFleets = new ArrayList<Fleet>();
|
|
| 793 | - finalFleets.add(new FleetImpl("Gold", 1));
|
|
| 794 | - finalFleets.add(new FleetImpl("Silver", 2));
|
|
| 795 | - Series finalSeries = new SeriesImpl("Final", /* isMedal */ false, finalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
|
|
| 796 | - series.add(finalSeries);
|
|
| 797 | -
|
|
| 798 | - // ------------ medal --------------
|
|
| 799 | - List<Fleet> medalFleets = new ArrayList<Fleet>();
|
|
| 800 | - medalFleets.add(new FleetImpl("Medal"));
|
|
| 801 | - Series medalSeries = new SeriesImpl("Medal", /* isMedal */ true, medalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
|
|
| 802 | - series.add(medalSeries);
|
|
| 803 | - Regatta regatta = new RegattaImpl(regattaName, boatClass, startDate, endDate, series, persistent, scoringScheme, "123", courseArea, rankingMetricConstructor);
|
|
| 804 | - return regatta;
|
|
| 805 | - }
|
|
| 806 | -
|
|
| 807 | - private void addRaceColumnsToSeries(List<String> finalRaceColumnNames, Series finalSeries) {
|
|
| 808 | - for (String raceColumnName : finalRaceColumnNames) {
|
|
| 809 | - finalSeries.addRaceColumn(raceColumnName, /* trackedRegattaRegistry */ null);
|
|
| 810 | - }
|
|
| 811 | - }
|
|
| 812 | -
|
|
| 813 | - @Test
|
|
| 814 | - public void testRegattaRaceAssociationStore() throws Exception {
|
|
| 815 | - BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("112er", /* typicallyStartsUpwind */ true);
|
|
| 816 | - Regatta regatta = createRegatta(RegattaImpl.getDefaultName("Cologne Masters", boatClass.getName()), boatClass,
|
|
| 817 | - regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new);
|
|
| 818 | -
|
|
| 819 | - List<Competitor> competitors = new ArrayList<Competitor>();
|
|
| 820 | - competitors.add(new CompetitorImpl("Axel", "Axel Uhl", Color.RED, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null));
|
|
| 821 | - Iterable<Waypoint> waypoints = Collections.emptyList();
|
|
| 822 | - Course course = new CourseImpl("Course", waypoints);
|
|
| 823 | -
|
|
| 824 | - RaceDefinition racedef = new RaceDefinitionImpl("M1", course, boatClass, competitors);
|
|
| 825 | - regatta.addRace(racedef);
|
|
| 826 | -
|
|
| 827 | - RacingEventServiceImpl evs = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
|
|
| 828 | - .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE);
|
|
| 829 | - assertNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
|
| 830 | - evs.raceAdded(regatta, racedef);
|
|
| 831 | - assertNotNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
|
| 832 | - evs.removeRegatta(regatta);
|
|
| 833 | - assertNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
|
| 834 | - }
|
|
| 835 | -
|
|
| 836 | -}
|
|
| 1 | +package com.sap.sailing.mongodb.test; |
|
| 2 | + |
|
| 3 | +import static org.junit.Assert.assertEquals; |
|
| 4 | +import static org.junit.Assert.assertFalse; |
|
| 5 | +import static org.junit.Assert.assertNotNull; |
|
| 6 | +import static org.junit.Assert.assertNotSame; |
|
| 7 | +import static org.junit.Assert.assertNull; |
|
| 8 | +import static org.junit.Assert.assertSame; |
|
| 9 | +import static org.junit.Assert.assertTrue; |
|
| 10 | + |
|
| 11 | +import java.io.Serializable; |
|
| 12 | +import java.net.MalformedURLException; |
|
| 13 | +import java.net.URL; |
|
| 14 | +import java.net.UnknownHostException; |
|
| 15 | +import java.util.ArrayList; |
|
| 16 | +import java.util.Arrays; |
|
| 17 | +import java.util.Calendar; |
|
| 18 | +import java.util.Collections; |
|
| 19 | +import java.util.Iterator; |
|
| 20 | +import java.util.List; |
|
| 21 | +import java.util.Locale; |
|
| 22 | +import java.util.UUID; |
|
| 23 | +import java.util.logging.Logger; |
|
| 24 | + |
|
| 25 | +import org.junit.Test; |
|
| 26 | + |
|
| 27 | +import com.mongodb.MongoException; |
|
| 28 | +import com.sap.sailing.domain.base.BoatClass; |
|
| 29 | +import com.sap.sailing.domain.base.Competitor; |
|
| 30 | +import com.sap.sailing.domain.base.Course; |
|
| 31 | +import com.sap.sailing.domain.base.CourseArea; |
|
| 32 | +import com.sap.sailing.domain.base.DomainFactory; |
|
| 33 | +import com.sap.sailing.domain.base.Event; |
|
| 34 | +import com.sap.sailing.domain.base.Fleet; |
|
| 35 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 36 | +import com.sap.sailing.domain.base.RaceColumnInSeries; |
|
| 37 | +import com.sap.sailing.domain.base.RaceDefinition; |
|
| 38 | +import com.sap.sailing.domain.base.Regatta; |
|
| 39 | +import com.sap.sailing.domain.base.Series; |
|
| 40 | +import com.sap.sailing.domain.base.Venue; |
|
| 41 | +import com.sap.sailing.domain.base.Waypoint; |
|
| 42 | +import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; |
|
| 43 | +import com.sap.sailing.domain.base.impl.CompetitorImpl; |
|
| 44 | +import com.sap.sailing.domain.base.impl.CourseImpl; |
|
| 45 | +import com.sap.sailing.domain.base.impl.EventImpl; |
|
| 46 | +import com.sap.sailing.domain.base.impl.FleetImpl; |
|
| 47 | +import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl; |
|
| 48 | +import com.sap.sailing.domain.base.impl.RaceDefinitionImpl; |
|
| 49 | +import com.sap.sailing.domain.base.impl.RegattaImpl; |
|
| 50 | +import com.sap.sailing.domain.base.impl.SeriesImpl; |
|
| 51 | +import com.sap.sailing.domain.base.impl.VenueImpl; |
|
| 52 | +import com.sap.sailing.domain.common.MaxPointsReason; |
|
| 53 | +import com.sap.sailing.domain.common.RaceIdentifier; |
|
| 54 | +import com.sap.sailing.domain.common.RankingMetrics; |
|
| 55 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 56 | +import com.sap.sailing.domain.common.RegattaNameAndRaceName; |
|
| 57 | +import com.sap.sailing.domain.common.ScoringSchemeType; |
|
| 58 | +import com.sap.sailing.domain.common.racelog.RacingProcedureType; |
|
| 59 | +import com.sap.sailing.domain.leaderboard.EventResolver; |
|
| 60 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 61 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; |
|
| 62 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; |
|
| 63 | +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; |
|
| 64 | +import com.sap.sailing.domain.leaderboard.ScoringScheme; |
|
| 65 | +import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; |
|
| 66 | +import com.sap.sailing.domain.leaderboard.impl.HighPoint; |
|
| 67 | +import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; |
|
| 68 | +import com.sap.sailing.domain.leaderboard.impl.LowPoint; |
|
| 69 | +import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; |
|
| 70 | +import com.sap.sailing.domain.persistence.DomainObjectFactory; |
|
| 71 | +import com.sap.sailing.domain.persistence.MongoObjectFactory; |
|
| 72 | +import com.sap.sailing.domain.persistence.PersistenceFactory; |
|
| 73 | +import com.sap.sailing.domain.persistence.impl.CollectionNames; |
|
| 74 | +import com.sap.sailing.domain.persistence.media.MediaDBFactory; |
|
| 75 | +import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; |
|
| 76 | +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; |
|
| 77 | +import com.sap.sailing.domain.ranking.RankingMetricConstructor; |
|
| 78 | +import com.sap.sailing.domain.ranking.TimeOnTimeAndDistanceRankingMetric; |
|
| 79 | +import com.sap.sailing.domain.test.AbstractLeaderboardTest; |
|
| 80 | +import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithFixedRank; |
|
| 81 | +import com.sap.sailing.domain.tracking.DynamicTrackedRace; |
|
| 82 | +import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; |
|
| 83 | +import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; |
|
| 84 | +import com.sap.sailing.domain.tracking.impl.EmptyWindStore; |
|
| 85 | +import com.sap.sailing.server.RacingEventService; |
|
| 86 | +import com.sap.sailing.server.impl.RacingEventServiceImpl; |
|
| 87 | +import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn; |
|
| 88 | +import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardMaxPointsReason; |
|
| 89 | +import com.sap.sse.common.Color; |
|
| 90 | +import com.sap.sse.common.TimePoint; |
|
| 91 | +import com.sap.sse.common.Util; |
|
| 92 | +import com.sap.sse.common.impl.MillisecondsTimePoint; |
|
| 93 | +import com.sap.sse.common.media.MediaTagConstants; |
|
| 94 | +import com.sap.sse.common.media.MimeType; |
|
| 95 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 96 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 97 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 98 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 99 | + |
|
| 100 | +public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest { |
|
| 101 | + private static final Logger logger = Logger.getLogger(TestStoringAndLoadingEventsAndRegattas.class.getName()); |
|
| 102 | + |
|
| 103 | + private final TimePoint eventStartDate; |
|
| 104 | + private final TimePoint eventEndDate; |
|
| 105 | + private final TimePoint regattaStartDate; |
|
| 106 | + private final TimePoint regattaEndDate; |
|
| 107 | + |
|
| 108 | + public TestStoringAndLoadingEventsAndRegattas() throws UnknownHostException, MongoException { |
|
| 109 | + super(); |
|
| 110 | + |
|
| 111 | + Calendar cal = Calendar.getInstance(); |
|
| 112 | + |
|
| 113 | + cal.set(2012, 12, 1); |
|
| 114 | + eventStartDate = new MillisecondsTimePoint(cal.getTimeInMillis()); |
|
| 115 | + cal.set(2012, 12, 5); |
|
| 116 | + eventEndDate = new MillisecondsTimePoint(cal.getTimeInMillis()); |
|
| 117 | + |
|
| 118 | + cal.set(2012, 12, 2); |
|
| 119 | + regattaStartDate = new MillisecondsTimePoint(cal.getTimeInMillis()); |
|
| 120 | + cal.set(2012, 12, 3); |
|
| 121 | + regattaEndDate = new MillisecondsTimePoint(cal.getTimeInMillis()); |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + private LeaderboardGroup createLeaderboardGroup(String name) { |
|
| 125 | + return new LeaderboardGroupImpl(name, "Description for "+name, /* displayName */ null, /* displayInReverseOrder */ false, Collections.<Leaderboard>emptyList()); |
|
| 126 | + } |
|
| 127 | + |
|
| 128 | + @Test |
|
| 129 | + public void testLoadStoreSimpleEventWithLinkToLeaderboardGroups() throws MalformedURLException { |
|
| 130 | + final String eventName = "Event Name"; |
|
| 131 | + final String eventDescription = "Event Description"; |
|
| 132 | + final String venueName = "Venue Name"; |
|
| 133 | + final String[] courseAreaNames = new String[] { "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrott" }; |
|
| 134 | + final URL officialWebsiteURL = new URL("http://official.website.com"); |
|
| 135 | + final URL sailorsInfoWebsiteURL = new URL("http://sailorsinfo.website.com"); |
|
| 136 | + final Venue venue = new VenueImpl(venueName); |
|
| 137 | + |
|
| 138 | + for (String courseAreaName : courseAreaNames) { |
|
| 139 | + CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName); |
|
| 140 | + venue.addCourseArea(courseArea); |
|
| 141 | + } |
|
| 142 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 143 | + final Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); |
|
| 144 | + final LeaderboardGroup lg1 = createLeaderboardGroup("lg1"); |
|
| 145 | + final LeaderboardGroup lg2 = createLeaderboardGroup("lg2"); |
|
| 146 | + event.addLeaderboardGroup(lg1); |
|
| 147 | + event.addLeaderboardGroup(lg2); |
|
| 148 | + event.setDescription(eventDescription); |
|
| 149 | + event.setOfficialWebsiteURL(officialWebsiteURL); |
|
| 150 | + event.setSailorsInfoWebsiteURL(sailorsInfoWebsiteURL); |
|
| 151 | + mof.storeEvent(event); |
|
| 152 | + |
|
| 153 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 154 | + final Event loadedEvent = dof.loadEvent(eventName); |
|
| 155 | + dof.loadLeaderboardGroupLinksForEvents(new EventResolver() { |
|
| 156 | + @Override |
|
| 157 | + public Event getEvent(Serializable id) { |
|
| 158 | + return id.equals(loadedEvent.getId()) ? loadedEvent : null; |
|
| 159 | + } |
|
| 160 | + }, new LeaderboardGroupResolver() { |
|
| 161 | + @Override |
|
| 162 | + public LeaderboardGroup getLeaderboardGroupByName(String leaderboardGroupName) { |
|
| 163 | + return leaderboardGroupName.equals(lg1.getName()) ? lg1 : leaderboardGroupName.equals(lg2.getName()) ? lg2 : null; |
|
| 164 | + } |
|
| 165 | + |
|
| 166 | + @Override |
|
| 167 | + public LeaderboardGroup getLeaderboardGroupByID(UUID leaderboardGroupID) { |
|
| 168 | + return leaderboardGroupID.equals(lg1.getId()) ? lg1 : leaderboardGroupID.equals(lg2.getId()) ? lg2 : null; |
|
| 169 | + } |
|
| 170 | + }); |
|
| 171 | + assertNotNull(loadedEvent); |
|
| 172 | + assertEquals(eventName, loadedEvent.getName()); |
|
| 173 | + assertEquals(eventDescription, loadedEvent.getDescription()); |
|
| 174 | + assertEquals(event.getOfficialWebsiteURL(), loadedEvent.getOfficialWebsiteURL()); |
|
| 175 | + assertEquals(event.getSailorsInfoWebsiteURL(), loadedEvent.getSailorsInfoWebsiteURL()); |
|
| 176 | + assertEquals(2, Util.size(loadedEvent.getLeaderboardGroups())); |
|
| 177 | + Iterator<LeaderboardGroup> lgIter = loadedEvent.getLeaderboardGroups().iterator(); |
|
| 178 | + assertSame(lg1, lgIter.next()); |
|
| 179 | + assertSame(lg2, lgIter.next()); |
|
| 180 | + final Venue loadedVenue = loadedEvent.getVenue(); |
|
| 181 | + assertNotNull(loadedVenue); |
|
| 182 | + assertEquals(venueName, loadedVenue.getName()); |
|
| 183 | + assertEquals(courseAreaNames.length, Util.size(loadedVenue.getCourseAreas())); |
|
| 184 | + int i=0; |
|
| 185 | + for (CourseArea loadedCourseArea : loadedVenue.getCourseAreas()) { |
|
| 186 | + assertEquals(courseAreaNames[i++], loadedCourseArea.getName()); |
|
| 187 | + } |
|
| 188 | + } |
|
| 189 | + |
|
| 190 | + @Test |
|
| 191 | + public void testLoadStoreSimpleEventAndRegattaWithCourseArea() { |
|
| 192 | + final String eventName = "Event Name"; |
|
| 193 | + final String venueName = "Venue Name"; |
|
| 194 | + final String courseAreaName = "Alpha"; |
|
| 195 | + final Venue venue = new VenueImpl(venueName); |
|
| 196 | + CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName); |
|
| 197 | + venue.addCourseArea(courseArea); |
|
| 198 | + |
|
| 199 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 200 | + Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); |
|
| 201 | + mof.storeEvent(event); |
|
| 202 | + |
|
| 203 | + final String regattaBaseName = "Kieler Woche"; |
|
| 204 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 205 | + Regatta regatta = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, |
|
| 206 | + regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), courseArea, OneDesignRankingMetric::new); |
|
| 207 | + mof.storeRegatta(regatta); |
|
| 208 | + |
|
| 209 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 210 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 211 | + assertNotNull(loadedRegatta); |
|
| 212 | + assertEquals(regatta.getName(), loadedRegatta.getName()); |
|
| 213 | + assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries())); |
|
| 214 | + assertNotNull(loadedRegatta.getDefaultCourseArea()); |
|
| 215 | + assertEquals(loadedRegatta.getDefaultCourseArea().getId(), courseArea.getId()); |
|
| 216 | + assertEquals(loadedRegatta.getDefaultCourseArea().getName(), courseArea.getName()); |
|
| 217 | + assertEquals(loadedRegatta.getStartDate(), regattaStartDate); |
|
| 218 | + assertEquals(loadedRegatta.getEndDate(), regattaEndDate); |
|
| 219 | + } |
|
| 220 | + |
|
| 221 | + @Test |
|
| 222 | + public void testLoadStoreSimpleEventWithImages() throws MalformedURLException { |
|
| 223 | + final URL imageURL = new URL("http://some.host/with/some/file2.jpg"); |
|
| 224 | + final String copyright = "copyright by Alex"; |
|
| 225 | + final String imageTitle = "My image title"; |
|
| 226 | + final String imageSubtitle = "My image subtitle"; |
|
| 227 | + final Integer imageWidth = 500; |
|
| 228 | + final Integer imageHeight = 300; |
|
| 229 | + final TimePoint createdAt = MillisecondsTimePoint.now(); |
|
| 230 | + final String eventName = "Event Name"; |
|
| 231 | + final String venueName = "Venue Name"; |
|
| 232 | + final String courseAreaName = "Alpha"; |
|
| 233 | + final Venue venue = new VenueImpl(venueName); |
|
| 234 | + CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName); |
|
| 235 | + venue.addCourseArea(courseArea); |
|
| 236 | + |
|
| 237 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 238 | + Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); |
|
| 239 | + |
|
| 240 | + ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt); |
|
| 241 | + image1.setCopyright(copyright); |
|
| 242 | + image1.setSize(imageWidth, imageHeight); |
|
| 243 | + image1.setTitle(imageTitle); |
|
| 244 | + image1.setSubtitle(imageSubtitle); |
|
| 245 | + image1.addTag("Tag1"); |
|
| 246 | + image1.addTag("Tag2"); |
|
| 247 | + image1.addTag("Tag3"); |
|
| 248 | + event.addImage(image1); |
|
| 249 | + |
|
| 250 | + ImageDescriptor image2 = new ImageDescriptorImpl(new URL("http://some.host/with/some/file2.jpg"), MillisecondsTimePoint.now()); |
|
| 251 | + image2.setCopyright("copyright"); |
|
| 252 | + event.addImage(image2); |
|
| 253 | + |
|
| 254 | + mof.storeEvent(event); |
|
| 255 | + |
|
| 256 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 257 | + final Event loadedEvent = dof.loadEvent(eventName); |
|
| 258 | + assertEquals(2, Util.size(loadedEvent.getImages())); |
|
| 259 | + ImageDescriptor loadedImage1 = loadedEvent.getImages().iterator().next(); |
|
| 260 | + assertNotNull(loadedImage1); |
|
| 261 | + assertEquals(imageURL, loadedImage1.getURL()); |
|
| 262 | + assertEquals(copyright, loadedImage1.getCopyright()); |
|
| 263 | + assertEquals(copyright, loadedImage1.getCopyright()); |
|
| 264 | + assertEquals(imageTitle, loadedImage1.getTitle()); |
|
| 265 | + assertEquals(imageSubtitle, loadedImage1.getSubtitle()); |
|
| 266 | + assertEquals(createdAt, loadedImage1.getCreatedAtDate()); |
|
| 267 | + assertEquals(imageWidth, loadedImage1.getWidthInPx()); |
|
| 268 | + assertEquals(imageHeight, loadedImage1.getHeightInPx()); |
|
| 269 | + assertEquals(3, Util.size(loadedImage1.getTags())); |
|
| 270 | + } |
|
| 271 | + |
|
| 272 | + @Test |
|
| 273 | + public void testLoadStoreSimpleEventWithVideos() throws MalformedURLException { |
|
| 274 | + final URL videoURL = new URL("http://some.host/with/some/video.mpg"); |
|
| 275 | + final URL videoThumbnailURL = new URL("http://some.host/with/some/video_thumbnail.jpg"); |
|
| 276 | + final Locale locale = Locale.GERMAN; |
|
| 277 | + final Integer videoLengthInSeconds = 2 * 60 * 60 * 1000; // 2h |
|
| 278 | + final MimeType mimeType = MimeType.mp4; |
|
| 279 | + final String copyright = "copyright by Don"; |
|
| 280 | + final String videoTitle = "My video title"; |
|
| 281 | + final String videoSubtitle = "My video subtitle"; |
|
| 282 | + final TimePoint createdAt = MillisecondsTimePoint.now(); |
|
| 283 | + final String eventName = "Event Name"; |
|
| 284 | + final String venueName = "Venue Name"; |
|
| 285 | + final String courseAreaName = "Alpha"; |
|
| 286 | + final Venue venue = new VenueImpl(venueName); |
|
| 287 | + CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), courseAreaName); |
|
| 288 | + venue.addCourseArea(courseArea); |
|
| 289 | + |
|
| 290 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 291 | + Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); |
|
| 292 | + |
|
| 293 | + VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, mimeType, createdAt); |
|
| 294 | + video1.setCopyright(copyright); |
|
| 295 | + video1.setTitle(videoTitle); |
|
| 296 | + video1.setLocale(locale); |
|
| 297 | + video1.setSubtitle(videoSubtitle); |
|
| 298 | + video1.setThumbnailURL(videoThumbnailURL); |
|
| 299 | + video1.setLengthInSeconds(videoLengthInSeconds); |
|
| 300 | + video1.addTag("Tag1"); |
|
| 301 | + video1.addTag("Tag2"); |
|
| 302 | + video1.addTag("Tag3"); |
|
| 303 | + event.addVideo(video1); |
|
| 304 | + |
|
| 305 | + VideoDescriptor video2 = new VideoDescriptorImpl(new URL("http://some.host/with/some/file2.ogg"), MimeType.ogg, MillisecondsTimePoint.now()); |
|
| 306 | + video2.setCopyright("copyright"); |
|
| 307 | + event.addVideo(video2); |
|
| 308 | + |
|
| 309 | + mof.storeEvent(event); |
|
| 310 | + |
|
| 311 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 312 | + final Event loadedEvent = dof.loadEvent(eventName); |
|
| 313 | + assertEquals(2, Util.size(loadedEvent.getVideos())); |
|
| 314 | + VideoDescriptor loadedVideo1 = loadedEvent.getVideos().iterator().next(); |
|
| 315 | + assertNotNull(loadedVideo1); |
|
| 316 | + assertEquals(videoURL, loadedVideo1.getURL()); |
|
| 317 | + assertEquals(videoThumbnailURL, loadedVideo1.getThumbnailURL()); |
|
| 318 | + assertEquals(videoLengthInSeconds, loadedVideo1.getLengthInSeconds()); |
|
| 319 | + assertEquals(copyright, loadedVideo1.getCopyright()); |
|
| 320 | + assertEquals(locale, loadedVideo1.getLocale()); |
|
| 321 | + assertEquals(videoTitle, loadedVideo1.getTitle()); |
|
| 322 | + assertEquals(videoSubtitle, loadedVideo1.getSubtitle()); |
|
| 323 | + assertEquals(createdAt, loadedVideo1.getCreatedAtDate()); |
|
| 324 | + assertEquals(3, Util.size(loadedVideo1.getTags())); |
|
| 325 | + } |
|
| 326 | + |
|
| 327 | + @SuppressWarnings("deprecation") |
|
| 328 | + @Test |
|
| 329 | + /** |
|
| 330 | + * We expected that the migration code creates also an image URL for each image we create. |
|
| 331 | + * Images with the 'Sponsor' tag should create a corresponding sponsor image URL |
|
| 332 | + * Videos should create a video URL. |
|
| 333 | + */ |
|
| 334 | + public void testLoadStoreSimpleEventWithImageAndVideoURLMigration() throws MalformedURLException { |
|
| 335 | + final URL imageURL = new URL("http://some.host/with/some/bla.jpg"); |
|
| 336 | + final URL sponsorImageURL = new URL("http://some.host/with/some/sponsor.jpg"); |
|
| 337 | + final URL videoURL = new URL("http://some.host/with/some/video.mpg"); |
|
| 338 | + final TimePoint createdAt = MillisecondsTimePoint.now(); |
|
| 339 | + final String eventName = "Event Name"; |
|
| 340 | + final Venue venue = new VenueImpl("My Venue"); |
|
| 341 | + CourseArea courseArea = DomainFactory.INSTANCE.getOrCreateCourseArea(UUID.randomUUID(), "Alfa"); |
|
| 342 | + venue.addCourseArea(courseArea); |
|
| 343 | + |
|
| 344 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 345 | + Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); |
|
| 346 | + |
|
| 347 | + ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt); |
|
| 348 | + image1.addTag(MediaTagConstants.GALLERY); |
|
| 349 | + event.addImage(image1); |
|
| 350 | + |
|
| 351 | + ImageDescriptor image2 = new ImageDescriptorImpl(sponsorImageURL, createdAt); |
|
| 352 | + event.addImage(image2); |
|
| 353 | + image2.addTag(MediaTagConstants.SPONSOR); |
|
| 354 | + |
|
| 355 | + VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, MimeType.mp4, createdAt); |
|
| 356 | + event.addVideo(video1); |
|
| 357 | + |
|
| 358 | + mof.storeEvent(event); |
|
| 359 | + |
|
| 360 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 361 | + final Event loadedEvent = dof.loadEvent(eventName); |
|
| 362 | + assertEquals(2, Util.size(loadedEvent.getImages())); |
|
| 363 | + assertEquals(1, Util.size(loadedEvent.getVideos())); |
|
| 364 | + assertEquals(1, Util.size(loadedEvent.getImageURLs())); |
|
| 365 | + assertEquals(1, Util.size(loadedEvent.getSponsorImageURLs())); |
|
| 366 | + assertEquals(1, Util.size(loadedEvent.getVideoURLs())); |
|
| 367 | + } |
|
| 368 | + |
|
| 369 | + |
|
| 370 | + @Test |
|
| 371 | + public void testLoadStoreRegattaConfiguration() { |
|
| 372 | + |
|
| 373 | + RegattaConfigurationImpl configuration = new RegattaConfigurationImpl(); |
|
| 374 | + configuration.setDefaultRacingProcedureType(RacingProcedureType.BASIC); |
|
| 375 | + |
|
| 376 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("ESS40", false); |
|
| 377 | + Regatta regatta = createRegattaAndAddRaceColumns(1, 1, RegattaImpl.getDefaultName("RR", boatClass.getName()), boatClass, |
|
| 378 | + regattaStartDate, regattaEndDate, false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT), OneDesignRankingMetric::new); |
|
| 379 | + regatta.setRegattaConfiguration(configuration); |
|
| 380 | + |
|
| 381 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 382 | + mof.storeRegatta(regatta); |
|
| 383 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 384 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), null); |
|
| 385 | + |
|
| 386 | + assertNotNull(loadedRegatta.getRegattaConfiguration()); |
|
| 387 | + assertEquals(RacingProcedureType.BASIC, loadedRegatta.getRegattaConfiguration().getDefaultRacingProcedureType()); |
|
| 388 | + } |
|
| 389 | + |
|
| 390 | + @Test |
|
| 391 | + public void testLoadStoreSimpleRegattaLeaderboard() { |
|
| 392 | + RacingEventService res = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE |
|
| 393 | + .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE); |
|
| 394 | + final int numberOfQualifyingRaces = 5; |
|
| 395 | + final int numberOfFinalRaces = 7; |
|
| 396 | + final String regattaBaseName = "Kieler Woche"; |
|
| 397 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 398 | + Regatta regattaProxy = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, |
|
| 399 | + regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new); |
|
| 400 | + final String regattaName = regattaProxy.getName(); |
|
| 401 | + Regatta regatta = res.createRegatta(regattaName, regattaProxy.getBoatClass().getName(), regattaStartDate, regattaEndDate, |
|
| 402 | + "123", regattaProxy.getSeries(), regattaProxy.isPersistent(), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, /* useStartTimeInference */ true, OneDesignRankingMetric::new); |
|
| 403 | + addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta); |
|
| 404 | + res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), null, new int[] { 3, 5 }); |
|
| 405 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 406 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 407 | + assertNotNull(loadedRegatta); |
|
| 408 | + assertEquals(regatta.getName(), loadedRegatta.getName()); |
|
| 409 | + assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries())); |
|
| 410 | + |
|
| 411 | + Leaderboard loadedLeaderboard = dof.loadLeaderboard(regatta.getName(), res); |
|
| 412 | + assertNotNull(loadedLeaderboard); |
|
| 413 | + assertTrue(loadedLeaderboard instanceof RegattaLeaderboard); |
|
| 414 | + RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard; |
|
| 415 | + assertSame(regatta, loadedRegattaLeaderboard.getRegatta()); |
|
| 416 | + } |
|
| 417 | + |
|
| 418 | + @Test |
|
| 419 | + public void testLoadStoreRegattaLeaderboardWithScoreCorrections() { |
|
| 420 | + // for some reason the dropping of collections doesn't work reliably on Linux... explicitly drop those collections that we depend on |
|
| 421 | + getMongoService().getDB().getCollection(CollectionNames.LEADERBOARDS.name()).drop(); |
|
| 422 | + getMongoService().getDB().getCollection(CollectionNames.REGATTAS.name()).drop(); |
|
| 423 | + Competitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner"); |
|
| 424 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 425 | + final DynamicTrackedRegatta[] trackedRegatta = new DynamicTrackedRegatta[1]; |
|
| 426 | + final DynamicTrackedRace q2YellowTrackedRace = new MockedTrackedRaceWithFixedRank(hasso, /* rank */ 1, /* started */ false, boatClass) { |
|
| 427 | + private static final long serialVersionUID = 1234L; |
|
| 428 | + @Override |
|
| 429 | + public RegattaAndRaceIdentifier getRaceIdentifier() { |
|
| 430 | + return new RegattaNameAndRaceName("Kieler Woche (29ERXX)", "Yellow Race 2"); |
|
| 431 | + } |
|
| 432 | + @Override |
|
| 433 | + public DynamicTrackedRegatta getTrackedRegatta() { |
|
| 434 | + return trackedRegatta[0]; |
|
| 435 | + } |
|
| 436 | + }; |
|
| 437 | + RacingEventService res = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace); |
|
| 438 | + final int numberOfQualifyingRaces = 5; |
|
| 439 | + final int numberOfFinalRaces = 7; |
|
| 440 | + final String regattaBaseName = "Kieler Woche"; |
|
| 441 | + |
|
| 442 | + Regatta regattaProxy = createRegatta(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new); |
|
| 443 | + Regatta regatta = res.createRegatta(regattaProxy.getName(), regattaProxy.getBoatClass().getName(), regattaProxy.getStartDate(), regattaProxy.getEndDate(), |
|
| 444 | + "123", regattaProxy.getSeries(), regattaProxy.isPersistent(), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, /* useStartTimeInference */ true, OneDesignRankingMetric::new); |
|
| 445 | + trackedRegatta[0] = new DynamicTrackedRegattaImpl(regatta); |
|
| 446 | + addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta); |
|
| 447 | + logColumnsInRegatta(regatta); |
|
| 448 | + RegattaLeaderboard regattaLeaderboard = res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), null, new int[] { 3, 5 }); |
|
| 449 | + assertSame(regatta, regattaLeaderboard.getRegatta()); |
|
| 450 | + final RaceColumnInSeries q2 = regatta.getSeriesByName("Qualifying").getRaceColumnByName("Q2"); |
|
| 451 | + final Fleet yellow = q2.getFleetByName("Yellow"); |
|
| 452 | + logColumnsInRegatta(regatta); |
|
| 453 | + logColumnsInRegattaLeaderboard(regattaLeaderboard); |
|
| 454 | + assertNotNull(regattaLeaderboard.getRaceColumnByName(q2.getName())); |
|
| 455 | + res.apply(new ConnectTrackedRaceToLeaderboardColumn(regattaLeaderboard.getName(), q2.getName(), yellow |
|
| 456 | + .getName(), q2YellowTrackedRace.getRaceIdentifier())); |
|
| 457 | + res.apply(new UpdateLeaderboardMaxPointsReason(regattaLeaderboard.getName(), q2.getName(), hasso.getId().toString(), |
|
| 458 | + MaxPointsReason.DNF, MillisecondsTimePoint.now())); |
|
| 459 | + |
|
| 460 | + // load new RacingEventService including regatta and leaderboard |
|
| 461 | + RacingEventService resForLoading = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace); |
|
| 462 | + Regatta loadedRegatta = resForLoading.getRegattaByName("Kieler Woche (29ERXX)"); |
|
| 463 | + assertNotNull(loadedRegatta); |
|
| 464 | + assertEquals(regatta.getName(), loadedRegatta.getName()); |
|
| 465 | + assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries())); |
|
| 466 | + Leaderboard loadedLeaderboard = resForLoading.getLeaderboardByName(loadedRegatta.getName()); |
|
| 467 | + assertNotNull(loadedLeaderboard); |
|
| 468 | + assertEquals(((ThresholdBasedResultDiscardingRule) regattaLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces().length, |
|
| 469 | + ((ThresholdBasedResultDiscardingRule) loadedLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces().length); |
|
| 470 | + assertTrue(Arrays.equals(((ThresholdBasedResultDiscardingRule) regattaLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces(), |
|
| 471 | + ((ThresholdBasedResultDiscardingRule) loadedLeaderboard.getResultDiscardingRule()).getDiscardIndexResultsStartingWithHowManyRaces())); |
|
| 472 | + assertTrue(loadedLeaderboard instanceof RegattaLeaderboard); |
|
| 473 | + RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard; |
|
| 474 | + assertSame(loadedRegatta, loadedRegattaLeaderboard.getRegatta()); |
|
| 475 | + // now re-associate the tracked race to let score correction "snap" to competitor: |
|
| 476 | + final RaceColumnInSeries loadedQ2 = loadedRegatta.getSeriesByName("Qualifying").getRaceColumnByName("Q2"); |
|
| 477 | + final Fleet loadedYellow = loadedQ2.getFleetByName("Yellow"); |
|
| 478 | + // adjust tracked regatta for tracked race: |
|
| 479 | + trackedRegatta[0] = new DynamicTrackedRegattaImpl(loadedRegatta); |
|
| 480 | + resForLoading.apply(new ConnectTrackedRaceToLeaderboardColumn(loadedLeaderboard.getName(), loadedQ2.getName(), loadedYellow |
|
| 481 | + .getName(), q2YellowTrackedRace.getRaceIdentifier())); |
|
| 482 | + MaxPointsReason hassosLoadedMaxPointsReason = loadedLeaderboard.getScoreCorrection().getMaxPointsReason(hasso, loadedQ2, MillisecondsTimePoint.now()); |
|
| 483 | + assertEquals(MaxPointsReason.DNF, hassosLoadedMaxPointsReason); |
|
| 484 | + } |
|
| 485 | + |
|
| 486 | + private void logColumnsInRegattaLeaderboard(RegattaLeaderboard regattaLeaderboard) { |
|
| 487 | + StringBuilder rlbrcNames = new StringBuilder(); |
|
| 488 | + for (RaceColumn rlbrc : regattaLeaderboard.getRaceColumns()) { |
|
| 489 | + rlbrcNames.append("; "); |
|
| 490 | + rlbrcNames.append(rlbrc.getName()); |
|
| 491 | + } |
|
| 492 | + logger.info("columns in regatta leaderboard for regatta "+regattaLeaderboard.getRegatta().getName()+" ("+ |
|
| 493 | + regattaLeaderboard.getRegatta().hashCode()+"): "+rlbrcNames); |
|
| 494 | + logColumnsInRegatta(regattaLeaderboard.getRegatta()); |
|
| 495 | + } |
|
| 496 | + |
|
| 497 | + private void logColumnsInRegatta(Regatta regatta) { |
|
| 498 | + StringBuilder rrcNames = new StringBuilder(); |
|
| 499 | + for (Series series : regatta.getSeries()) { |
|
| 500 | + for (RaceColumn raceColumn : series.getRaceColumns()) { |
|
| 501 | + rrcNames.append("; "); |
|
| 502 | + rrcNames.append(raceColumn.getName()); |
|
| 503 | + } |
|
| 504 | + } |
|
| 505 | + logger.info("columns in regatta "+regatta.getName()+" ("+regatta.hashCode()+") : "+rrcNames); |
|
| 506 | + } |
|
| 507 | + |
|
| 508 | + private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace) { |
|
| 509 | + return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE |
|
| 510 | + .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE) { |
|
| 511 | + @Override |
|
| 512 | + public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) { |
|
| 513 | + return q2YellowTrackedRace; |
|
| 514 | + } |
|
| 515 | + }; |
|
| 516 | + } |
|
| 517 | + |
|
| 518 | + @Test |
|
| 519 | + public void testLoadStoreSimpleRegatta() { |
|
| 520 | + final int numberOfQualifyingRaces = 5; |
|
| 521 | + final int numberOfFinalRaces = 7; |
|
| 522 | + final String regattaBaseName = "Kieler Woche"; |
|
| 523 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true); |
|
| 524 | + final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()); |
|
| 525 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName, |
|
| 526 | + boatClass, regattaStartDate, regattaEndDate, /* persistent */false, |
|
| 527 | + DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 528 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 529 | + mof.storeRegatta(regatta); |
|
| 530 | + |
|
| 531 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 532 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 533 | + assertSame(LowPoint.class, loadedRegatta.getScoringScheme().getClass()); |
|
| 534 | + assertEquals(regattaName, loadedRegatta.getName()); |
|
| 535 | + Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator(); |
|
| 536 | + Series loadedQualifyingSeries = seriesIter.next(); |
|
| 537 | + assertEquals(numberOfQualifyingRaces, Util.size(loadedQualifyingSeries.getRaceColumns())); |
|
| 538 | + assertEquals(0, loadedQualifyingSeries.getFleetByName("Yellow").compareTo(loadedQualifyingSeries.getFleetByName("Blue"))); |
|
| 539 | + Series loadedFinalSeries = seriesIter.next(); |
|
| 540 | + assertEquals(numberOfFinalRaces, Util.size(loadedFinalSeries.getRaceColumns())); |
|
| 541 | + assertTrue(loadedFinalSeries.getFleetByName("Silver").compareTo(loadedFinalSeries.getFleetByName("Gold")) > 0); |
|
| 542 | + Series loadedMedalSeries = seriesIter.next(); |
|
| 543 | + assertEquals(1, Util.size(loadedMedalSeries.getRaceColumns())); |
|
| 544 | + assertEquals(loadedRegatta.getStartDate(), regattaStartDate); |
|
| 545 | + assertEquals(loadedRegatta.getEndDate(), regattaEndDate); |
|
| 546 | + assertEquals(RankingMetrics.ONE_DESIGN, loadedRegatta.getRankingMetricType()); |
|
| 547 | + } |
|
| 548 | + |
|
| 549 | + @Test |
|
| 550 | + public void testLoadStoreRegattaWithHandicapRanking() { |
|
| 551 | + final int numberOfQualifyingRaces = 5; |
|
| 552 | + final int numberOfFinalRaces = 7; |
|
| 553 | + final String regattaBaseName = "Kieler Woche"; |
|
| 554 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true); |
|
| 555 | + final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()); |
|
| 556 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName, |
|
| 557 | + boatClass, regattaStartDate, regattaEndDate, /* persistent */false, |
|
| 558 | + DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), TimeOnTimeAndDistanceRankingMetric::new); |
|
| 559 | + assertEquals(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, regatta.getRankingMetricType()); |
|
| 560 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 561 | + mof.storeRegatta(regatta); |
|
| 562 | + |
|
| 563 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 564 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 565 | + assertSame(LowPoint.class, loadedRegatta.getScoringScheme().getClass()); |
|
| 566 | + assertEquals(regattaName, loadedRegatta.getName()); |
|
| 567 | + Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator(); |
|
| 568 | + Series loadedQualifyingSeries = seriesIter.next(); |
|
| 569 | + assertEquals(numberOfQualifyingRaces, Util.size(loadedQualifyingSeries.getRaceColumns())); |
|
| 570 | + assertEquals(0, loadedQualifyingSeries.getFleetByName("Yellow").compareTo(loadedQualifyingSeries.getFleetByName("Blue"))); |
|
| 571 | + Series loadedFinalSeries = seriesIter.next(); |
|
| 572 | + assertEquals(numberOfFinalRaces, Util.size(loadedFinalSeries.getRaceColumns())); |
|
| 573 | + assertTrue(loadedFinalSeries.getFleetByName("Silver").compareTo(loadedFinalSeries.getFleetByName("Gold")) > 0); |
|
| 574 | + Series loadedMedalSeries = seriesIter.next(); |
|
| 575 | + assertEquals(1, Util.size(loadedMedalSeries.getRaceColumns())); |
|
| 576 | + assertEquals(loadedRegatta.getStartDate(), regattaStartDate); |
|
| 577 | + assertEquals(loadedRegatta.getEndDate(), regattaEndDate); |
|
| 578 | + assertEquals(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, loadedRegatta.getRankingMetricType()); |
|
| 579 | + } |
|
| 580 | + |
|
| 581 | + @Test |
|
| 582 | + public void testLoadStoreSimpleRegattaWithEmptyStartAndEndDate() { |
|
| 583 | + final int numberOfQualifyingRaces = 1; |
|
| 584 | + final int numberOfFinalRaces = 1; |
|
| 585 | + final String regattaBaseName = "Kieler Woche"; |
|
| 586 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */true); |
|
| 587 | + final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()); |
|
| 588 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaName, |
|
| 589 | + boatClass, null, null, /* persistent */false, |
|
| 590 | + DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 591 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 592 | + mof.storeRegatta(regatta); |
|
| 593 | + |
|
| 594 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 595 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 596 | + assertEquals(regattaName, loadedRegatta.getName()); |
|
| 597 | + assertEquals(loadedRegatta.getStartDate(), null); |
|
| 598 | + assertEquals(loadedRegatta.getEndDate(), null); |
|
| 599 | + } |
|
| 600 | + |
|
| 601 | + @Test |
|
| 602 | + public void testLoadStoreSimpleRegattaWithSeriesScoringScheme() { |
|
| 603 | + final int numberOfQualifyingRaces = 5; |
|
| 604 | + final int numberOfFinalRaces = 7; |
|
| 605 | + final String regattaBaseName = "Kieler Woche"; |
|
| 606 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 607 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), |
|
| 608 | + boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 609 | + regatta.getSeriesByName("Qualifying").setResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(new int[] { 1, 2, 3 })); |
|
| 610 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 611 | + mof.storeRegatta(regatta); |
|
| 612 | + |
|
| 613 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 614 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 615 | + assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, |
|
| 616 | + loadedRegatta.getSeriesByName("Qualifying").getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces())); |
|
| 617 | + } |
|
| 618 | + |
|
| 619 | + @Test |
|
| 620 | + public void testLoadStoreSimpleRegattaWithScoreForMedalStartingWithZero() { |
|
| 621 | + final int numberOfQualifyingRaces = 5; |
|
| 622 | + final int numberOfFinalRaces = 7; |
|
| 623 | + final String regattaBaseName = "Kieler Woche"; |
|
| 624 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 625 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), |
|
| 626 | + boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 627 | + regatta.getSeriesByName("Medal").setStartsWithZeroScore(true); |
|
| 628 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 629 | + mof.storeRegatta(regatta); |
|
| 630 | + |
|
| 631 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 632 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 633 | + assertFalse(loadedRegatta.getSeriesByName("Qualifying").isStartsWithZeroScore()); |
|
| 634 | + assertTrue(loadedRegatta.getSeriesByName("Medal").isStartsWithZeroScore()); |
|
| 635 | + } |
|
| 636 | + |
|
| 637 | + @Test |
|
| 638 | + public void testLoadStoreSimpleRegattaWithHighPointScoringScheme() { |
|
| 639 | + final int numberOfQualifyingRaces = 5; |
|
| 640 | + final int numberOfFinalRaces = 7; |
|
| 641 | + final String regattaBaseName = "ESS40 Cardiff 2012"; |
|
| 642 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("ESS40", /* typicallyStartsUpwind */ false); |
|
| 643 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), |
|
| 644 | + boatClass, regattaStartDate, regattaEndDate, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT), OneDesignRankingMetric::new); |
|
| 645 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 646 | + mof.storeRegatta(regatta); |
|
| 647 | + |
|
| 648 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 649 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 650 | + assertSame(HighPoint.class, loadedRegatta.getScoringScheme().getClass()); |
|
| 651 | + } |
|
| 652 | + |
|
| 653 | + @Test |
|
| 654 | + public void testLoadStoreRegattaWithFleetsEnsuringIdenticalFleetsInSeriesAndRaceColumns() { |
|
| 655 | + final int numberOfQualifyingRaces = 5; |
|
| 656 | + final int numberOfFinalRaces = 7; |
|
| 657 | + final String regattaBaseName = "Kieler Woche"; |
|
| 658 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 659 | + final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()); |
|
| 660 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, |
|
| 661 | + regattaName, boatClass, regattaStartDate, regattaEndDate, |
|
| 662 | + /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 663 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 664 | + mof.storeRegatta(regatta); |
|
| 665 | + |
|
| 666 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 667 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 668 | + assertEquals(regattaName, loadedRegatta.getName()); |
|
| 669 | + Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator(); |
|
| 670 | + Series loadedQualifyingSeries = seriesIter.next(); |
|
| 671 | + int i=1; |
|
| 672 | + for (RaceColumn raceColumn : loadedQualifyingSeries.getRaceColumns()) { |
|
| 673 | + assertTrue(raceColumn instanceof RaceColumnInSeriesImpl); |
|
| 674 | + assertEquals("Q"+i, raceColumn.getName()); |
|
| 675 | + assertTrue(Util.equals(loadedQualifyingSeries.getFleets(), raceColumn.getFleets())); |
|
| 676 | + i++; |
|
| 677 | + } |
|
| 678 | + Series loadedFinalSeries = seriesIter.next(); |
|
| 679 | + i=1; |
|
| 680 | + for (RaceColumn raceColumn : loadedFinalSeries.getRaceColumns()) { |
|
| 681 | + assertTrue(raceColumn instanceof RaceColumnInSeriesImpl); |
|
| 682 | + assertEquals("F"+i, raceColumn.getName()); |
|
| 683 | + assertTrue(Util.equals(loadedFinalSeries.getFleets(), raceColumn.getFleets())); |
|
| 684 | + i++; |
|
| 685 | + } |
|
| 686 | + Series loadedMedalSeries = seriesIter.next(); |
|
| 687 | + for (RaceColumn raceColumn : loadedMedalSeries.getRaceColumns()) { |
|
| 688 | + assertTrue(raceColumn instanceof RaceColumnInSeriesImpl); |
|
| 689 | + assertEquals("M", raceColumn.getName()); |
|
| 690 | + assertTrue(Util.equals(loadedMedalSeries.getFleets(), raceColumn.getFleets())); |
|
| 691 | + } |
|
| 692 | + } |
|
| 693 | + |
|
| 694 | + @Test |
|
| 695 | + public void testLoadStoreRegattaWithFleetsEnsuringFleetOrdering() { |
|
| 696 | + final String regattaBaseName = "Kieler Woche"; |
|
| 697 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 698 | + final String regattaName = RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()); |
|
| 699 | + Regatta regatta = createRegatta(regattaName, boatClass, regattaStartDate, regattaEndDate, |
|
| 700 | + /* persistent */ false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new); |
|
| 701 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 702 | + mof.storeRegatta(regatta); |
|
| 703 | + |
|
| 704 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 705 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 706 | + assertEquals(regattaName, loadedRegatta.getName()); |
|
| 707 | + |
|
| 708 | + Iterator<? extends Series> seriesIter = loadedRegatta.getSeries().iterator(); |
|
| 709 | + Series loadedQualifyingSeries = seriesIter.next(); |
|
| 710 | + |
|
| 711 | + Iterator<? extends Fleet> qualiFleetIt = loadedQualifyingSeries.getFleets().iterator(); |
|
| 712 | + Fleet qualiFleet1 = qualiFleetIt.next(); |
|
| 713 | + assertEquals(qualiFleet1.getName(), "Yellow"); |
|
| 714 | + Fleet qualiFleet2 = qualiFleetIt.next(); |
|
| 715 | + assertEquals(qualiFleet2.getName(), "Blue"); |
|
| 716 | + |
|
| 717 | + Series loadedFinalSeries = seriesIter.next(); |
|
| 718 | + Iterator<? extends Fleet> finalFleetIt = loadedFinalSeries.getFleets().iterator(); |
|
| 719 | + Fleet finalFleet1 = finalFleetIt.next(); |
|
| 720 | + assertEquals(finalFleet1.getName(), "Gold"); |
|
| 721 | + Fleet finalFleet2 = finalFleetIt.next(); |
|
| 722 | + assertEquals(finalFleet2.getName(), "Silver"); |
|
| 723 | + } |
|
| 724 | + |
|
| 725 | + @Test |
|
| 726 | + public void testStorageOfRaceIdentifiersOnRaceColumnInSeries() { |
|
| 727 | + final int numberOfQualifyingRaces = 5; |
|
| 728 | + final int numberOfFinalRaces = 7; |
|
| 729 | + final String regattaBaseName = "Kieler Woche"; |
|
| 730 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true); |
|
| 731 | + Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, |
|
| 732 | + RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass, regattaStartDate, regattaEndDate, |
|
| 733 | + /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), OneDesignRankingMetric::new); |
|
| 734 | + Series qualifyingSeries = regatta.getSeries().iterator().next(); |
|
| 735 | + RaceColumn q2 = qualifyingSeries.getRaceColumnByName("Q2"); |
|
| 736 | + final RegattaNameAndRaceName q2TrackedRaceIdentifier = new RegattaNameAndRaceName(regatta.getName(), "Q2 TracTrac"); |
|
| 737 | + q2.setRaceIdentifier(qualifyingSeries.getFleetByName("Yellow"), q2TrackedRaceIdentifier); |
|
| 738 | + MongoObjectFactory mof = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService()); |
|
| 739 | + mof.storeRegatta(regatta); |
|
| 740 | + |
|
| 741 | + DomainObjectFactory dof = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE); |
|
| 742 | + Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null); |
|
| 743 | + Series loadedQualifyingSeries = loadedRegatta.getSeries().iterator().next(); |
|
| 744 | + RaceColumn loadedQ2 = loadedQualifyingSeries.getRaceColumnByName("Q2"); |
|
| 745 | + RaceIdentifier loadedQ2TrackedRaceIdentifier = loadedQ2.getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Yellow")); |
|
| 746 | + assertEquals(q2TrackedRaceIdentifier, loadedQ2TrackedRaceIdentifier); |
|
| 747 | + assertNotSame(q2TrackedRaceIdentifier, loadedQ2TrackedRaceIdentifier); |
|
| 748 | + assertNull(loadedQualifyingSeries.getRaceColumnByName("Q1").getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Yellow"))); |
|
| 749 | + assertNull(loadedQualifyingSeries.getRaceColumnByName("Q2").getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Blue"))); |
|
| 750 | + } |
|
| 751 | + |
|
| 752 | + private Regatta createRegattaAndAddRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces, |
|
| 753 | + final String regattaName, BoatClass boatClass, TimePoint startDate, TimePoint endDate, boolean persistent, |
|
| 754 | + ScoringScheme scoringScheme, RankingMetricConstructor rankingMetricConstructor) { |
|
| 755 | + Regatta regatta = createRegatta(regattaName, boatClass, startDate, endDate, persistent, scoringScheme, null, |
|
| 756 | + rankingMetricConstructor); |
|
| 757 | + addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta); |
|
| 758 | + return regatta; |
|
| 759 | + } |
|
| 760 | + |
|
| 761 | + private void addRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces, Regatta regatta) { |
|
| 762 | + List<String> finalRaceColumnNames = new ArrayList<String>(); |
|
| 763 | + for (int i=1; i<=numberOfFinalRaces; i++) { |
|
| 764 | + finalRaceColumnNames.add("F"+i); |
|
| 765 | + } |
|
| 766 | + List<String> qualifyingRaceColumnNames = new ArrayList<String>(); |
|
| 767 | + for (int i=1; i<=numberOfQualifyingRaces; i++) { |
|
| 768 | + qualifyingRaceColumnNames.add("Q"+i); |
|
| 769 | + } |
|
| 770 | + List<String> medalRaceColumnNames = new ArrayList<String>(); |
|
| 771 | + medalRaceColumnNames.add("M"); |
|
| 772 | + addRaceColumnsToSeries(qualifyingRaceColumnNames, regatta.getSeriesByName("Qualifying")); |
|
| 773 | + addRaceColumnsToSeries(finalRaceColumnNames, regatta.getSeriesByName("Final")); |
|
| 774 | + addRaceColumnsToSeries(medalRaceColumnNames, regatta.getSeriesByName("Medal")); |
|
| 775 | + } |
|
| 776 | + |
|
| 777 | + private Regatta createRegatta(final String regattaName, BoatClass boatClass, TimePoint startDate, |
|
| 778 | + TimePoint endDate, boolean persistent, ScoringScheme scoringScheme, CourseArea courseArea, |
|
| 779 | + RankingMetricConstructor rankingMetricConstructor) { |
|
| 780 | + List<String> emptyRaceColumnNames = Collections.emptyList(); |
|
| 781 | + List<Series> series = new ArrayList<Series>(); |
|
| 782 | + |
|
| 783 | + // -------- qualifying series ------------ |
|
| 784 | + List<Fleet> qualifyingFleets = new ArrayList<Fleet>(); |
|
| 785 | + qualifyingFleets.add(new FleetImpl("Yellow")); |
|
| 786 | + qualifyingFleets.add(new FleetImpl("Blue")); |
|
| 787 | + Series qualifyingSeries = new SeriesImpl("Qualifying", /* isMedal */false, qualifyingFleets, |
|
| 788 | + emptyRaceColumnNames, /* trackedRegattaRegistry */ null); |
|
| 789 | + series.add(qualifyingSeries); |
|
| 790 | + |
|
| 791 | + // -------- final series ------------ |
|
| 792 | + List<Fleet> finalFleets = new ArrayList<Fleet>(); |
|
| 793 | + finalFleets.add(new FleetImpl("Gold", 1)); |
|
| 794 | + finalFleets.add(new FleetImpl("Silver", 2)); |
|
| 795 | + Series finalSeries = new SeriesImpl("Final", /* isMedal */ false, finalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null); |
|
| 796 | + series.add(finalSeries); |
|
| 797 | + |
|
| 798 | + // ------------ medal -------------- |
|
| 799 | + List<Fleet> medalFleets = new ArrayList<Fleet>(); |
|
| 800 | + medalFleets.add(new FleetImpl("Medal")); |
|
| 801 | + Series medalSeries = new SeriesImpl("Medal", /* isMedal */ true, medalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null); |
|
| 802 | + series.add(medalSeries); |
|
| 803 | + Regatta regatta = new RegattaImpl(regattaName, boatClass, startDate, endDate, series, persistent, scoringScheme, "123", courseArea, rankingMetricConstructor); |
|
| 804 | + return regatta; |
|
| 805 | + } |
|
| 806 | + |
|
| 807 | + private void addRaceColumnsToSeries(List<String> finalRaceColumnNames, Series finalSeries) { |
|
| 808 | + for (String raceColumnName : finalRaceColumnNames) { |
|
| 809 | + finalSeries.addRaceColumn(raceColumnName, /* trackedRegattaRegistry */ null); |
|
| 810 | + } |
|
| 811 | + } |
|
| 812 | + |
|
| 813 | + @Test |
|
| 814 | + public void testRegattaRaceAssociationStore() throws Exception { |
|
| 815 | + BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("112er", /* typicallyStartsUpwind */ true); |
|
| 816 | + Regatta regatta = createRegatta(RegattaImpl.getDefaultName("Cologne Masters", boatClass.getName()), boatClass, |
|
| 817 | + regattaStartDate, regattaEndDate, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, OneDesignRankingMetric::new); |
|
| 818 | + |
|
| 819 | + List<Competitor> competitors = new ArrayList<Competitor>(); |
|
| 820 | + competitors.add(new CompetitorImpl("Axel", "Axel Uhl", Color.RED, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null)); |
|
| 821 | + Iterable<Waypoint> waypoints = Collections.emptyList(); |
|
| 822 | + Course course = new CourseImpl("Course", waypoints); |
|
| 823 | + |
|
| 824 | + RaceDefinition racedef = new RaceDefinitionImpl("M1", course, boatClass, competitors); |
|
| 825 | + regatta.addRace(racedef); |
|
| 826 | + |
|
| 827 | + RacingEventServiceImpl evs = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE |
|
| 828 | + .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE); |
|
| 829 | + assertNull(evs.getRememberedRegattaForRace(racedef.getId())); |
|
| 830 | + evs.raceAdded(regatta, racedef); |
|
| 831 | + assertNotNull(evs.getRememberedRegattaForRace(racedef.getId())); |
|
| 832 | + evs.removeRegatta(regatta); |
|
| 833 | + assertNull(evs.getRememberedRegattaForRace(racedef.getId())); |
|
| 834 | + } |
|
| 835 | + |
|
| 836 | +} |
java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/data/impl/GPSFixWithPolarContext.java
| ... | ... | @@ -38,7 +38,7 @@ public class GPSFixWithPolarContext implements HasGPSFixPolarContext { |
| 38 | 38 | |
| 39 | 39 | @Override |
| 40 | 40 | public ClusterDTO getWindSpeedRange() { |
| 41 | - return new ClusterDTO(windSpeedRangeGroup.getClusterFor(wind.getObject()).toString()); |
|
| 41 | + return new ClusterDTO(wind == null || wind.getObject() == null ? "null" : windSpeedRangeGroup.getClusterFor(wind.getObject()).toString()); |
|
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | @Override |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/AdminConsolePage.java
| ... | ... | @@ -18,6 +18,7 @@ import com.sap.sailing.selenium.pages.HostPage; |
| 18 | 18 | import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
|
| 19 | 19 | import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardGroupConfigurationPanelPO;
|
| 20 | 20 | import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaStructureManagementPanelPO;
|
| 21 | +import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesCompetitorsPanelPO;
|
|
| 21 | 22 | import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesManagementPanelPO;
|
| 22 | 23 | import com.sap.sailing.selenium.pages.adminconsole.tractrac.TracTracEventManagementPanelPO;
|
| 23 | 24 | |
| ... | ... | @@ -47,7 +48,7 @@ public class AdminConsolePage extends HostPage { |
| 47 | 48 | private static final String TRACTRAC_EVENTS_TAB_LABEL = "TracTrac Events"; //$NON-NLS-1$
|
| 48 | 49 | private static final String TRACTRAC_EVENTS_TAB_IDENTIFIER = "TracTracEventManagement"; //$NON-NLS-1$
|
| 49 | 50 | |
| 50 | - private static final String TRACKED_RACES_TAB_PARENT_LABEL = "Races"; //$NON-NLS-1$
|
|
| 51 | + private static final String TRACKED_RACES_TAB_PARENT_LABEL = "Tracked races"; //$NON-NLS-1$
|
|
| 51 | 52 | private static final String TRACKED_RACES_TAB_PARENT_IDENTIFIER = "RacesPanel"; //$NON-NLS-1$
|
| 52 | 53 | |
| 53 | 54 | private static final String TRACKED_RACES_TAB_LABEL = "Tracked races"; //$NON-NLS-1$
|
| ... | ... | @@ -62,6 +63,9 @@ public class AdminConsolePage extends HostPage { |
| 62 | 63 | private static final String LEADERBOARD_GROUP_CONFIGURATION_TAB_LABEL = "Leaderboard groups"; //$NON-NLS-1$
|
| 63 | 64 | private static final String LEADERBOARD_GROUP_CONFIGURATION_TAB_IDENTIFIER = "LeaderboardGroupConfiguration"; //$NON-NLS-1$
|
| 64 | 65 | |
| 66 | + private static final String COMPETITOR_PANEL_TAB_LABEL = "Competitors"; //$NON-NLS-1$
|
|
| 67 | + private static final String COMPETITOR_PANEL_TAB_IDENTIFIER = "CompetitorPanel"; //$NON-NLS-1$
|
|
| 68 | +
|
|
| 65 | 69 | /**
|
| 66 | 70 | * <p>Goes to the administration console and returns the representing page object.</p>
|
| 67 | 71 | *
|
| ... | ... | @@ -120,6 +124,12 @@ public class AdminConsolePage extends HostPage { |
| 120 | 124 | LEADERBOARD_GROUP_CONFIGURATION_TAB_IDENTIFIER, false));
|
| 121 | 125 | }
|
| 122 | 126 | |
| 127 | + public TrackedRacesCompetitorsPanelPO goToTrackedRacesCompetitors() {
|
|
| 128 | + goToTab(TRACKED_RACES_TAB_PARENT_LABEL, TRACKED_RACES_TAB_PARENT_IDENTIFIER, true);
|
|
| 129 | + return new TrackedRacesCompetitorsPanelPO(this.driver, goToTab(COMPETITOR_PANEL_TAB_LABEL,
|
|
| 130 | + COMPETITOR_PANEL_TAB_IDENTIFIER, false));
|
|
| 131 | + }
|
|
| 132 | +
|
|
| 123 | 133 | /**
|
| 124 | 134 | * <p>Verifies that the current page is the administration console by checking the title of the page.</p>
|
| 125 | 135 | */
|
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesCompetitorCreateDialogPO.java
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +package com.sap.sailing.selenium.pages.adminconsole.tracking;
|
|
| 2 | +
|
|
| 3 | +import org.openqa.selenium.WebDriver;
|
|
| 4 | +import org.openqa.selenium.WebElement;
|
|
| 5 | +
|
|
| 6 | +import com.sap.sailing.selenium.core.BySeleniumId;
|
|
| 7 | +import com.sap.sailing.selenium.core.FindBy;
|
|
| 8 | +import com.sap.sailing.selenium.pages.common.DataEntryDialogPO;
|
|
| 9 | +
|
|
| 10 | +public class TrackedRacesCompetitorCreateDialogPO extends DataEntryDialogPO {
|
|
| 11 | + @FindBy(how = BySeleniumId.class, using = "NameTextBox")
|
|
| 12 | + private WebElement nameTextBox;
|
|
| 13 | +
|
|
| 14 | + @FindBy(how = BySeleniumId.class, using = "SailIdTextBox")
|
|
| 15 | + private WebElement sailIdTextBox;
|
|
| 16 | +
|
|
| 17 | + @FindBy(how = BySeleniumId.class, using = "BoatClassNameSuggestBox")
|
|
| 18 | + private WebElement boatClassNameSuggestBox;
|
|
| 19 | +
|
|
| 20 | + @FindBy(how = BySeleniumId.class, using = "OkButton")
|
|
| 21 | + private WebElement okButton;
|
|
| 22 | +
|
|
| 23 | + public TrackedRacesCompetitorCreateDialogPO(WebDriver driver, WebElement element) {
|
|
| 24 | + super(driver, element);
|
|
| 25 | + }
|
|
| 26 | +
|
|
| 27 | + public void setNameTextBox(String name) {
|
|
| 28 | + this.nameTextBox.clear();
|
|
| 29 | + this.nameTextBox.sendKeys(name);
|
|
| 30 | + }
|
|
| 31 | +
|
|
| 32 | + public void setSailIdTextBox(String sailId) {
|
|
| 33 | + this.sailIdTextBox.clear();
|
|
| 34 | + this.sailIdTextBox.sendKeys(sailId);
|
|
| 35 | + }
|
|
| 36 | +
|
|
| 37 | + public void setBoatClassNameSuggestBox(String boatClassName) {
|
|
| 38 | + this.boatClassNameSuggestBox.clear();
|
|
| 39 | + this.boatClassNameSuggestBox.sendKeys(boatClassName);
|
|
| 40 | + }
|
|
| 41 | +}
|
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesCompetitorTablePO.java
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +package com.sap.sailing.selenium.pages.adminconsole.tracking;
|
|
| 2 | +
|
|
| 3 | +import org.openqa.selenium.WebDriver;
|
|
| 4 | +import org.openqa.selenium.WebElement;
|
|
| 5 | +
|
|
| 6 | +import com.sap.sailing.selenium.pages.gwt.CellTablePO;
|
|
| 7 | +import com.sap.sailing.selenium.pages.gwt.DataEntryPO;
|
|
| 8 | +
|
|
| 9 | +import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesCompetitorTablePO.CompetitorEntry;
|
|
| 10 | +
|
|
| 11 | +public class TrackedRacesCompetitorTablePO extends CellTablePO<CompetitorEntry> {
|
|
| 12 | + public static class CompetitorEntry extends DataEntryPO {
|
|
| 13 | + private static final String NAME_COLUMN = "Name";
|
|
| 14 | + private static final String SAILID_COLUMN = "Sail number";
|
|
| 15 | + private static final String BOATCLASSNAME_COLUMN = "Boat Class";
|
|
| 16 | + private static final String ID_COLUMN = "ID";
|
|
| 17 | +
|
|
| 18 | + protected CompetitorEntry(TrackedRacesCompetitorTablePO table, WebElement element) {
|
|
| 19 | + super(table, element);
|
|
| 20 | + }
|
|
| 21 | +
|
|
| 22 | + @Override
|
|
| 23 | + public String getIdentifier() {
|
|
| 24 | + return getId();
|
|
| 25 | + }
|
|
| 26 | +
|
|
| 27 | + public String getId() {
|
|
| 28 | + return getColumnContent(ID_COLUMN);
|
|
| 29 | + }
|
|
| 30 | +
|
|
| 31 | + public String getName() {
|
|
| 32 | + return getColumnContent(NAME_COLUMN);
|
|
| 33 | + }
|
|
| 34 | +
|
|
| 35 | + public String getSailId() {
|
|
| 36 | + return getColumnContent(SAILID_COLUMN);
|
|
| 37 | + }
|
|
| 38 | +
|
|
| 39 | + public String getBoatClassName() {
|
|
| 40 | + return getColumnContent(BOATCLASSNAME_COLUMN);
|
|
| 41 | + }
|
|
| 42 | + }
|
|
| 43 | + public TrackedRacesCompetitorTablePO(WebDriver driver, WebElement element) {
|
|
| 44 | + super(driver,element);
|
|
| 45 | + }
|
|
| 46 | +
|
|
| 47 | + @Override
|
|
| 48 | + protected CompetitorEntry createDataEntry(WebElement element) {
|
|
| 49 | + return new CompetitorEntry(this, element);
|
|
| 50 | + }
|
|
| 51 | +} |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesCompetitorsPanelPO.java
| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | +package com.sap.sailing.selenium.pages.adminconsole.tracking;
|
|
| 2 | +
|
|
| 3 | +import org.openqa.selenium.WebDriver;
|
|
| 4 | +import org.openqa.selenium.WebElement;
|
|
| 5 | +
|
|
| 6 | +import com.sap.sailing.selenium.core.BySeleniumId;
|
|
| 7 | +import com.sap.sailing.selenium.core.FindBy;
|
|
| 8 | +import com.sap.sailing.selenium.pages.PageArea;
|
|
| 9 | +
|
|
| 10 | +public class TrackedRacesCompetitorsPanelPO extends PageArea {
|
|
| 11 | + @FindBy(how = BySeleniumId.class, using = "AddCompetitorButton")
|
|
| 12 | + private WebElement addButton;
|
|
| 13 | +
|
|
| 14 | + @FindBy(how = BySeleniumId.class, using = "CompetitorsTable")
|
|
| 15 | + private WebElement competitorsTable;
|
|
| 16 | +
|
|
| 17 | + public TrackedRacesCompetitorsPanelPO(WebDriver driver, WebElement element) {
|
|
| 18 | + super(driver, element);
|
|
| 19 | + }
|
|
| 20 | +
|
|
| 21 | + public TrackedRacesCompetitorCreateDialogPO pushAddButton() {
|
|
| 22 | + this.addButton.click();
|
|
| 23 | + waitForAjaxRequests();
|
|
| 24 | + WebElement dialog = findElementBySeleniumId(this.driver, "CompetitorEditDialog");
|
|
| 25 | + return new TrackedRacesCompetitorCreateDialogPO(this.driver, dialog);
|
|
| 26 | + }
|
|
| 27 | +
|
|
| 28 | + public TrackedRacesCompetitorTablePO getCompetitorTable() {
|
|
| 29 | + return new TrackedRacesCompetitorTablePO(this.driver, this.competitorsTable);
|
|
| 30 | + }
|
|
| 31 | +}
|
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestCompetitorCreation.java
| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | +package com.sap.sailing.selenium.test.adminconsole;
|
|
| 2 | +
|
|
| 3 | +import static org.junit.Assert.assertEquals;
|
|
| 4 | +import static org.junit.Assert.assertNotNull;
|
|
| 5 | +import static org.junit.Assert.assertTrue;
|
|
| 6 | +
|
|
| 7 | +import org.junit.Before;
|
|
| 8 | +import org.junit.Test;
|
|
| 9 | +
|
|
| 10 | +import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
|
|
| 11 | +import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesCompetitorCreateDialogPO;
|
|
| 12 | +import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesCompetitorTablePO.CompetitorEntry;
|
|
| 13 | +import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesCompetitorsPanelPO;
|
|
| 14 | +import com.sap.sailing.selenium.test.AbstractSeleniumTest;
|
|
| 15 | +
|
|
| 16 | +public class TestCompetitorCreation extends AbstractSeleniumTest {
|
|
| 17 | + @Override
|
|
| 18 | + @Before
|
|
| 19 | + public void setUp() {
|
|
| 20 | + clearState(getContextRoot());
|
|
| 21 | + super.setUp();
|
|
| 22 | + }
|
|
| 23 | +
|
|
| 24 | + @Test
|
|
| 25 | + public void testOpenCreateCompetitorDialog() {
|
|
| 26 | + final TrackedRacesCompetitorsPanelPO competitorsPanel = goToCompetitorsPanel();
|
|
| 27 | + final TrackedRacesCompetitorCreateDialogPO dialog = competitorsPanel.pushAddButton(); // fails with an exception if the dialog is not found
|
|
| 28 | + assertNotNull(dialog);
|
|
| 29 | + }
|
|
| 30 | +
|
|
| 31 | + private TrackedRacesCompetitorsPanelPO goToCompetitorsPanel() {
|
|
| 32 | + final AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
|
|
| 33 | + final TrackedRacesCompetitorsPanelPO competitorsPanel = adminConsole.goToTrackedRacesCompetitors();
|
|
| 34 | + return competitorsPanel;
|
|
| 35 | + }
|
|
| 36 | +
|
|
| 37 | + @Test
|
|
| 38 | + public void testCompetitorCreation() {
|
|
| 39 | + final TrackedRacesCompetitorsPanelPO competitorsPanel = goToCompetitorsPanel();
|
|
| 40 | + final TrackedRacesCompetitorCreateDialogPO dialog = competitorsPanel.pushAddButton();
|
|
| 41 | + final String name = ""+System.currentTimeMillis();
|
|
| 42 | + dialog.setNameTextBox(name);
|
|
| 43 | + String sailId = ""+System.currentTimeMillis();
|
|
| 44 | + dialog.setSailIdTextBox(sailId);
|
|
| 45 | + final String boatClassName = "Laser Int.";
|
|
| 46 | + dialog.setBoatClassNameSuggestBox(boatClassName);
|
|
| 47 | + dialog.pressOk();
|
|
| 48 | + boolean found = false;
|
|
| 49 | + for (final CompetitorEntry it : competitorsPanel.getCompetitorTable().getEntries()) {
|
|
| 50 | + String itName = it.getName();
|
|
| 51 | + if (itName.equals(name)) {
|
|
| 52 | + found = true;
|
|
| 53 | + // found a candidate:
|
|
| 54 | + assertEquals(sailId, it.getSailId());
|
|
| 55 | + assertEquals(boatClassName, it.getBoatClassName());
|
|
| 56 | + }
|
|
| 57 | + }
|
|
| 58 | + assertTrue(found);
|
|
| 59 | + }
|
|
| 60 | +}
|
java/com.sap.sailing.server.gateway.serialization.shared.android/META-INF/MANIFEST.MF
| ... | ... | @@ -8,7 +8,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 |
| 8 | 8 | Require-Bundle: com.sap.sailing.domain.common, |
| 9 | 9 | com.sap.sailing.domain.shared.android, |
| 10 | 10 | org.json.simple;bundle-version="1.1.0", |
| 11 | - com.sap.sse.common |
|
| 11 | + com.sap.sse.common, |
|
| 12 | + com.sap.sse.shared.android |
|
| 12 | 13 | Export-Package: com.sap.sailing.server.gateway.deserialization, |
| 13 | 14 | com.sap.sailing.server.gateway.deserialization.coursedata.impl, |
| 14 | 15 | com.sap.sailing.server.gateway.deserialization.impl, |
java/com.sap.sailing.server.gateway.serialization.shared.android/pom.xml
| ... | ... | @@ -1,25 +1,25 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
| 4 | - <modelVersion>4.0.0</modelVersion>
|
|
| 5 | - <parent>
|
|
| 6 | - <artifactId>root</artifactId>
|
|
| 7 | - <groupId>com.sap.sailing</groupId>
|
|
| 8 | - <version>1.0.0-SNAPSHOT</version>
|
|
| 9 | - </parent>
|
|
| 10 | - <artifactId>com.sap.sailing.server.gateway.serialization.shared.android</artifactId>
|
|
| 11 | - <packaging>eclipse-plugin</packaging>
|
|
| 12 | - <build>
|
|
| 13 | - <plugins>
|
|
| 14 | - <plugin>
|
|
| 15 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 16 | - <artifactId>tycho-compiler-plugin</artifactId>
|
|
| 17 | - <version>${tycho-version}</version>
|
|
| 18 | - <configuration>
|
|
| 19 | - <source>1.7</source>
|
|
| 20 | - <target>1.7</target>
|
|
| 21 | - </configuration>
|
|
| 22 | - </plugin>
|
|
| 23 | - </plugins>
|
|
| 24 | - </build>
|
|
| 25 | -</project>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>com.sap.sailing.server.gateway.serialization.shared.android</artifactId> |
|
| 11 | + <packaging>eclipse-plugin</packaging> |
|
| 12 | + <build> |
|
| 13 | + <plugins> |
|
| 14 | + <plugin> |
|
| 15 | + <groupId>org.eclipse.tycho</groupId> |
|
| 16 | + <artifactId>tycho-compiler-plugin</artifactId> |
|
| 17 | + <version>${tycho-version}</version> |
|
| 18 | + <configuration> |
|
| 19 | + <source>1.7</source> |
|
| 20 | + <target>1.7</target> |
|
| 21 | + </configuration> |
|
| 22 | + </plugin> |
|
| 23 | + </plugins> |
|
| 24 | + </build> |
|
| 25 | +</project> |
java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java
| ... | ... | @@ -23,12 +23,12 @@ import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer |
| 23 | 23 | import com.sap.sse.common.TimePoint; |
| 24 | 24 | import com.sap.sse.common.Util; |
| 25 | 25 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 26 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 27 | -import com.sap.sse.common.media.ImageDescriptorImpl; |
|
| 28 | 26 | import com.sap.sse.common.media.ImageSize; |
| 29 | 27 | import com.sap.sse.common.media.MimeType; |
| 30 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 31 | -import com.sap.sse.common.media.VideoDescriptorImpl; |
|
| 28 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 29 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 30 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 31 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 32 | 32 | |
| 33 | 33 | public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> { |
| 34 | 34 | private final JsonDeserializer<Venue> venueDeserializer; |
java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java
| ... | ... | @@ -9,8 +9,8 @@ import com.sap.sailing.domain.base.EventBase; |
| 9 | 9 | import com.sap.sailing.domain.base.LeaderboardGroupBase; |
| 10 | 10 | import com.sap.sailing.domain.base.Venue; |
| 11 | 11 | import com.sap.sailing.server.gateway.serialization.JsonSerializer; |
| 12 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 13 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 12 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 13 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 14 | 14 | |
| 15 | 15 | public class EventBaseJsonSerializer implements JsonSerializer<EventBase> { |
| 16 | 16 | public static final String FIELD_ID = "id"; |
java/com.sap.sailing.server.gateway.serialization.test/META-INF/MANIFEST.MF
| ... | ... | @@ -14,4 +14,5 @@ Require-Bundle: com.sap.sailing.domain;bundle-version="1.0.0", |
| 14 | 14 | org.json.simple, |
| 15 | 15 | org.mockito.mockito-core;bundle-version="1.9.5", |
| 16 | 16 | org.objenesis;bundle-version="1.3.0", |
| 17 | - com.sap.sse.common |
|
| 17 | + com.sap.sse.common, |
|
| 18 | + com.sap.sse.shared.android |
java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java
| ... | ... | @@ -32,8 +32,8 @@ import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJso |
| 32 | 32 | import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer; |
| 33 | 33 | import com.sap.sse.common.TimePoint; |
| 34 | 34 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 35 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 36 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 35 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 36 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 37 | 37 | |
| 38 | 38 | public class EventDataJsonSerializerTest { |
| 39 | 39 | protected final UUID expectedId = UUID.randomUUID(); |
java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithImagesAndVideosTest.java
| ... | ... | @@ -36,11 +36,11 @@ import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer; |
| 36 | 36 | import com.sap.sse.common.TimePoint; |
| 37 | 37 | import com.sap.sse.common.Util; |
| 38 | 38 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 39 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 40 | -import com.sap.sse.common.media.ImageDescriptorImpl; |
|
| 41 | 39 | import com.sap.sse.common.media.MimeType; |
| 42 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 43 | -import com.sap.sse.common.media.VideoDescriptorImpl; |
|
| 40 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 41 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 42 | +import com.sap.sse.shared.media.impl.ImageDescriptorImpl; |
|
| 43 | +import com.sap.sse.shared.media.impl.VideoDescriptorImpl; |
|
| 44 | 44 | |
| 45 | 45 | public class EventDataJsonSerializerWithImagesAndVideosTest { |
| 46 | 46 | private final UUID expectedId = UUID.randomUUID(); |
java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java
| ... | ... | @@ -32,8 +32,8 @@ import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJso |
| 32 | 32 | import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer; |
| 33 | 33 | import com.sap.sse.common.TimePoint; |
| 34 | 34 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 35 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 36 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 35 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 36 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 37 | 37 | |
| 38 | 38 | public class EventDataJsonSerializerWithNullValuesTest { |
| 39 | 39 | protected final UUID expectedId = UUID.randomUUID(); |
java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java
| ... | ... | @@ -31,8 +31,8 @@ import com.sap.sailing.server.gateway.serialization.impl.EventBaseJsonSerializer |
| 31 | 31 | import com.sap.sailing.server.gateway.serialization.impl.LeaderboardGroupBaseJsonSerializer; |
| 32 | 32 | import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer; |
| 33 | 33 | import com.sap.sse.common.TimePoint; |
| 34 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 35 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 34 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 35 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 36 | 36 | |
| 37 | 37 | public class EventWithNullStartAndEndDataJsonSerializerTest { |
| 38 | 38 |
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
| ... | ... | @@ -129,11 +129,11 @@ import com.sap.sse.common.TimePoint; |
| 129 | 129 | import com.sap.sse.common.Util; |
| 130 | 130 | import com.sap.sse.common.impl.MillisecondsDurationImpl; |
| 131 | 131 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 132 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 133 | 132 | import com.sap.sse.common.media.MimeType; |
| 134 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 135 | 133 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 136 | 134 | import com.sap.sse.mongodb.MongoDBService; |
| 135 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 136 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 137 | 137 | |
| 138 | 138 | public class MasterDataImportTest { |
| 139 | 139 |
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java
| ... | ... | @@ -72,10 +72,10 @@ import com.sap.sse.common.Color; |
| 72 | 72 | import com.sap.sse.common.TimePoint; |
| 73 | 73 | import com.sap.sse.common.Util; |
| 74 | 74 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 75 | -import com.sap.sse.common.media.ImageDescriptor; |
|
| 76 | -import com.sap.sse.common.media.VideoDescriptor; |
|
| 77 | 75 | import com.sap.sse.common.search.KeywordQuery; |
| 78 | 76 | import com.sap.sse.common.search.Result; |
| 77 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 78 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 79 | 79 | |
| 80 | 80 | public class SearchServiceTest { |
| 81 | 81 | private RacingEventService server; |
java/com.sap.sailing.server/SailingServer (No Proxy OSX).launch
| ... | ... | @@ -1,38 +1,38 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
| 2 | -<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher"> |
|
| 3 | -<booleanAttribute key="append.args" value="true"/> |
|
| 4 | -<booleanAttribute key="automaticAdd" value="false"/> |
|
| 5 | -<booleanAttribute key="automaticValidate" value="false"/> |
|
| 6 | -<stringAttribute key="bootstrap" value=""/> |
|
| 7 | -<stringAttribute key="checked" value="[NONE]"/> |
|
| 8 | -<booleanAttribute key="clearConfig" value="false"/> |
|
| 9 | -<booleanAttribute key="com.sap.jvm.profiling.ui.widgets.allowDebugging" value="false"/> |
|
| 10 | -<stringAttribute key="configLocation" value="${workspace_loc}/target"/> |
|
| 11 | -<booleanAttribute key="default" value="true"/> |
|
| 12 | -<booleanAttribute key="default_auto_start" value="true"/> |
|
| 13 | -<intAttribute key="default_start_level" value="4"/> |
|
| 14 | -<booleanAttribute key="includeOptional" value="true"/> |
|
| 15 | -<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> |
|
| 16 | -<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> |
|
| 17 | -<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> |
|
| 18 | -</listAttribute> |
|
| 19 | -<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/> |
|
| 20 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
|
| 21 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/> |
|
| 22 | -<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/> |
|
| 23 | -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback"/> |
|
| 24 | -<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/> |
|
| 25 | -<stringAttribute key="pde.version" value="3.3"/> |
|
| 26 | -<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%"/> |
|
| 27 | -<stringAttribute key="profilingTraceType-IO_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/> |
|
| 28 | -<stringAttribute key="profilingTraceType-METHOD_PARAMETER_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/> |
|
| 29 | -<stringAttribute key="profilingTraceType-NETWORK_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_RESOLVE_ALL_HOSTS%CTX_KEY%true%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/> |
|
| 30 | -<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%false%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%true%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/> |
|
| 31 | -<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/> |
|
| 32 | -<booleanAttribute key="show_selected_only" value="false"/> |
|
| 33 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/> |
|
| 34 | -<booleanAttribute key="tracing" value="false"/> |
|
| 35 | -<booleanAttribute key="useCustomFeatures" value="false"/> |
|
| 36 | -<booleanAttribute key="useDefaultConfigArea" value="false"/> |
|
| 37 | -<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.news@default:default,com.sap.sailing.polars.datamining.shared@default:default,com.sap.sailing.polars.datamining@default:default,com.sap.sailing.polars@4:true,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization.shared.android@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sailing.xrr.schema@default:default,com.sap.sailing.xrr.structureimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.annotations@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.filestorage@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt.theme@5:true,com.sap.sse.gwt@default:default,com.sap.sse.mail@4:true,com.sap.sse.mongodb@default:default,com.sap.sse.operationaltransformation@default:default,com.sap.sse.replication@4:true,com.sap.sse.security.common@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.sap.sse.shared.android@default:default,com.sap.sse@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/> |
|
| 38 | -</launchConfiguration> |
|
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | +<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
|
|
| 3 | +<booleanAttribute key="append.args" value="true"/>
|
|
| 4 | +<booleanAttribute key="automaticAdd" value="false"/>
|
|
| 5 | +<booleanAttribute key="automaticValidate" value="false"/>
|
|
| 6 | +<stringAttribute key="bootstrap" value=""/>
|
|
| 7 | +<stringAttribute key="checked" value="[NONE]"/>
|
|
| 8 | +<booleanAttribute key="clearConfig" value="false"/>
|
|
| 9 | +<booleanAttribute key="com.sap.jvm.profiling.ui.widgets.allowDebugging" value="false"/>
|
|
| 10 | +<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
|
|
| 11 | +<booleanAttribute key="default" value="true"/>
|
|
| 12 | +<booleanAttribute key="default_auto_start" value="true"/>
|
|
| 13 | +<intAttribute key="default_start_level" value="4"/>
|
|
| 14 | +<booleanAttribute key="includeOptional" value="true"/>
|
|
| 15 | +<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
| 16 | +<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
|
| 17 | +<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
|
| 18 | +</listAttribute>
|
|
| 19 | +<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
|
| 20 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
|
| 21 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
|
| 22 | +<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
|
| 23 | +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback"/>
|
|
| 24 | +<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
|
| 25 | +<stringAttribute key="pde.version" value="3.3"/>
|
|
| 26 | +<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%"/>
|
|
| 27 | +<stringAttribute key="profilingTraceType-IO_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
|
| 28 | +<stringAttribute key="profilingTraceType-METHOD_PARAMETER_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
|
| 29 | +<stringAttribute key="profilingTraceType-NETWORK_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_RESOLVE_ALL_HOSTS%CTX_KEY%true%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
|
| 30 | +<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%false%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%true%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
|
| 31 | +<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
|
| 32 | +<booleanAttribute key="show_selected_only" value="false"/>
|
|
| 33 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 34 | +<booleanAttribute key="tracing" value="false"/>
|
|
| 35 | +<booleanAttribute key="useCustomFeatures" value="false"/>
|
|
| 36 | +<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
|
| 37 | +<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.news@default:default,com.sap.sailing.polars.datamining.shared@default:default,com.sap.sailing.polars.datamining@default:default,com.sap.sailing.polars@4:true,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization.shared.android@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sailing.xrr.schema@default:default,com.sap.sailing.xrr.structureimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.annotations@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.filestorage@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt.theme@5:true,com.sap.sse.gwt@default:default,com.sap.sse.mail@4:true,com.sap.sse.mongodb@default:default,com.sap.sse.operationaltransformation@default:default,com.sap.sse.replication@4:true,com.sap.sse.security.common@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.sap.sse.shared.android@default:default,com.sap.sse@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
|
| 38 | +</launchConfiguration>
|
java/com.sap.sailing.server/SailingServer (No Proxy).launch
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | <stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%false%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%true%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
| 31 | 31 | <stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
| 32 | 32 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 33 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 33 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 34 | 34 | <booleanAttribute key="tracing" value="false"/>
|
| 35 | 35 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 36 | 36 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch
| ... | ... | @@ -29,7 +29,7 @@ |
| 29 | 29 | <stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
| 30 | 30 | <stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
| 31 | 31 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 32 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 32 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 33 | 33 | <booleanAttribute key="tracing" value="false"/>
|
| 34 | 34 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 35 | 35 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
| ... | ... | @@ -16,14 +16,14 @@ |
| 16 | 16 | <listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
| 17 | 17 | </listAttribute>
|
| 18 | 18 | <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
| 19 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_31"/>
|
|
| 19 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_20"/>
|
|
| 20 | 20 | <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
| 21 | 21 | <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
| 22 | 22 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2011 -Xmx6000m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar -Djava.library.path=${project_loc:com.sap.sailing.monitoring}/../../configuration/native-libraries -Dtractrac.mtb.cache.dir=/Users/spamies/Projects/sailing/tmp/mtb -Dmongo.dbName=replica"/>
|
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch
| ... | ... | @@ -29,7 +29,7 @@ |
| 29 | 29 | <stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
| 30 | 30 | <stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
| 31 | 31 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 32 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 32 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 33 | 33 | <booleanAttribute key="tracing" value="false"/>
|
| 34 | 34 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 35 | 35 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (Proxy).launch
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | <stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
| 31 | 31 | <stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
| 32 | 32 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 33 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 33 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 34 | 34 | <booleanAttribute key="tracing" value="false"/>
|
| 35 | 35 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 36 | 36 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch
| ... | ... | @@ -17,13 +17,13 @@ |
| 17 | 17 | <listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
| 18 | 18 | </listAttribute>
|
| 19 | 19 | <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
| 20 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_31"/>
|
|
| 20 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_20"/>
|
|
| 21 | 21 | <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console"/>
|
| 22 | 22 | <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
| 23 | 23 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Xmx6000m -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dhttp.proxyHost=proxy.wdf.sap.corp -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080 -Dexpedition.udp.port=2010 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -XX:+UseMembar"/>
|
| 24 | 24 | <stringAttribute key="pde.version" value="3.3"/>
|
| 25 | 25 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 26 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | 27 | <booleanAttribute key="tracing" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useDefaultConfigArea" value="true"/>
|
java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch
| ... | ... | @@ -22,7 +22,7 @@ |
| 22 | 22 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-DsimulateLiveMode=true -DsimulateLiveMode.delayInMillis=250 -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2010 -Xmx6000m -Dhttp.proxyHost=proxy.wdf.sap.corp -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar"/>
|
| 23 | 23 | <stringAttribute key="pde.version" value="3.3"/>
|
| 24 | 24 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 25 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 25 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 26 | 26 | <booleanAttribute key="tracing" value="false"/>
|
| 27 | 27 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 28 | 28 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/SailingServer (Proxy, winddbTest).launch
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
| 25 | 25 | <stringAttribute key="pde.version" value="3.3"/>
|
| 26 | 26 | <booleanAttribute key="show_selected_only" value="false"/>
|
| 27 | -<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 27 | +<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-asl@default:default,jackson-jaxrs@default:default,jackson-mapper-asl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,lz4-java@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.poi.ooxml.schemas@default:default,org.apache.poi.ooxml@default:default,org.apache.poi@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.apache.xmlbeans@default:default,org.dom4j@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
|
| 28 | 28 | <booleanAttribute key="tracing" value="false"/>
|
| 29 | 29 | <booleanAttribute key="useCustomFeatures" value="false"/>
|
| 30 | 30 | <booleanAttribute key="useDefaultConfigArea" value="false"/>
|
java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java
| ... | ... | @@ -1,623 +1,623 @@ |
| 1 | -package com.sap.sailing.server;
|
|
| 2 | -
|
|
| 3 | -import java.io.IOException;
|
|
| 4 | -import java.io.Serializable;
|
|
| 5 | -import java.net.MalformedURLException;
|
|
| 6 | -import java.net.SocketException;
|
|
| 7 | -import java.net.URI;
|
|
| 8 | -import java.net.URL;
|
|
| 9 | -import java.util.Collection;
|
|
| 10 | -import java.util.ConcurrentModificationException;
|
|
| 11 | -import java.util.List;
|
|
| 12 | -import java.util.Map;
|
|
| 13 | -import java.util.UUID;
|
|
| 14 | -import java.util.concurrent.ConcurrentHashMap;
|
|
| 15 | -
|
|
| 16 | -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
|
| 17 | -import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
|
| 18 | -import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
|
| 19 | -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
|
| 20 | -import com.sap.sailing.domain.base.Competitor;
|
|
| 21 | -import com.sap.sailing.domain.base.CompetitorStore;
|
|
| 22 | -import com.sap.sailing.domain.base.CourseArea;
|
|
| 23 | -import com.sap.sailing.domain.base.DomainFactory;
|
|
| 24 | -import com.sap.sailing.domain.base.Event;
|
|
| 25 | -import com.sap.sailing.domain.base.EventBase;
|
|
| 26 | -import com.sap.sailing.domain.base.Fleet;
|
|
| 27 | -import com.sap.sailing.domain.base.LeaderboardSearchResult;
|
|
| 28 | -import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
|
|
| 29 | -import com.sap.sailing.domain.base.Mark;
|
|
| 30 | -import com.sap.sailing.domain.base.RaceColumn;
|
|
| 31 | -import com.sap.sailing.domain.base.RaceDefinition;
|
|
| 32 | -import com.sap.sailing.domain.base.Regatta;
|
|
| 33 | -import com.sap.sailing.domain.base.RegattaRegistry;
|
|
| 34 | -import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
|
| 35 | -import com.sap.sailing.domain.base.SailingServerConfiguration;
|
|
| 36 | -import com.sap.sailing.domain.base.Series;
|
|
| 37 | -import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
|
|
| 38 | -import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier;
|
|
| 39 | -import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
|
|
| 40 | -import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
|
| 41 | -import com.sap.sailing.domain.common.DataImportProgress;
|
|
| 42 | -import com.sap.sailing.domain.common.Position;
|
|
| 43 | -import com.sap.sailing.domain.common.RaceFetcher;
|
|
| 44 | -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
|
| 45 | -import com.sap.sailing.domain.common.RegattaFetcher;
|
|
| 46 | -import com.sap.sailing.domain.common.RegattaIdentifier;
|
|
| 47 | -import com.sap.sailing.domain.common.RegattaName;
|
|
| 48 | -import com.sap.sailing.domain.common.ScoringSchemeType;
|
|
| 49 | -import com.sap.sailing.domain.common.media.MediaTrack;
|
|
| 50 | -import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
|
| 51 | -import com.sap.sailing.domain.leaderboard.EventResolver;
|
|
| 52 | -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
|
| 53 | -import com.sap.sailing.domain.leaderboard.Leaderboard;
|
|
| 54 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
|
| 55 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver;
|
|
| 56 | -import com.sap.sailing.domain.leaderboard.LeaderboardRegistry;
|
|
| 57 | -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
|
| 58 | -import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
|
| 59 | -import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
|
| 60 | -import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
|
| 61 | -import com.sap.sailing.domain.polars.PolarDataService;
|
|
| 62 | -import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
|
| 63 | -import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
|
| 64 | -import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
|
|
| 65 | -import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
|
| 66 | -import com.sap.sailing.domain.tracking.RaceListener;
|
|
| 67 | -import com.sap.sailing.domain.tracking.RaceTracker;
|
|
| 68 | -import com.sap.sailing.domain.tracking.TrackedRace;
|
|
| 69 | -import com.sap.sailing.domain.tracking.TrackedRegatta;
|
|
| 70 | -import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
|
| 71 | -import com.sap.sailing.domain.tracking.TrackerManager;
|
|
| 72 | -import com.sap.sailing.domain.tracking.WindStore;
|
|
| 73 | -import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
|
| 74 | -import com.sap.sailing.server.simulation.SimulationService;
|
|
| 75 | -import com.sap.sse.common.TimePoint;
|
|
| 76 | -import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
|
| 77 | -import com.sap.sse.common.Util;
|
|
| 78 | -import com.sap.sse.common.Util.Triple;
|
|
| 79 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 80 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 81 | -import com.sap.sse.common.search.KeywordQuery;
|
|
| 82 | -import com.sap.sse.common.search.Result;
|
|
| 83 | -import com.sap.sse.common.search.Searchable;
|
|
| 84 | -import com.sap.sse.filestorage.FileStorageManagementService;
|
|
| 85 | -import com.sap.sse.replication.impl.ReplicableWithObjectInputStream;
|
|
| 86 | -
|
|
| 87 | -/**
|
|
| 88 | - * An OSGi service that can be used to track boat races using a TracTrac connector that pushes live GPS boat location,
|
|
| 89 | - * waypoint, coarse and mark passing data.
|
|
| 90 | - * <p>
|
|
| 91 | - *
|
|
| 92 | - * If a race/regatta is already being tracked, another {@link #addTracTracRace(URL, URI, URI, WindStore, long)} or
|
|
| 93 | - * {@link #addRegatta(URL, URI, URI, WindStore, long)} call will have no effect, even if a different {@link WindStore}
|
|
| 94 | - * is requested.
|
|
| 95 | - * <p>
|
|
| 96 | - *
|
|
| 97 | - * When the tracking of a race/regatta is {@link #stopTracking(Regatta, RaceDefinition) stopped}, the next time it's
|
|
| 98 | - * started to be tracked, a new {@link TrackedRace} at least will be constructed. This also means that when a
|
|
| 99 | - * {@link TrackedRegatta} exists that still holds other {@link TrackedRace}s, the no longer tracked {@link TrackedRace}
|
|
| 100 | - * will be removed from the {@link TrackedRegatta}. corresponding information is removed also from the
|
|
| 101 | - * {@link DomainFactory}'s caches to ensure that clean, fresh data is received should another tracking request be issued
|
|
| 102 | - * later.
|
|
| 103 | - * <p>
|
|
| 104 | - *
|
|
| 105 | - * During receiving the initial load for a replication in {@link #initiallyFillFromInternal(java.io.ObjectInputStream)},
|
|
| 106 | - * tracked regattas read from the stream are observed (see {@link RaceListener}) by this object for automatic updates to
|
|
| 107 | - * the default leaderboard and for automatic linking to leaderboard columns. It is assumed that no explicit replication
|
|
| 108 | - * of these operations will happen based on the changes performed on the replication master.
|
|
| 109 | - *
|
|
| 110 | - * @author Axel Uhl (d043530)
|
|
| 111 | - *
|
|
| 112 | - */
|
|
| 113 | -public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher,
|
|
| 114 | - LeaderboardRegistry, EventResolver, LeaderboardGroupResolver, TrackerManager, Searchable<LeaderboardSearchResult, KeywordQuery>,
|
|
| 115 | - ReplicableWithObjectInputStream<RacingEventService, RacingEventServiceOperation<?>>, RaceLogResolver {
|
|
| 116 | - @Override
|
|
| 117 | - Regatta getRegatta(RegattaName regattaName);
|
|
| 118 | -
|
|
| 119 | - @Override
|
|
| 120 | - RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier);
|
|
| 121 | -
|
|
| 122 | - DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race);
|
|
| 123 | -
|
|
| 124 | - DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
|
| 125 | -
|
|
| 126 | - /**
|
|
| 127 | - * Obtains an unmodifiable map of the leaderboard configured in this service keyed by their names.
|
|
| 128 | - */
|
|
| 129 | - Map<String, Leaderboard> getLeaderboards();
|
|
| 130 | -
|
|
| 131 | - /**
|
|
| 132 | - * @return a leaderboard whose {@link Leaderboard#getName()} method returns the value of the <code>name</code>
|
|
| 133 | - * parameter, or <code>null</code> if no such leaderboard is known to this service
|
|
| 134 | - */
|
|
| 135 | - Leaderboard getLeaderboardByName(String name);
|
|
| 136 | -
|
|
| 137 | - /**
|
|
| 138 | - * Looks at the mark tracks in the tracked races attached to the <code>leaderboard</code>. If it doesn't find a
|
|
| 139 | - * track for the <code>mark</code> requested there which has fixes before and after <code>timePoint</code> (to
|
|
| 140 | - * ensure that no track cropping has taken place, removing the fixes for the interesting time period), looks in the
|
|
| 141 | - * leaderboard's regatta log and the specific <code>raceLog</code> (if provided) or all race logs attached to the
|
|
| 142 | - * leaderboard (if not provided) for device mappings for the mark and tries to load fixes from the
|
|
| 143 | - * {@link GPSFixStore}. The latter is only necessary if the mark isn't found in any tracked race with fixes
|
|
| 144 | - * surrounding <code>timePoint</code> because should there be a tracked race in the leaderboard that has the mark
|
|
| 145 | - * then it will also have received the fixes from the {@link GPSFixStore} through the regatta log mapping.
|
|
| 146 | - * <p>
|
|
| 147 | - *
|
|
| 148 | - * @return the position obtained by interpolation but never extrapolation from the track identified as described
|
|
| 149 | - * above
|
|
| 150 | - */
|
|
| 151 | - Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog);
|
|
| 152 | -
|
|
| 153 | - /**
|
|
| 154 | - * Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta.
|
|
| 155 | - * See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to
|
|
| 156 | - * {@link #addTracTracRace(URL, URI, URI, WindStore, long)} with an equal combination of URLs/URIs, the {@link TracTracRaceTracker}
|
|
| 157 | - * already tracking the race was re-used. The trackers will be stopped by this call regardless of how many calls
|
|
| 158 | - * were made that ensured they were tracking.
|
|
| 159 | - */
|
|
| 160 | - void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
|
| 161 | -
|
|
| 162 | - /**
|
|
| 163 | - * Removes <code>race</code> and any corresponding {@link #getTrackedRace(Regatta, RaceDefinition) tracked race}
|
|
| 164 | - * from this service. If it was the last {@link RaceDefinition} in its {@link Regatta} and the regatta
|
|
| 165 | - * {@link Regatta#isPersistent() is not stored persistently}, the <code>regatta</code> is removed as well and will no
|
|
| 166 | - * longer be returned by {@link #getAllRegattas()}. The wind tracking is stopped for <code>race</code>.
|
|
| 167 | - * <p>
|
|
| 168 | - *
|
|
| 169 | - * Any {@link RaceTracker} for which <code>race</race> is the last race tracked that is still reachable
|
|
| 170 | - * from {@link #getAllRegattas()} will be {@link RaceTracker#stop(boolean) stopped}.
|
|
| 171 | - *
|
|
| 172 | - * The <code>race</code> will be also removed from all leaderboards containing a column that has <code>race</code>'s
|
|
| 173 | - * {@link #getTrackedRace(Regatta, RaceDefinition) corresponding} {@link TrackedRace} as its
|
|
| 174 | - * {@link RaceColumn#getTrackedRace(Fleet)}.
|
|
| 175 | - *
|
|
| 176 | - * @param regatta
|
|
| 177 | - * the regatta from which to remove the race
|
|
| 178 | - * @param race
|
|
| 179 | - * the race to remove
|
|
| 180 | - */
|
|
| 181 | - void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,InterruptedException;
|
|
| 182 | -
|
|
| 183 | - /**
|
|
| 184 | - * @param port
|
|
| 185 | - * the UDP port on which to listen for incoming messages from Expedition clients
|
|
| 186 | - * @param correctByDeclination
|
|
| 187 | - * An optional service to convert the wind bearings (which the receiver may
|
|
| 188 | - * believe to be true bearings) from magnetic to true bearings.
|
|
| 189 | - * @throws SocketException
|
|
| 190 | - * thrown, e.g., in case there is already another listener on the port requested
|
|
| 191 | - */
|
|
| 192 | - void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws Exception;
|
|
| 193 | -
|
|
| 194 | - void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException;
|
|
| 195 | -
|
|
| 196 | - /**
|
|
| 197 | - * The {@link Triple#getC() third component} of the triples returned is a wind tracker-specific
|
|
| 198 | - * comment where a wind tracker may provide information such as its type name or, if applicable,
|
|
| 199 | - * connectivity information such as the network port on which it receives wind information.
|
|
| 200 | - */
|
|
| 201 | - Iterable<Util.Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces();
|
|
| 202 | -
|
|
| 203 | - /**
|
|
| 204 | - * Creates a new leaderboard with the <code>name</code> specified.
|
|
| 205 | - * @param discardThresholds
|
|
| 206 | - * Tells the thresholds from which on a next higher number of worst races will be discarded per
|
|
| 207 | - * competitor. Example: <code>[3, 6]</code> means that starting from three races the single worst race
|
|
| 208 | - * will be discarded; starting from six races, the two worst races per competitor are discarded.
|
|
| 209 | - *
|
|
| 210 | - * @return the leaderboard created
|
|
| 211 | - */
|
|
| 212 | - FlexibleLeaderboard addFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringScheme scoringScheme, Serializable courseAreaId);
|
|
| 213 | -
|
|
| 214 | - RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, int[] discardThresholds);
|
|
| 215 | -
|
|
| 216 | - void removeLeaderboard(String leaderboardName);
|
|
| 217 | -
|
|
| 218 | - /**
|
|
| 219 | - * Renames a leaderboard. If a leaderboard by the name <code>oldName</code> does not exist in {@link #getLeaderboards()},
|
|
| 220 | - * or if a leaderboard with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
|
| 221 | - * If the method completes normally, the rename has been successful, and the leaderboard previously obtained by calling
|
|
| 222 | - * {@link #getLeaderboardByName(String) getLeaderboardByName(oldName)} can now be obtained by calling
|
|
| 223 | - * {@link #getLeaderboardByName(String) getLeaderboardByName(newName)}.
|
|
| 224 | - */
|
|
| 225 | - void renameLeaderboard(String oldName, String newName);
|
|
| 226 | -
|
|
| 227 | - RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace);
|
|
| 228 | -
|
|
| 229 | - void moveLeaderboardColumnUp(String leaderboardName, String columnName);
|
|
| 230 | -
|
|
| 231 | - void moveLeaderboardColumnDown(String leaderboardName, String columnName);
|
|
| 232 | -
|
|
| 233 | - void removeLeaderboardColumn(String leaderboardName, String columnName);
|
|
| 234 | -
|
|
| 235 | - void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName);
|
|
| 236 | -
|
|
| 237 | - /**
|
|
| 238 | - * @see RaceColumn#setFactor(Double)
|
|
| 239 | - */
|
|
| 240 | - void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor);
|
|
| 241 | -
|
|
| 242 | - /**
|
|
| 243 | - * Updates the leaderboard data in the persistent store
|
|
| 244 | - */
|
|
| 245 | - void updateStoredLeaderboard(Leaderboard leaderboard);
|
|
| 246 | -
|
|
| 247 | - void updateStoredRegatta(Regatta regatta);
|
|
| 248 | -
|
|
| 249 | - void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
|
| 250 | -
|
|
| 251 | - /**
|
|
| 252 | - * Removes the regatta as well as all regatta leaderboards for that regatta
|
|
| 253 | - */
|
|
| 254 | - void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
|
| 255 | -
|
|
| 256 | - /**
|
|
| 257 | - * Removes the given series
|
|
| 258 | - */
|
|
| 259 | - void removeSeries(Series series) throws MalformedURLException, IOException, InterruptedException;
|
|
| 260 | -
|
|
| 261 | - DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
|
| 262 | -
|
|
| 263 | - /**
|
|
| 264 | - * Obtains an unmodifiable map of the leaderboard groups configured in this service keyed by their names.
|
|
| 265 | - */
|
|
| 266 | - Map<String, LeaderboardGroup> getLeaderboardGroups();
|
|
| 267 | -
|
|
| 268 | - /**
|
|
| 269 | - * Creates a new group with the name <code>groupName</code>, the description <code>desciption</code> and the
|
|
| 270 | - * leaderboards with the names in <code>leaderboardNames</code> and saves it in the database.
|
|
| 271 | - * @param id TODO
|
|
| 272 | - * @param groupName
|
|
| 273 | - * The name of the new group
|
|
| 274 | - * @param description
|
|
| 275 | - * The description of the new group
|
|
| 276 | - * @param displayName TODO
|
|
| 277 | - * @param displayGroupsInReverseOrder TODO
|
|
| 278 | - * @param leaderboardNames
|
|
| 279 | - * The names of the leaderboards, which should be contained by the new group.<br />
|
|
| 280 | - * If there isn't a leaderboard with one of these names an {@link IllegalArgumentException} is thrown.
|
|
| 281 | - * @return The new leaderboard group
|
|
| 282 | - */
|
|
| 283 | - LeaderboardGroup addLeaderboardGroup(UUID id, String groupName, String description,
|
|
| 284 | - String displayName, boolean displayGroupsInReverseOrder, List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
|
| 285 | -
|
|
| 286 | - /**
|
|
| 287 | - * Removes the group with the name <code>groupName</code> from the service and the database.
|
|
| 288 | - * @param groupName The name of the group which shall be removed.
|
|
| 289 | - */
|
|
| 290 | - void removeLeaderboardGroup(String groupName);
|
|
| 291 | -
|
|
| 292 | - /**
|
|
| 293 | - * Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br />
|
|
| 294 | - * If there's no group with the name <code>oldName</code> or there's already a group with the name
|
|
| 295 | - * <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
|
| 296 | - *
|
|
| 297 | - * @param oldName The old name of the group
|
|
| 298 | - * @param newName The new name of the group
|
|
| 299 | - */
|
|
| 300 | - void renameLeaderboardGroup(String oldName, String newName);
|
|
| 301 | -
|
|
| 302 | - /**
|
|
| 303 | - * Updates the group data in the persistant store.
|
|
| 304 | - */
|
|
| 305 | - void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup);
|
|
| 306 | -
|
|
| 307 | - DynamicTrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore, GPSFixStore gpsFixStore,
|
|
| 308 | - long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, boolean useMarkPassingCalculator);
|
|
| 309 | -
|
|
| 310 | - Regatta getOrCreateDefaultRegatta(String name, String boatClassName, Serializable id);
|
|
| 311 | -
|
|
| 312 | - /**
|
|
| 313 | - * @param series the series must not have any {@link RaceColumn}s yet
|
|
| 314 | - */
|
|
| 315 | - Regatta createRegatta(String regattaName, String boatClassName, TimePoint startDate, TimePoint endDate, Serializable id, Iterable<? extends Series> series,
|
|
| 316 | - boolean persistent, ScoringScheme scoringScheme, Serializable defaultCourseAreaId,
|
|
| 317 | - boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor);
|
|
| 318 | -
|
|
| 319 | - Regatta updateRegatta(RegattaIdentifier regattaIdentifier, TimePoint startDate, TimePoint endDate, Serializable newDefaultCourseAreaId, RegattaConfiguration regattaConfiguration, Iterable<? extends Series> series, boolean useStartTimeInference);
|
|
| 320 | -
|
|
| 321 | - /**
|
|
| 322 | - * Adds <code>raceDefinition</code> to the {@link Regatta} such that it will appear in {@link Regatta#getAllRaces()}
|
|
| 323 | - * and {@link Regatta#getRaceByName(String)}.
|
|
| 324 | - *
|
|
| 325 | - * @param addToRegatta identifier of an regatta that must exist already
|
|
| 326 | - */
|
|
| 327 | - void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition);
|
|
| 328 | -
|
|
| 329 | - void updateLeaderboardGroup(String oldName, String newName, String description, String displayName,
|
|
| 330 | - List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
|
| 331 | -
|
|
| 332 | - /**
|
|
| 333 | - * @return a thread-safe copy of the events currently known by the service; it's safe for callers to iterate over
|
|
| 334 | - * the iterable returned, and no risk of a {@link ConcurrentModificationException} exists
|
|
| 335 | - */
|
|
| 336 | - Iterable<Event> getAllEvents();
|
|
| 337 | -
|
|
| 338 | - /**
|
|
| 339 | - * Creates a new event with the name <code>eventName</code>, the venue <code>venue</code> and the regattas with the
|
|
| 340 | - * names in <code>regattaNames</code>, saves it in the database and replicates it. Use for TESTING only!
|
|
| 341 | - *
|
|
| 342 | - * @param eventName
|
|
| 343 | - * The name of the new event
|
|
| 344 | - * @param eventDescription TODO
|
|
| 345 | - * @param startDate
|
|
| 346 | - * The start date of the event
|
|
| 347 | - * @param endDate
|
|
| 348 | - * The end date of the event
|
|
| 349 | - * @param isPublic
|
|
| 350 | - * Indicates whether the event is public accessible via the publication URL or not
|
|
| 351 | - * @param id
|
|
| 352 | - * The id of the new event
|
|
| 353 | - * @param venue
|
|
| 354 | - * The name of the venue of the new event
|
|
| 355 | - * @return The new event
|
|
| 356 | - */
|
|
| 357 | - Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id);
|
|
| 358 | -
|
|
| 359 | - /**
|
|
| 360 | - * Updates a sailing event with the name <code>eventName</code>, the venue<code>venue</code> and the regattas with
|
|
| 361 | - * the names in <code>regattaNames</code> and updates it in the database.
|
|
| 362 | - * @param eventName
|
|
| 363 | - * The name of the event to update
|
|
| 364 | - * @param startDate
|
|
| 365 | - * The start date of the event
|
|
| 366 | - * @param endDate
|
|
| 367 | - * The end date of the event
|
|
| 368 | - * @param venueName
|
|
| 369 | - * The name of the venue of the event
|
|
| 370 | - * @param isPublic
|
|
| 371 | - * Indicates whether the event is public accessible via the publication URL or not
|
|
| 372 | - * @return The new event
|
|
| 373 | - */
|
|
| 374 | - void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
|
|
| 375 | - String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL,
|
|
| 376 | - Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos);
|
|
| 377 | -
|
|
| 378 | - /**
|
|
| 379 | - * Renames a sailing event. If a sailing event by the name <code>oldName</code> does not exist in {@link #getEvents()},
|
|
| 380 | - * or if a event with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
|
| 381 | - * If the method completes normally, the rename has been successful, and the event previously obtained by calling
|
|
| 382 | - * {@link #getEventByName(String) getEventByName(oldName)} can now be obtained by calling
|
|
| 383 | - * {@link #getEventByName(String) getEventByName(newName)}.
|
|
| 384 | - */
|
|
| 385 | - void renameEvent(UUID id, String newEventName);
|
|
| 386 | -
|
|
| 387 | - void removeEvent(UUID id);
|
|
| 388 | -
|
|
| 389 | -
|
|
| 390 | - /**
|
|
| 391 | - * @return a thread-safe copy of the events (or the exception that occurred trying to obtain the events; arranged in
|
|
| 392 | - * a {@link Util.Pair}) of from all sailing server instances currently known by the service; it's safe for
|
|
| 393 | - * callers to iterate over the iterable returned, and no risk of a {@link ConcurrentModificationException}
|
|
| 394 | - * exists
|
|
| 395 | - */
|
|
| 396 | - Map<RemoteSailingServerReference, Util.Pair<Iterable<EventBase>, Exception>> getPublicEventsOfAllSailingServers();
|
|
| 397 | -
|
|
| 398 | - RemoteSailingServerReference addRemoteSailingServerReference(String name, URL url);
|
|
| 399 | -
|
|
| 400 | - void removeRemoteSailingServerReference(String name);
|
|
| 401 | -
|
|
| 402 | -
|
|
| 403 | - CourseArea[] addCourseAreas(UUID eventId, String[] courseAreaNames, UUID[] courseAreaIds);
|
|
| 404 | -
|
|
| 405 | - com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
|
|
| 406 | -
|
|
| 407 | - CourseArea getCourseArea(Serializable courseAreaId);
|
|
| 408 | -
|
|
| 409 | - /**
|
|
| 410 | - * Adds the specified mediaTrack to the in-memory media library.
|
|
| 411 | - * Important note: Only if mediaTrack.dbId != null the mediaTrack will be persisted in the the database.
|
|
| 412 | - * @param mediaTrack
|
|
| 413 | - */
|
|
| 414 | - void mediaTrackAdded(MediaTrack mediaTrack);
|
|
| 415 | -
|
|
| 416 | - /**
|
|
| 417 | - * Calling mediaTrackAdded for every entry in the specified collection.
|
|
| 418 | - * @param mediaTracks
|
|
| 419 | - */
|
|
| 420 | - void mediaTracksAdded(Collection<MediaTrack> mediaTracks);
|
|
| 421 | -
|
|
| 422 | - void mediaTrackTitleChanged(MediaTrack mediaTrack);
|
|
| 423 | -
|
|
| 424 | - void mediaTrackUrlChanged(MediaTrack mediaTrack);
|
|
| 425 | -
|
|
| 426 | - void mediaTrackStartTimeChanged(MediaTrack mediaTrack);
|
|
| 427 | -
|
|
| 428 | - void mediaTrackDurationChanged(MediaTrack mediaTrack);
|
|
| 429 | -
|
|
| 430 | - void mediaTrackAssignedRacesChanged(MediaTrack mediaTrack);
|
|
| 431 | -
|
|
| 432 | - void mediaTrackDeleted(MediaTrack mediaTrack);
|
|
| 433 | -
|
|
| 434 | - /**
|
|
| 435 | - * In contrast to mediaTracksAdded, this method takes mediaTracks with a given dbId.
|
|
| 436 | - * Checks if the track already exists in the library and the database and adds/stores it
|
|
| 437 | - * accordingly. If a track already exists and override, its properties are checked for changes
|
|
| 438 | - * @param mediaTrack
|
|
| 439 | - * @param override If true, track properties (title, url, start time, duration, not mime type!) will be
|
|
| 440 | - * overwritten with the values from the track to be imported.
|
|
| 441 | - */
|
|
| 442 | - void mediaTracksImported(Collection<MediaTrack> mediaTracksToImport, boolean override);
|
|
| 443 | -
|
|
| 444 | - Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier);
|
|
| 445 | -
|
|
| 446 | - Collection<MediaTrack> getMediaTracksInTimeRange(RegattaAndRaceIdentifier regattaAndRaceIdentifier);
|
|
| 447 | -
|
|
| 448 | - Collection<MediaTrack> getAllMediaTracks();
|
|
| 449 | -
|
|
| 450 | - void reloadRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
|
| 451 | -
|
|
| 452 | - RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
|
| 453 | -
|
|
| 454 | - /**
|
|
| 455 | - * @param rankingMetricConstructor TODO
|
|
| 456 | - * @return a pair with the found or created regatta, and a boolean that tells whether the regatta was created during
|
|
| 457 | - * the call
|
|
| 458 | - */
|
|
| 459 | - Util.Pair<Regatta, Boolean> getOrCreateRegattaWithoutReplication(String fullRegattaName, String boatClassName,
|
|
| 460 | - TimePoint startDate, TimePoint endDate, Serializable id,
|
|
| 461 | - Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme,
|
|
| 462 | - Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor);
|
|
| 463 | -
|
|
| 464 | - /**
|
|
| 465 | - * @return map where keys are the toString() representation of the {@link RaceDefinition#getId() IDs} of races passed to
|
|
| 466 | - * {@link #setRegattaForRace(Regatta, RaceDefinition)}. It helps remember the connection between races and regattas.
|
|
| 467 | - */
|
|
| 468 | - ConcurrentHashMap<String, Regatta> getPersistentRegattasForRaceIDs();
|
|
| 469 | -
|
|
| 470 | - Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue,
|
|
| 471 | - boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, Iterable<ImageDescriptor> images,
|
|
| 472 | - Iterable<VideoDescriptor> videos);
|
|
| 473 | -
|
|
| 474 | - void setRegattaForRace(Regatta regatta, String raceIdAsString);
|
|
| 475 | -
|
|
| 476 | - CourseArea[] addCourseAreasWithoutReplication(UUID eventId, UUID[] courseAreaIds, String[] courseAreaNames);
|
|
| 477 | -
|
|
| 478 | - CourseArea[] removeCourseAreaWithoutReplication(UUID eventId, UUID[] courseAreaIds);
|
|
| 479 | -
|
|
| 480 | - /**
|
|
| 481 | - * Returns a mobile device's configuration.
|
|
| 482 | - * @param identifier of the client (may include event)
|
|
| 483 | - * @return the {@link DeviceConfiguration}
|
|
| 484 | - */
|
|
| 485 | - DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier);
|
|
| 486 | -
|
|
| 487 | - /**
|
|
| 488 | - * Adds a device configuration.
|
|
| 489 | - * @param matcher defining for which the configuration applies.
|
|
| 490 | - * @param configuration of the device.
|
|
| 491 | - */
|
|
| 492 | - void createOrUpdateDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration);
|
|
| 493 | -
|
|
| 494 | - /**
|
|
| 495 | - * Removes a configuration by its matching object.
|
|
| 496 | - * @param matcher
|
|
| 497 | - */
|
|
| 498 | - void removeDeviceConfiguration(DeviceConfigurationMatcher matcher);
|
|
| 499 | -
|
|
| 500 | - /**
|
|
| 501 | - * Returns all configurations and their matching objects.
|
|
| 502 | - * @return the {@link DeviceConfiguration}s.
|
|
| 503 | - */
|
|
| 504 | - Map<DeviceConfigurationMatcher, DeviceConfiguration> getAllDeviceConfigurations();
|
|
| 505 | -
|
|
| 506 | - /**
|
|
| 507 | - * Forces a new start time on the RaceLog identified by the passed parameters.
|
|
| 508 | - * @param leaderboardName name of the RaceLog's leaderboard.
|
|
| 509 | - * @param raceColumnName name of the RaceLog's column
|
|
| 510 | - * @param fleetName name of the RaceLog's fleet
|
|
| 511 | - * @param authorName name of the {@link AbstractLogEventAuthor} the {@link RaceLogStartTimeEvent} will be created with
|
|
| 512 | - * @param authorPriority priority of the author.
|
|
| 513 | - * @param passId Pass identifier of the new start time event.
|
|
| 514 | - * @param logicalTimePoint logical {@link TimePoint} of the new event.
|
|
| 515 | - * @param startTime the new Start-Time
|
|
| 516 | - * @return
|
|
| 517 | - */
|
|
| 518 | - TimePoint setStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName, String authorName,
|
|
| 519 | - int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime, RacingProcedureType racingProcedure);
|
|
| 520 | -
|
|
| 521 | - /**
|
|
| 522 | - * Gets the start time, pass identifier and racing procedure for the queried race. Start time might be <code>null</code>.
|
|
| 523 | - */
|
|
| 524 | - Util.Triple<TimePoint, Integer, RacingProcedureType> getStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName);
|
|
| 525 | -
|
|
| 526 | - MongoObjectFactory getMongoObjectFactory();
|
|
| 527 | -
|
|
| 528 | - DomainObjectFactory getDomainObjectFactory();
|
|
| 529 | -
|
|
| 530 | - WindStore getWindStore();
|
|
| 531 | -
|
|
| 532 | - PolarDataService getPolarDataService();
|
|
| 533 | -
|
|
| 534 | - SimulationService getSimulationService();
|
|
| 535 | -
|
|
| 536 | - GPSFixStore getGPSFixStore();
|
|
| 537 | -
|
|
| 538 | - RaceTracker getRaceTrackerById(Object id);
|
|
| 539 | -
|
|
| 540 | - AbstractLogEventAuthor getServerAuthor();
|
|
| 541 | -
|
|
| 542 | - CompetitorStore getCompetitorStore();
|
|
| 543 | -
|
|
| 544 | - TypeBasedServiceFinderFactory getTypeBasedServiceFinderFactory();
|
|
| 545 | -
|
|
| 546 | - /**
|
|
| 547 | - * This lock exists to allow only one master data import at a time to avoid situation where multiple Imports
|
|
| 548 | - * override each other in unpredictable fashion
|
|
| 549 | - */
|
|
| 550 | - DataImportLockWithProgress getDataImportLock();
|
|
| 551 | -
|
|
| 552 | - DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId,
|
|
| 553 | - double overallProgressPct,
|
|
| 554 | - String subProgressName, double subProgressPct);
|
|
| 555 | -
|
|
| 556 | - DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId,
|
|
| 557 | - double overallProgressPct,
|
|
| 558 | - String subProgressName, double subProgressPct);
|
|
| 559 | -
|
|
| 560 | - void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage);
|
|
| 561 | -
|
|
| 562 | - void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage);
|
|
| 563 | -
|
|
| 564 | - void setDataImportDeleteProgressFromMapTimerWithReplication(UUID importOperationId);
|
|
| 565 | -
|
|
| 566 | - void setDataImportDeleteProgressFromMapTimerWithoutReplication(UUID importOperationId);
|
|
| 567 | -
|
|
| 568 | - /**
|
|
| 569 | - * For the reference to a remote sailing server, updates its events cache and returns the event list
|
|
| 570 | - * or, if fetching the event list from the remote server did fail, the exception for which it failed.
|
|
| 571 | - */
|
|
| 572 | - Util.Pair<Iterable<EventBase>, Exception> updateRemoteServerEventCacheSynchronously(RemoteSailingServerReference ref);
|
|
| 573 | -
|
|
| 574 | - /**
|
|
| 575 | - * Searches the content of this server, not that of any remote servers referenced by any {@link RemoteSailingServerReference}s.
|
|
| 576 | - */
|
|
| 577 | - @Override
|
|
| 578 | - Result<LeaderboardSearchResult> search(KeywordQuery query);
|
|
| 579 | -
|
|
| 580 | - /**
|
|
| 581 | - * Searches a specific remote server whose reference has the {@link RemoteSailingServerReference#getName() name}
|
|
| 582 | - * <code>remoteServerReferenceName</code>. If a remote server reference with that name is not known,
|
|
| 583 | - * <code>null</code> is returned. Otherwise, a non-<code>null</code> and possibly empty search result set is
|
|
| 584 | - * returned.
|
|
| 585 | - */
|
|
| 586 | - Result<LeaderboardSearchResultBase> searchRemotely(String remoteServerReferenceName, KeywordQuery query);
|
|
| 587 | -
|
|
| 588 | - /**
|
|
| 589 | - * Gets the configuration of the local sailing server instances.
|
|
| 590 | - */
|
|
| 591 | - SailingServerConfiguration getSailingServerConfiguration();
|
|
| 592 | -
|
|
| 593 | - void updateServerConfiguration(SailingServerConfiguration serverConfiguration);
|
|
| 594 | -
|
|
| 595 | - /**
|
|
| 596 | - * References to remote servers may be dead or alive. This is internally determined by regularly polling those
|
|
| 597 | - * servers for their events list. If the events list cannot be successfully retrieved, the server is considered "dead."
|
|
| 598 | - * This method returns the "live" server references.
|
|
| 599 | - */
|
|
| 600 | - Iterable<RemoteSailingServerReference> getLiveRemoteServerReferences();
|
|
| 601 | -
|
|
| 602 | - RemoteSailingServerReference getRemoteServerReferenceByName(String remoteServerReferenceName);
|
|
| 603 | -
|
|
| 604 | - void addRegattaWithoutReplication(Regatta regatta);
|
|
| 605 | -
|
|
| 606 | - void addEventWithoutReplication(Event event);
|
|
| 607 | -
|
|
| 608 | - /**
|
|
| 609 | - * Adds the leaderboard group to this service; if the group has an overall leaderboard, the overall leaderboard
|
|
| 610 | - * is added to this service as well. For both, the group and the overall leaderboard, any previously existing
|
|
| 611 | - * objects by the same name of that type will be replaced.
|
|
| 612 | - */
|
|
| 613 | - void addLeaderboardGroupWithoutReplication(LeaderboardGroup leaderboardGroup);
|
|
| 614 | -
|
|
| 615 | - /**
|
|
| 616 | - * @return {@code null} if no service can be found in the OSGi registry
|
|
| 617 | - */
|
|
| 618 | - FileStorageManagementService getFileStorageManagementService();
|
|
| 619 | -
|
|
| 620 | - ClassLoader getCombinedMasterDataClassLoader();
|
|
| 621 | -
|
|
| 622 | - Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint);
|
|
| 623 | -}
|
|
| 1 | +package com.sap.sailing.server; |
|
| 2 | + |
|
| 3 | +import java.io.IOException; |
|
| 4 | +import java.io.Serializable; |
|
| 5 | +import java.net.MalformedURLException; |
|
| 6 | +import java.net.SocketException; |
|
| 7 | +import java.net.URI; |
|
| 8 | +import java.net.URL; |
|
| 9 | +import java.util.Collection; |
|
| 10 | +import java.util.ConcurrentModificationException; |
|
| 11 | +import java.util.List; |
|
| 12 | +import java.util.Map; |
|
| 13 | +import java.util.UUID; |
|
| 14 | +import java.util.concurrent.ConcurrentHashMap; |
|
| 15 | + |
|
| 16 | +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; |
|
| 17 | +import com.sap.sailing.domain.abstractlog.race.RaceLog; |
|
| 18 | +import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; |
|
| 19 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; |
|
| 20 | +import com.sap.sailing.domain.base.Competitor; |
|
| 21 | +import com.sap.sailing.domain.base.CompetitorStore; |
|
| 22 | +import com.sap.sailing.domain.base.CourseArea; |
|
| 23 | +import com.sap.sailing.domain.base.DomainFactory; |
|
| 24 | +import com.sap.sailing.domain.base.Event; |
|
| 25 | +import com.sap.sailing.domain.base.EventBase; |
|
| 26 | +import com.sap.sailing.domain.base.Fleet; |
|
| 27 | +import com.sap.sailing.domain.base.LeaderboardSearchResult; |
|
| 28 | +import com.sap.sailing.domain.base.LeaderboardSearchResultBase; |
|
| 29 | +import com.sap.sailing.domain.base.Mark; |
|
| 30 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 31 | +import com.sap.sailing.domain.base.RaceDefinition; |
|
| 32 | +import com.sap.sailing.domain.base.Regatta; |
|
| 33 | +import com.sap.sailing.domain.base.RegattaRegistry; |
|
| 34 | +import com.sap.sailing.domain.base.RemoteSailingServerReference; |
|
| 35 | +import com.sap.sailing.domain.base.SailingServerConfiguration; |
|
| 36 | +import com.sap.sailing.domain.base.Series; |
|
| 37 | +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; |
|
| 38 | +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; |
|
| 39 | +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; |
|
| 40 | +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; |
|
| 41 | +import com.sap.sailing.domain.common.DataImportProgress; |
|
| 42 | +import com.sap.sailing.domain.common.Position; |
|
| 43 | +import com.sap.sailing.domain.common.RaceFetcher; |
|
| 44 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 45 | +import com.sap.sailing.domain.common.RegattaFetcher; |
|
| 46 | +import com.sap.sailing.domain.common.RegattaIdentifier; |
|
| 47 | +import com.sap.sailing.domain.common.RegattaName; |
|
| 48 | +import com.sap.sailing.domain.common.ScoringSchemeType; |
|
| 49 | +import com.sap.sailing.domain.common.media.MediaTrack; |
|
| 50 | +import com.sap.sailing.domain.common.racelog.RacingProcedureType; |
|
| 51 | +import com.sap.sailing.domain.leaderboard.EventResolver; |
|
| 52 | +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; |
|
| 53 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 54 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; |
|
| 55 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; |
|
| 56 | +import com.sap.sailing.domain.leaderboard.LeaderboardRegistry; |
|
| 57 | +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; |
|
| 58 | +import com.sap.sailing.domain.leaderboard.ScoringScheme; |
|
| 59 | +import com.sap.sailing.domain.persistence.DomainObjectFactory; |
|
| 60 | +import com.sap.sailing.domain.persistence.MongoObjectFactory; |
|
| 61 | +import com.sap.sailing.domain.polars.PolarDataService; |
|
| 62 | +import com.sap.sailing.domain.racelog.tracking.GPSFixStore; |
|
| 63 | +import com.sap.sailing.domain.ranking.RankingMetricConstructor; |
|
| 64 | +import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; |
|
| 65 | +import com.sap.sailing.domain.tracking.DynamicTrackedRace; |
|
| 66 | +import com.sap.sailing.domain.tracking.RaceListener; |
|
| 67 | +import com.sap.sailing.domain.tracking.RaceTracker; |
|
| 68 | +import com.sap.sailing.domain.tracking.TrackedRace; |
|
| 69 | +import com.sap.sailing.domain.tracking.TrackedRegatta; |
|
| 70 | +import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; |
|
| 71 | +import com.sap.sailing.domain.tracking.TrackerManager; |
|
| 72 | +import com.sap.sailing.domain.tracking.WindStore; |
|
| 73 | +import com.sap.sailing.server.masterdata.DataImportLockWithProgress; |
|
| 74 | +import com.sap.sailing.server.simulation.SimulationService; |
|
| 75 | +import com.sap.sse.common.TimePoint; |
|
| 76 | +import com.sap.sse.common.TypeBasedServiceFinderFactory; |
|
| 77 | +import com.sap.sse.common.Util; |
|
| 78 | +import com.sap.sse.common.Util.Triple; |
|
| 79 | +import com.sap.sse.common.search.KeywordQuery; |
|
| 80 | +import com.sap.sse.common.search.Result; |
|
| 81 | +import com.sap.sse.common.search.Searchable; |
|
| 82 | +import com.sap.sse.filestorage.FileStorageManagementService; |
|
| 83 | +import com.sap.sse.replication.impl.ReplicableWithObjectInputStream; |
|
| 84 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 85 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 86 | + |
|
| 87 | +/** |
|
| 88 | + * An OSGi service that can be used to track boat races using a TracTrac connector that pushes live GPS boat location, |
|
| 89 | + * waypoint, coarse and mark passing data. |
|
| 90 | + * <p> |
|
| 91 | + * |
|
| 92 | + * If a race/regatta is already being tracked, another {@link #addTracTracRace(URL, URI, URI, WindStore, long)} or |
|
| 93 | + * {@link #addRegatta(URL, URI, URI, WindStore, long)} call will have no effect, even if a different {@link WindStore} |
|
| 94 | + * is requested. |
|
| 95 | + * <p> |
|
| 96 | + * |
|
| 97 | + * When the tracking of a race/regatta is {@link #stopTracking(Regatta, RaceDefinition) stopped}, the next time it's |
|
| 98 | + * started to be tracked, a new {@link TrackedRace} at least will be constructed. This also means that when a |
|
| 99 | + * {@link TrackedRegatta} exists that still holds other {@link TrackedRace}s, the no longer tracked {@link TrackedRace} |
|
| 100 | + * will be removed from the {@link TrackedRegatta}. corresponding information is removed also from the |
|
| 101 | + * {@link DomainFactory}'s caches to ensure that clean, fresh data is received should another tracking request be issued |
|
| 102 | + * later. |
|
| 103 | + * <p> |
|
| 104 | + * |
|
| 105 | + * During receiving the initial load for a replication in {@link #initiallyFillFromInternal(java.io.ObjectInputStream)}, |
|
| 106 | + * tracked regattas read from the stream are observed (see {@link RaceListener}) by this object for automatic updates to |
|
| 107 | + * the default leaderboard and for automatic linking to leaderboard columns. It is assumed that no explicit replication |
|
| 108 | + * of these operations will happen based on the changes performed on the replication master. |
|
| 109 | + * |
|
| 110 | + * @author Axel Uhl (d043530) |
|
| 111 | + * |
|
| 112 | + */ |
|
| 113 | +public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher, |
|
| 114 | + LeaderboardRegistry, EventResolver, LeaderboardGroupResolver, TrackerManager, Searchable<LeaderboardSearchResult, KeywordQuery>, |
|
| 115 | + ReplicableWithObjectInputStream<RacingEventService, RacingEventServiceOperation<?>>, RaceLogResolver { |
|
| 116 | + @Override |
|
| 117 | + Regatta getRegatta(RegattaName regattaName); |
|
| 118 | + |
|
| 119 | + @Override |
|
| 120 | + RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier); |
|
| 121 | + |
|
| 122 | + DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race); |
|
| 123 | + |
|
| 124 | + DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier); |
|
| 125 | + |
|
| 126 | + /** |
|
| 127 | + * Obtains an unmodifiable map of the leaderboard configured in this service keyed by their names. |
|
| 128 | + */ |
|
| 129 | + Map<String, Leaderboard> getLeaderboards(); |
|
| 130 | + |
|
| 131 | + /** |
|
| 132 | + * @return a leaderboard whose {@link Leaderboard#getName()} method returns the value of the <code>name</code> |
|
| 133 | + * parameter, or <code>null</code> if no such leaderboard is known to this service |
|
| 134 | + */ |
|
| 135 | + Leaderboard getLeaderboardByName(String name); |
|
| 136 | + |
|
| 137 | + /** |
|
| 138 | + * Looks at the mark tracks in the tracked races attached to the <code>leaderboard</code>. If it doesn't find a |
|
| 139 | + * track for the <code>mark</code> requested there which has fixes before and after <code>timePoint</code> (to |
|
| 140 | + * ensure that no track cropping has taken place, removing the fixes for the interesting time period), looks in the |
|
| 141 | + * leaderboard's regatta log and the specific <code>raceLog</code> (if provided) or all race logs attached to the |
|
| 142 | + * leaderboard (if not provided) for device mappings for the mark and tries to load fixes from the |
|
| 143 | + * {@link GPSFixStore}. The latter is only necessary if the mark isn't found in any tracked race with fixes |
|
| 144 | + * surrounding <code>timePoint</code> because should there be a tracked race in the leaderboard that has the mark |
|
| 145 | + * then it will also have received the fixes from the {@link GPSFixStore} through the regatta log mapping. |
|
| 146 | + * <p> |
|
| 147 | + * |
|
| 148 | + * @return the position obtained by interpolation but never extrapolation from the track identified as described |
|
| 149 | + * above |
|
| 150 | + */ |
|
| 151 | + Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog); |
|
| 152 | + |
|
| 153 | + /** |
|
| 154 | + * Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta. |
|
| 155 | + * See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to |
|
| 156 | + * {@link #addTracTracRace(URL, URI, URI, WindStore, long)} with an equal combination of URLs/URIs, the {@link TracTracRaceTracker} |
|
| 157 | + * already tracking the race was re-used. The trackers will be stopped by this call regardless of how many calls |
|
| 158 | + * were made that ensured they were tracking. |
|
| 159 | + */ |
|
| 160 | + void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException; |
|
| 161 | + |
|
| 162 | + /** |
|
| 163 | + * Removes <code>race</code> and any corresponding {@link #getTrackedRace(Regatta, RaceDefinition) tracked race} |
|
| 164 | + * from this service. If it was the last {@link RaceDefinition} in its {@link Regatta} and the regatta |
|
| 165 | + * {@link Regatta#isPersistent() is not stored persistently}, the <code>regatta</code> is removed as well and will no |
|
| 166 | + * longer be returned by {@link #getAllRegattas()}. The wind tracking is stopped for <code>race</code>. |
|
| 167 | + * <p> |
|
| 168 | + * |
|
| 169 | + * Any {@link RaceTracker} for which <code>race</race> is the last race tracked that is still reachable |
|
| 170 | + * from {@link #getAllRegattas()} will be {@link RaceTracker#stop(boolean) stopped}. |
|
| 171 | + * |
|
| 172 | + * The <code>race</code> will be also removed from all leaderboards containing a column that has <code>race</code>'s |
|
| 173 | + * {@link #getTrackedRace(Regatta, RaceDefinition) corresponding} {@link TrackedRace} as its |
|
| 174 | + * {@link RaceColumn#getTrackedRace(Fleet)}. |
|
| 175 | + * |
|
| 176 | + * @param regatta |
|
| 177 | + * the regatta from which to remove the race |
|
| 178 | + * @param race |
|
| 179 | + * the race to remove |
|
| 180 | + */ |
|
| 181 | + void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,InterruptedException; |
|
| 182 | + |
|
| 183 | + /** |
|
| 184 | + * @param port |
|
| 185 | + * the UDP port on which to listen for incoming messages from Expedition clients |
|
| 186 | + * @param correctByDeclination |
|
| 187 | + * An optional service to convert the wind bearings (which the receiver may |
|
| 188 | + * believe to be true bearings) from magnetic to true bearings. |
|
| 189 | + * @throws SocketException |
|
| 190 | + * thrown, e.g., in case there is already another listener on the port requested |
|
| 191 | + */ |
|
| 192 | + void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws Exception; |
|
| 193 | + |
|
| 194 | + void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException; |
|
| 195 | + |
|
| 196 | + /** |
|
| 197 | + * The {@link Triple#getC() third component} of the triples returned is a wind tracker-specific |
|
| 198 | + * comment where a wind tracker may provide information such as its type name or, if applicable, |
|
| 199 | + * connectivity information such as the network port on which it receives wind information. |
|
| 200 | + */ |
|
| 201 | + Iterable<Util.Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces(); |
|
| 202 | + |
|
| 203 | + /** |
|
| 204 | + * Creates a new leaderboard with the <code>name</code> specified. |
|
| 205 | + * @param discardThresholds |
|
| 206 | + * Tells the thresholds from which on a next higher number of worst races will be discarded per |
|
| 207 | + * competitor. Example: <code>[3, 6]</code> means that starting from three races the single worst race |
|
| 208 | + * will be discarded; starting from six races, the two worst races per competitor are discarded. |
|
| 209 | + * |
|
| 210 | + * @return the leaderboard created |
|
| 211 | + */ |
|
| 212 | + FlexibleLeaderboard addFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringScheme scoringScheme, Serializable courseAreaId); |
|
| 213 | + |
|
| 214 | + RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, int[] discardThresholds); |
|
| 215 | + |
|
| 216 | + void removeLeaderboard(String leaderboardName); |
|
| 217 | + |
|
| 218 | + /** |
|
| 219 | + * Renames a leaderboard. If a leaderboard by the name <code>oldName</code> does not exist in {@link #getLeaderboards()}, |
|
| 220 | + * or if a leaderboard with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown. |
|
| 221 | + * If the method completes normally, the rename has been successful, and the leaderboard previously obtained by calling |
|
| 222 | + * {@link #getLeaderboardByName(String) getLeaderboardByName(oldName)} can now be obtained by calling |
|
| 223 | + * {@link #getLeaderboardByName(String) getLeaderboardByName(newName)}. |
|
| 224 | + */ |
|
| 225 | + void renameLeaderboard(String oldName, String newName); |
|
| 226 | + |
|
| 227 | + RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace); |
|
| 228 | + |
|
| 229 | + void moveLeaderboardColumnUp(String leaderboardName, String columnName); |
|
| 230 | + |
|
| 231 | + void moveLeaderboardColumnDown(String leaderboardName, String columnName); |
|
| 232 | + |
|
| 233 | + void removeLeaderboardColumn(String leaderboardName, String columnName); |
|
| 234 | + |
|
| 235 | + void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName); |
|
| 236 | + |
|
| 237 | + /** |
|
| 238 | + * @see RaceColumn#setFactor(Double) |
|
| 239 | + */ |
|
| 240 | + void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor); |
|
| 241 | + |
|
| 242 | + /** |
|
| 243 | + * Updates the leaderboard data in the persistent store |
|
| 244 | + */ |
|
| 245 | + void updateStoredLeaderboard(Leaderboard leaderboard); |
|
| 246 | + |
|
| 247 | + void updateStoredRegatta(Regatta regatta); |
|
| 248 | + |
|
| 249 | + void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException; |
|
| 250 | + |
|
| 251 | + /** |
|
| 252 | + * Removes the regatta as well as all regatta leaderboards for that regatta |
|
| 253 | + */ |
|
| 254 | + void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException; |
|
| 255 | + |
|
| 256 | + /** |
|
| 257 | + * Removes the given series |
|
| 258 | + */ |
|
| 259 | + void removeSeries(Series series) throws MalformedURLException, IOException, InterruptedException; |
|
| 260 | + |
|
| 261 | + DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier); |
|
| 262 | + |
|
| 263 | + /** |
|
| 264 | + * Obtains an unmodifiable map of the leaderboard groups configured in this service keyed by their names. |
|
| 265 | + */ |
|
| 266 | + Map<String, LeaderboardGroup> getLeaderboardGroups(); |
|
| 267 | + |
|
| 268 | + /** |
|
| 269 | + * Creates a new group with the name <code>groupName</code>, the description <code>desciption</code> and the |
|
| 270 | + * leaderboards with the names in <code>leaderboardNames</code> and saves it in the database. |
|
| 271 | + * @param id TODO |
|
| 272 | + * @param groupName |
|
| 273 | + * The name of the new group |
|
| 274 | + * @param description |
|
| 275 | + * The description of the new group |
|
| 276 | + * @param displayName TODO |
|
| 277 | + * @param displayGroupsInReverseOrder TODO |
|
| 278 | + * @param leaderboardNames |
|
| 279 | + * The names of the leaderboards, which should be contained by the new group.<br /> |
|
| 280 | + * If there isn't a leaderboard with one of these names an {@link IllegalArgumentException} is thrown. |
|
| 281 | + * @return The new leaderboard group |
|
| 282 | + */ |
|
| 283 | + LeaderboardGroup addLeaderboardGroup(UUID id, String groupName, String description, |
|
| 284 | + String displayName, boolean displayGroupsInReverseOrder, List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType); |
|
| 285 | + |
|
| 286 | + /** |
|
| 287 | + * Removes the group with the name <code>groupName</code> from the service and the database. |
|
| 288 | + * @param groupName The name of the group which shall be removed. |
|
| 289 | + */ |
|
| 290 | + void removeLeaderboardGroup(String groupName); |
|
| 291 | + |
|
| 292 | + /** |
|
| 293 | + * Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br /> |
|
| 294 | + * If there's no group with the name <code>oldName</code> or there's already a group with the name |
|
| 295 | + * <code>newName</code> a {@link IllegalArgumentException} is thrown. |
|
| 296 | + * |
|
| 297 | + * @param oldName The old name of the group |
|
| 298 | + * @param newName The new name of the group |
|
| 299 | + */ |
|
| 300 | + void renameLeaderboardGroup(String oldName, String newName); |
|
| 301 | + |
|
| 302 | + /** |
|
| 303 | + * Updates the group data in the persistant store. |
|
| 304 | + */ |
|
| 305 | + void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup); |
|
| 306 | + |
|
| 307 | + DynamicTrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore, GPSFixStore gpsFixStore, |
|
| 308 | + long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, boolean useMarkPassingCalculator); |
|
| 309 | + |
|
| 310 | + Regatta getOrCreateDefaultRegatta(String name, String boatClassName, Serializable id); |
|
| 311 | + |
|
| 312 | + /** |
|
| 313 | + * @param series the series must not have any {@link RaceColumn}s yet |
|
| 314 | + */ |
|
| 315 | + Regatta createRegatta(String regattaName, String boatClassName, TimePoint startDate, TimePoint endDate, Serializable id, Iterable<? extends Series> series, |
|
| 316 | + boolean persistent, ScoringScheme scoringScheme, Serializable defaultCourseAreaId, |
|
| 317 | + boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor); |
|
| 318 | + |
|
| 319 | + Regatta updateRegatta(RegattaIdentifier regattaIdentifier, TimePoint startDate, TimePoint endDate, Serializable newDefaultCourseAreaId, RegattaConfiguration regattaConfiguration, Iterable<? extends Series> series, boolean useStartTimeInference); |
|
| 320 | + |
|
| 321 | + /** |
|
| 322 | + * Adds <code>raceDefinition</code> to the {@link Regatta} such that it will appear in {@link Regatta#getAllRaces()} |
|
| 323 | + * and {@link Regatta#getRaceByName(String)}. |
|
| 324 | + * |
|
| 325 | + * @param addToRegatta identifier of an regatta that must exist already |
|
| 326 | + */ |
|
| 327 | + void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition); |
|
| 328 | + |
|
| 329 | + void updateLeaderboardGroup(String oldName, String newName, String description, String displayName, |
|
| 330 | + List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType); |
|
| 331 | + |
|
| 332 | + /** |
|
| 333 | + * @return a thread-safe copy of the events currently known by the service; it's safe for callers to iterate over |
|
| 334 | + * the iterable returned, and no risk of a {@link ConcurrentModificationException} exists |
|
| 335 | + */ |
|
| 336 | + Iterable<Event> getAllEvents(); |
|
| 337 | + |
|
| 338 | + /** |
|
| 339 | + * Creates a new event with the name <code>eventName</code>, the venue <code>venue</code> and the regattas with the |
|
| 340 | + * names in <code>regattaNames</code>, saves it in the database and replicates it. Use for TESTING only! |
|
| 341 | + * |
|
| 342 | + * @param eventName |
|
| 343 | + * The name of the new event |
|
| 344 | + * @param eventDescription TODO |
|
| 345 | + * @param startDate |
|
| 346 | + * The start date of the event |
|
| 347 | + * @param endDate |
|
| 348 | + * The end date of the event |
|
| 349 | + * @param isPublic |
|
| 350 | + * Indicates whether the event is public accessible via the publication URL or not |
|
| 351 | + * @param id |
|
| 352 | + * The id of the new event |
|
| 353 | + * @param venue |
|
| 354 | + * The name of the venue of the new event |
|
| 355 | + * @return The new event |
|
| 356 | + */ |
|
| 357 | + Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venueName, boolean isPublic, UUID id); |
|
| 358 | + |
|
| 359 | + /** |
|
| 360 | + * Updates a sailing event with the name <code>eventName</code>, the venue<code>venue</code> and the regattas with |
|
| 361 | + * the names in <code>regattaNames</code> and updates it in the database. |
|
| 362 | + * @param eventName |
|
| 363 | + * The name of the event to update |
|
| 364 | + * @param startDate |
|
| 365 | + * The start date of the event |
|
| 366 | + * @param endDate |
|
| 367 | + * The end date of the event |
|
| 368 | + * @param venueName |
|
| 369 | + * The name of the venue of the event |
|
| 370 | + * @param isPublic |
|
| 371 | + * Indicates whether the event is public accessible via the publication URL or not |
|
| 372 | + * @return The new event |
|
| 373 | + */ |
|
| 374 | + void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, |
|
| 375 | + String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, |
|
| 376 | + Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos); |
|
| 377 | + |
|
| 378 | + /** |
|
| 379 | + * Renames a sailing event. If a sailing event by the name <code>oldName</code> does not exist in {@link #getEvents()}, |
|
| 380 | + * or if a event with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown. |
|
| 381 | + * If the method completes normally, the rename has been successful, and the event previously obtained by calling |
|
| 382 | + * {@link #getEventByName(String) getEventByName(oldName)} can now be obtained by calling |
|
| 383 | + * {@link #getEventByName(String) getEventByName(newName)}. |
|
| 384 | + */ |
|
| 385 | + void renameEvent(UUID id, String newEventName); |
|
| 386 | + |
|
| 387 | + void removeEvent(UUID id); |
|
| 388 | + |
|
| 389 | + |
|
| 390 | + /** |
|
| 391 | + * @return a thread-safe copy of the events (or the exception that occurred trying to obtain the events; arranged in |
|
| 392 | + * a {@link Util.Pair}) of from all sailing server instances currently known by the service; it's safe for |
|
| 393 | + * callers to iterate over the iterable returned, and no risk of a {@link ConcurrentModificationException} |
|
| 394 | + * exists |
|
| 395 | + */ |
|
| 396 | + Map<RemoteSailingServerReference, Util.Pair<Iterable<EventBase>, Exception>> getPublicEventsOfAllSailingServers(); |
|
| 397 | + |
|
| 398 | + RemoteSailingServerReference addRemoteSailingServerReference(String name, URL url); |
|
| 399 | + |
|
| 400 | + void removeRemoteSailingServerReference(String name); |
|
| 401 | + |
|
| 402 | + |
|
| 403 | + CourseArea[] addCourseAreas(UUID eventId, String[] courseAreaNames, UUID[] courseAreaIds); |
|
| 404 | + |
|
| 405 | + com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory(); |
|
| 406 | + |
|
| 407 | + CourseArea getCourseArea(Serializable courseAreaId); |
|
| 408 | + |
|
| 409 | + /** |
|
| 410 | + * Adds the specified mediaTrack to the in-memory media library. |
|
| 411 | + * Important note: Only if mediaTrack.dbId != null the mediaTrack will be persisted in the the database. |
|
| 412 | + * @param mediaTrack |
|
| 413 | + */ |
|
| 414 | + void mediaTrackAdded(MediaTrack mediaTrack); |
|
| 415 | + |
|
| 416 | + /** |
|
| 417 | + * Calling mediaTrackAdded for every entry in the specified collection. |
|
| 418 | + * @param mediaTracks |
|
| 419 | + */ |
|
| 420 | + void mediaTracksAdded(Collection<MediaTrack> mediaTracks); |
|
| 421 | + |
|
| 422 | + void mediaTrackTitleChanged(MediaTrack mediaTrack); |
|
| 423 | + |
|
| 424 | + void mediaTrackUrlChanged(MediaTrack mediaTrack); |
|
| 425 | + |
|
| 426 | + void mediaTrackStartTimeChanged(MediaTrack mediaTrack); |
|
| 427 | + |
|
| 428 | + void mediaTrackDurationChanged(MediaTrack mediaTrack); |
|
| 429 | + |
|
| 430 | + void mediaTrackAssignedRacesChanged(MediaTrack mediaTrack); |
|
| 431 | + |
|
| 432 | + void mediaTrackDeleted(MediaTrack mediaTrack); |
|
| 433 | + |
|
| 434 | + /** |
|
| 435 | + * In contrast to mediaTracksAdded, this method takes mediaTracks with a given dbId. |
|
| 436 | + * Checks if the track already exists in the library and the database and adds/stores it |
|
| 437 | + * accordingly. If a track already exists and override, its properties are checked for changes |
|
| 438 | + * @param mediaTrack |
|
| 439 | + * @param override If true, track properties (title, url, start time, duration, not mime type!) will be |
|
| 440 | + * overwritten with the values from the track to be imported. |
|
| 441 | + */ |
|
| 442 | + void mediaTracksImported(Collection<MediaTrack> mediaTracksToImport, boolean override); |
|
| 443 | + |
|
| 444 | + Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier); |
|
| 445 | + |
|
| 446 | + Collection<MediaTrack> getMediaTracksInTimeRange(RegattaAndRaceIdentifier regattaAndRaceIdentifier); |
|
| 447 | + |
|
| 448 | + Collection<MediaTrack> getAllMediaTracks(); |
|
| 449 | + |
|
| 450 | + void reloadRaceLog(String leaderboardName, String raceColumnName, String fleetName); |
|
| 451 | + |
|
| 452 | + RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName); |
|
| 453 | + |
|
| 454 | + /** |
|
| 455 | + * @param rankingMetricConstructor TODO |
|
| 456 | + * @return a pair with the found or created regatta, and a boolean that tells whether the regatta was created during |
|
| 457 | + * the call |
|
| 458 | + */ |
|
| 459 | + Util.Pair<Regatta, Boolean> getOrCreateRegattaWithoutReplication(String fullRegattaName, String boatClassName, |
|
| 460 | + TimePoint startDate, TimePoint endDate, Serializable id, |
|
| 461 | + Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme, |
|
| 462 | + Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor); |
|
| 463 | + |
|
| 464 | + /** |
|
| 465 | + * @return map where keys are the toString() representation of the {@link RaceDefinition#getId() IDs} of races passed to |
|
| 466 | + * {@link #setRegattaForRace(Regatta, RaceDefinition)}. It helps remember the connection between races and regattas. |
|
| 467 | + */ |
|
| 468 | + ConcurrentHashMap<String, Regatta> getPersistentRegattasForRaceIDs(); |
|
| 469 | + |
|
| 470 | + Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, |
|
| 471 | + boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, Iterable<ImageDescriptor> images, |
|
| 472 | + Iterable<VideoDescriptor> videos); |
|
| 473 | + |
|
| 474 | + void setRegattaForRace(Regatta regatta, String raceIdAsString); |
|
| 475 | + |
|
| 476 | + CourseArea[] addCourseAreasWithoutReplication(UUID eventId, UUID[] courseAreaIds, String[] courseAreaNames); |
|
| 477 | + |
|
| 478 | + CourseArea[] removeCourseAreaWithoutReplication(UUID eventId, UUID[] courseAreaIds); |
|
| 479 | + |
|
| 480 | + /** |
|
| 481 | + * Returns a mobile device's configuration. |
|
| 482 | + * @param identifier of the client (may include event) |
|
| 483 | + * @return the {@link DeviceConfiguration} |
|
| 484 | + */ |
|
| 485 | + DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier); |
|
| 486 | + |
|
| 487 | + /** |
|
| 488 | + * Adds a device configuration. |
|
| 489 | + * @param matcher defining for which the configuration applies. |
|
| 490 | + * @param configuration of the device. |
|
| 491 | + */ |
|
| 492 | + void createOrUpdateDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration); |
|
| 493 | + |
|
| 494 | + /** |
|
| 495 | + * Removes a configuration by its matching object. |
|
| 496 | + * @param matcher |
|
| 497 | + */ |
|
| 498 | + void removeDeviceConfiguration(DeviceConfigurationMatcher matcher); |
|
| 499 | + |
|
| 500 | + /** |
|
| 501 | + * Returns all configurations and their matching objects. |
|
| 502 | + * @return the {@link DeviceConfiguration}s. |
|
| 503 | + */ |
|
| 504 | + Map<DeviceConfigurationMatcher, DeviceConfiguration> getAllDeviceConfigurations(); |
|
| 505 | + |
|
| 506 | + /** |
|
| 507 | + * Forces a new start time on the RaceLog identified by the passed parameters. |
|
| 508 | + * @param leaderboardName name of the RaceLog's leaderboard. |
|
| 509 | + * @param raceColumnName name of the RaceLog's column |
|
| 510 | + * @param fleetName name of the RaceLog's fleet |
|
| 511 | + * @param authorName name of the {@link AbstractLogEventAuthor} the {@link RaceLogStartTimeEvent} will be created with |
|
| 512 | + * @param authorPriority priority of the author. |
|
| 513 | + * @param passId Pass identifier of the new start time event. |
|
| 514 | + * @param logicalTimePoint logical {@link TimePoint} of the new event. |
|
| 515 | + * @param startTime the new Start-Time |
|
| 516 | + * @return |
|
| 517 | + */ |
|
| 518 | + TimePoint setStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName, String authorName, |
|
| 519 | + int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime, RacingProcedureType racingProcedure); |
|
| 520 | + |
|
| 521 | + /** |
|
| 522 | + * Gets the start time, pass identifier and racing procedure for the queried race. Start time might be <code>null</code>. |
|
| 523 | + */ |
|
| 524 | + Util.Triple<TimePoint, Integer, RacingProcedureType> getStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName); |
|
| 525 | + |
|
| 526 | + MongoObjectFactory getMongoObjectFactory(); |
|
| 527 | + |
|
| 528 | + DomainObjectFactory getDomainObjectFactory(); |
|
| 529 | + |
|
| 530 | + WindStore getWindStore(); |
|
| 531 | + |
|
| 532 | + PolarDataService getPolarDataService(); |
|
| 533 | + |
|
| 534 | + SimulationService getSimulationService(); |
|
| 535 | + |
|
| 536 | + GPSFixStore getGPSFixStore(); |
|
| 537 | + |
|
| 538 | + RaceTracker getRaceTrackerById(Object id); |
|
| 539 | + |
|
| 540 | + AbstractLogEventAuthor getServerAuthor(); |
|
| 541 | + |
|
| 542 | + CompetitorStore getCompetitorStore(); |
|
| 543 | + |
|
| 544 | + TypeBasedServiceFinderFactory getTypeBasedServiceFinderFactory(); |
|
| 545 | + |
|
| 546 | + /** |
|
| 547 | + * This lock exists to allow only one master data import at a time to avoid situation where multiple Imports |
|
| 548 | + * override each other in unpredictable fashion |
|
| 549 | + */ |
|
| 550 | + DataImportLockWithProgress getDataImportLock(); |
|
| 551 | + |
|
| 552 | + DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId, |
|
| 553 | + double overallProgressPct, |
|
| 554 | + String subProgressName, double subProgressPct); |
|
| 555 | + |
|
| 556 | + DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId, |
|
| 557 | + double overallProgressPct, |
|
| 558 | + String subProgressName, double subProgressPct); |
|
| 559 | + |
|
| 560 | + void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage); |
|
| 561 | + |
|
| 562 | + void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage); |
|
| 563 | + |
|
| 564 | + void setDataImportDeleteProgressFromMapTimerWithReplication(UUID importOperationId); |
|
| 565 | + |
|
| 566 | + void setDataImportDeleteProgressFromMapTimerWithoutReplication(UUID importOperationId); |
|
| 567 | + |
|
| 568 | + /** |
|
| 569 | + * For the reference to a remote sailing server, updates its events cache and returns the event list |
|
| 570 | + * or, if fetching the event list from the remote server did fail, the exception for which it failed. |
|
| 571 | + */ |
|
| 572 | + Util.Pair<Iterable<EventBase>, Exception> updateRemoteServerEventCacheSynchronously(RemoteSailingServerReference ref); |
|
| 573 | + |
|
| 574 | + /** |
|
| 575 | + * Searches the content of this server, not that of any remote servers referenced by any {@link RemoteSailingServerReference}s. |
|
| 576 | + */ |
|
| 577 | + @Override |
|
| 578 | + Result<LeaderboardSearchResult> search(KeywordQuery query); |
|
| 579 | + |
|
| 580 | + /** |
|
| 581 | + * Searches a specific remote server whose reference has the {@link RemoteSailingServerReference#getName() name} |
|
| 582 | + * <code>remoteServerReferenceName</code>. If a remote server reference with that name is not known, |
|
| 583 | + * <code>null</code> is returned. Otherwise, a non-<code>null</code> and possibly empty search result set is |
|
| 584 | + * returned. |
|
| 585 | + */ |
|
| 586 | + Result<LeaderboardSearchResultBase> searchRemotely(String remoteServerReferenceName, KeywordQuery query); |
|
| 587 | + |
|
| 588 | + /** |
|
| 589 | + * Gets the configuration of the local sailing server instances. |
|
| 590 | + */ |
|
| 591 | + SailingServerConfiguration getSailingServerConfiguration(); |
|
| 592 | + |
|
| 593 | + void updateServerConfiguration(SailingServerConfiguration serverConfiguration); |
|
| 594 | + |
|
| 595 | + /** |
|
| 596 | + * References to remote servers may be dead or alive. This is internally determined by regularly polling those |
|
| 597 | + * servers for their events list. If the events list cannot be successfully retrieved, the server is considered "dead." |
|
| 598 | + * This method returns the "live" server references. |
|
| 599 | + */ |
|
| 600 | + Iterable<RemoteSailingServerReference> getLiveRemoteServerReferences(); |
|
| 601 | + |
|
| 602 | + RemoteSailingServerReference getRemoteServerReferenceByName(String remoteServerReferenceName); |
|
| 603 | + |
|
| 604 | + void addRegattaWithoutReplication(Regatta regatta); |
|
| 605 | + |
|
| 606 | + void addEventWithoutReplication(Event event); |
|
| 607 | + |
|
| 608 | + /** |
|
| 609 | + * Adds the leaderboard group to this service; if the group has an overall leaderboard, the overall leaderboard |
|
| 610 | + * is added to this service as well. For both, the group and the overall leaderboard, any previously existing |
|
| 611 | + * objects by the same name of that type will be replaced. |
|
| 612 | + */ |
|
| 613 | + void addLeaderboardGroupWithoutReplication(LeaderboardGroup leaderboardGroup); |
|
| 614 | + |
|
| 615 | + /** |
|
| 616 | + * @return {@code null} if no service can be found in the OSGi registry |
|
| 617 | + */ |
|
| 618 | + FileStorageManagementService getFileStorageManagementService(); |
|
| 619 | + |
|
| 620 | + ClassLoader getCombinedMasterDataClassLoader(); |
|
| 621 | + |
|
| 622 | + Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint); |
|
| 623 | +} |
java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
| ... | ... | @@ -1,3344 +1,3344 @@ |
| 1 | -package com.sap.sailing.server.impl;
|
|
| 2 | -
|
|
| 3 | -import java.io.BufferedReader;
|
|
| 4 | -import java.io.IOException;
|
|
| 5 | -import java.io.InputStream;
|
|
| 6 | -import java.io.InputStreamReader;
|
|
| 7 | -import java.io.ObjectInputStream;
|
|
| 8 | -import java.io.ObjectOutputStream;
|
|
| 9 | -import java.io.Serializable;
|
|
| 10 | -import java.net.MalformedURLException;
|
|
| 11 | -import java.net.SocketException;
|
|
| 12 | -import java.net.URL;
|
|
| 13 | -import java.net.URLConnection;
|
|
| 14 | -import java.net.URLEncoder;
|
|
| 15 | -import java.util.ArrayList;
|
|
| 16 | -import java.util.Arrays;
|
|
| 17 | -import java.util.Collection;
|
|
| 18 | -import java.util.Collections;
|
|
| 19 | -import java.util.Comparator;
|
|
| 20 | -import java.util.HashMap;
|
|
| 21 | -import java.util.HashSet;
|
|
| 22 | -import java.util.Iterator;
|
|
| 23 | -import java.util.LinkedHashMap;
|
|
| 24 | -import java.util.List;
|
|
| 25 | -import java.util.Map;
|
|
| 26 | -import java.util.Map.Entry;
|
|
| 27 | -import java.util.Set;
|
|
| 28 | -import java.util.UUID;
|
|
| 29 | -import java.util.concurrent.ConcurrentHashMap;
|
|
| 30 | -import java.util.concurrent.Executor;
|
|
| 31 | -import java.util.concurrent.Executors;
|
|
| 32 | -import java.util.concurrent.LinkedBlockingQueue;
|
|
| 33 | -import java.util.concurrent.ScheduledExecutorService;
|
|
| 34 | -import java.util.concurrent.ScheduledFuture;
|
|
| 35 | -import java.util.concurrent.ThreadPoolExecutor;
|
|
| 36 | -import java.util.concurrent.TimeUnit;
|
|
| 37 | -import java.util.function.Function;
|
|
| 38 | -import java.util.logging.Level;
|
|
| 39 | -import java.util.logging.Logger;
|
|
| 40 | -
|
|
| 41 | -import org.json.simple.JSONArray;
|
|
| 42 | -import org.json.simple.JSONObject;
|
|
| 43 | -import org.json.simple.parser.JSONParser;
|
|
| 44 | -import org.json.simple.parser.ParseException;
|
|
| 45 | -import org.osgi.framework.BundleContext;
|
|
| 46 | -import org.osgi.framework.ServiceReference;
|
|
| 47 | -import org.osgi.util.tracker.ServiceTracker;
|
|
| 48 | -
|
|
| 49 | -import com.sap.sailing.domain.abstractlog.AbstractLog;
|
|
| 50 | -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
|
| 51 | -import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
|
| 52 | -import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
|
| 53 | -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
|
| 54 | -import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
|
| 55 | -import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
|
|
| 56 | -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
|
| 57 | -import com.sap.sailing.domain.abstractlog.race.state.RaceState;
|
|
| 58 | -import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
|
|
| 59 | -import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
|
|
| 60 | -import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
|
|
| 61 | -import com.sap.sailing.domain.base.Competitor;
|
|
| 62 | -import com.sap.sailing.domain.base.CompetitorStore;
|
|
| 63 | -import com.sap.sailing.domain.base.CompetitorStore.CompetitorUpdateListener;
|
|
| 64 | -import com.sap.sailing.domain.base.ControlPoint;
|
|
| 65 | -import com.sap.sailing.domain.base.CourseArea;
|
|
| 66 | -import com.sap.sailing.domain.base.DomainFactory;
|
|
| 67 | -import com.sap.sailing.domain.base.Event;
|
|
| 68 | -import com.sap.sailing.domain.base.EventBase;
|
|
| 69 | -import com.sap.sailing.domain.base.EventFetcher;
|
|
| 70 | -import com.sap.sailing.domain.base.Fleet;
|
|
| 71 | -import com.sap.sailing.domain.base.LeaderboardSearchResult;
|
|
| 72 | -import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
|
|
| 73 | -import com.sap.sailing.domain.base.Mark;
|
|
| 74 | -import com.sap.sailing.domain.base.RaceColumn;
|
|
| 75 | -import com.sap.sailing.domain.base.RaceColumnInSeries;
|
|
| 76 | -import com.sap.sailing.domain.base.RaceDefinition;
|
|
| 77 | -import com.sap.sailing.domain.base.Regatta;
|
|
| 78 | -import com.sap.sailing.domain.base.RegattaListener;
|
|
| 79 | -import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
|
| 80 | -import com.sap.sailing.domain.base.SailingServerConfiguration;
|
|
| 81 | -import com.sap.sailing.domain.base.Series;
|
|
| 82 | -import com.sap.sailing.domain.base.Sideline;
|
|
| 83 | -import com.sap.sailing.domain.base.Waypoint;
|
|
| 84 | -import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
|
|
| 85 | -import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier;
|
|
| 86 | -import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
|
|
| 87 | -import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
|
| 88 | -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMapImpl;
|
|
| 89 | -import com.sap.sailing.domain.base.impl.DynamicCompetitor;
|
|
| 90 | -import com.sap.sailing.domain.base.impl.EventImpl;
|
|
| 91 | -import com.sap.sailing.domain.base.impl.RegattaImpl;
|
|
| 92 | -import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl;
|
|
| 93 | -import com.sap.sailing.domain.common.DataImportProgress;
|
|
| 94 | -import com.sap.sailing.domain.common.Distance;
|
|
| 95 | -import com.sap.sailing.domain.common.Position;
|
|
| 96 | -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
|
| 97 | -import com.sap.sailing.domain.common.RegattaIdentifier;
|
|
| 98 | -import com.sap.sailing.domain.common.RegattaName;
|
|
| 99 | -import com.sap.sailing.domain.common.Renamable;
|
|
| 100 | -import com.sap.sailing.domain.common.ScoringSchemeType;
|
|
| 101 | -import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
|
| 102 | -import com.sap.sailing.domain.common.Wind;
|
|
| 103 | -import com.sap.sailing.domain.common.WindSource;
|
|
| 104 | -import com.sap.sailing.domain.common.dto.FleetDTO;
|
|
| 105 | -import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO;
|
|
| 106 | -import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO;
|
|
| 107 | -import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
|
|
| 108 | -import com.sap.sailing.domain.common.media.MediaTrack;
|
|
| 109 | -import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
|
| 110 | -import com.sap.sailing.domain.common.tracking.GPSFix;
|
|
| 111 | -import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
|
| 112 | -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
|
| 113 | -import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
|
| 114 | -import com.sap.sailing.domain.leaderboard.Leaderboard;
|
|
| 115 | -import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
|
| 116 | -import com.sap.sailing.domain.leaderboard.LeaderboardRegistry;
|
|
| 117 | -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
|
| 118 | -import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
|
| 119 | -import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
|
| 120 | -import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
|
| 121 | -import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
|
| 122 | -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
|
| 123 | -import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
|
|
| 124 | -import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
|
| 125 | -import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
|
| 126 | -import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
|
| 127 | -import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
|
|
| 128 | -import com.sap.sailing.domain.persistence.MongoWindStore;
|
|
| 129 | -import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
|
| 130 | -import com.sap.sailing.domain.persistence.PersistenceFactory;
|
|
| 131 | -import com.sap.sailing.domain.persistence.media.MediaDB;
|
|
| 132 | -import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
|
| 133 | -import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory;
|
|
| 134 | -import com.sap.sailing.domain.polars.PolarDataService;
|
|
| 135 | -import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
|
| 136 | -import com.sap.sailing.domain.racelog.RaceLogStore;
|
|
| 137 | -import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
|
| 138 | -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
|
| 139 | -import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo;
|
|
| 140 | -import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
|
| 141 | -import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
|
| 142 | -import com.sap.sailing.domain.regattalike.HasRegattaLike;
|
|
| 143 | -import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
|
| 144 | -import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
|
|
| 145 | -import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
|
| 146 | -import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
|
| 147 | -import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
|
| 148 | -import com.sap.sailing.domain.tracking.GPSFixTrack;
|
|
| 149 | -import com.sap.sailing.domain.tracking.MarkPassing;
|
|
| 150 | -import com.sap.sailing.domain.tracking.RaceChangeListener;
|
|
| 151 | -import com.sap.sailing.domain.tracking.RaceHandle;
|
|
| 152 | -import com.sap.sailing.domain.tracking.RaceListener;
|
|
| 153 | -import com.sap.sailing.domain.tracking.RaceTracker;
|
|
| 154 | -import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
|
| 155 | -import com.sap.sailing.domain.tracking.TrackedRace;
|
|
| 156 | -import com.sap.sailing.domain.tracking.TrackedRaceStatus;
|
|
| 157 | -import com.sap.sailing.domain.tracking.TrackedRegatta;
|
|
| 158 | -import com.sap.sailing.domain.tracking.WindStore;
|
|
| 159 | -import com.sap.sailing.domain.tracking.WindTracker;
|
|
| 160 | -import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
|
| 161 | -import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
|
| 162 | -import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
|
|
| 163 | -import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
|
| 164 | -import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
|
| 165 | -import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
|
|
| 166 | -import com.sap.sailing.server.RacingEventService;
|
|
| 167 | -import com.sap.sailing.server.Replicator;
|
|
| 168 | -import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
|
|
| 169 | -import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
|
|
| 170 | -import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer;
|
|
| 171 | -import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardSearchResultBaseJsonDeserializer;
|
|
| 172 | -import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer;
|
|
| 173 | -import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
|
| 174 | -import com.sap.sailing.server.operationaltransformation.AddCourseAreas;
|
|
| 175 | -import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
|
|
| 176 | -import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation;
|
|
| 177 | -import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
|
|
| 178 | -import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
|
|
| 179 | -import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
|
| 180 | -import com.sap.sailing.server.operationaltransformation.CreateEvent;
|
|
| 181 | -import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDataImportProgress;
|
|
| 182 | -import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDeviceConfiguration;
|
|
| 183 | -import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
|
| 184 | -import com.sap.sailing.server.operationaltransformation.DataImportFailed;
|
|
| 185 | -import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix;
|
|
| 186 | -import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
|
|
| 187 | -import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFixForExistingTrack;
|
|
| 188 | -import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFixForNewMarkTrack;
|
|
| 189 | -import com.sap.sailing.server.operationaltransformation.RecordWindFix;
|
|
| 190 | -import com.sap.sailing.server.operationaltransformation.RemoveDeviceConfiguration;
|
|
| 191 | -import com.sap.sailing.server.operationaltransformation.RemoveEvent;
|
|
| 192 | -import com.sap.sailing.server.operationaltransformation.RemoveMediaTrackOperation;
|
|
| 193 | -import com.sap.sailing.server.operationaltransformation.RemoveWindFix;
|
|
| 194 | -import com.sap.sailing.server.operationaltransformation.RenameEvent;
|
|
| 195 | -import com.sap.sailing.server.operationaltransformation.SetDataImportDeleteProgressFromMapTimer;
|
|
| 196 | -import com.sap.sailing.server.operationaltransformation.TrackRegatta;
|
|
| 197 | -import com.sap.sailing.server.operationaltransformation.UpdateCompetitor;
|
|
| 198 | -import com.sap.sailing.server.operationaltransformation.UpdateEndOfTracking;
|
|
| 199 | -import com.sap.sailing.server.operationaltransformation.UpdateMarkPassings;
|
|
| 200 | -import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackDurationOperation;
|
|
| 201 | -import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackRacesOperation;
|
|
| 202 | -import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackStartTimeOperation;
|
|
| 203 | -import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackTitleOperation;
|
|
| 204 | -import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackUrlOperation;
|
|
| 205 | -import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive;
|
|
| 206 | -import com.sap.sailing.server.operationaltransformation.UpdateStartOfTracking;
|
|
| 207 | -import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived;
|
|
| 208 | -import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
|
|
| 209 | -import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
|
|
| 210 | -import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
|
|
| 211 | -import com.sap.sailing.server.simulation.SimulationService;
|
|
| 212 | -import com.sap.sailing.server.simulation.SimulationServiceFactory;
|
|
| 213 | -import com.sap.sse.ServerInfo;
|
|
| 214 | -import com.sap.sse.common.TimePoint;
|
|
| 215 | -import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
|
| 216 | -import com.sap.sse.common.Util;
|
|
| 217 | -import com.sap.sse.common.Util.Pair;
|
|
| 218 | -import com.sap.sse.common.Util.Triple;
|
|
| 219 | -import com.sap.sse.common.impl.MillisecondsTimePoint;
|
|
| 220 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 221 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 222 | -import com.sap.sse.common.search.KeywordQuery;
|
|
| 223 | -import com.sap.sse.common.search.Result;
|
|
| 224 | -import com.sap.sse.common.search.ResultImpl;
|
|
| 225 | -import com.sap.sse.concurrent.LockUtil;
|
|
| 226 | -import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
|
| 227 | -import com.sap.sse.filestorage.FileStorageManagementService;
|
|
| 228 | -import com.sap.sse.replication.OperationExecutionListener;
|
|
| 229 | -import com.sap.sse.replication.OperationWithResult;
|
|
| 230 | -import com.sap.sse.replication.ReplicationMasterDescriptor;
|
|
| 231 | -import com.sap.sse.replication.impl.OperationWithResultWithIdWrapper;
|
|
| 232 | -import com.sap.sse.util.ClearStateTestSupport;
|
|
| 233 | -import com.sap.sse.util.JoinedClassLoader;
|
|
| 234 | -import com.sap.sse.util.impl.ThreadFactoryWithPriority;
|
|
| 235 | -
|
|
| 236 | -public class RacingEventServiceImpl implements RacingEventService, ClearStateTestSupport, RegattaListener,
|
|
| 237 | - LeaderboardRegistry, Replicator, EventFetcher {
|
|
| 238 | - private static final Logger logger = Logger.getLogger(RacingEventServiceImpl.class.getName());
|
|
| 239 | -
|
|
| 240 | - /**
|
|
| 241 | - * A scheduler for the periodic checks of the paramURL documents for the advent of {@link ControlPoint}s with static
|
|
| 242 | - * position information otherwise not available through <code>MarkPassingReceiver</code>'s events.
|
|
| 243 | - */
|
|
| 244 | - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactoryWithPriority(Thread.NORM_PRIORITY, /* daemon */ true));
|
|
| 245 | -
|
|
| 246 | - private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
|
| 247 | -
|
|
| 248 | - /**
|
|
| 249 | - * Holds the {@link Event} objects for those event registered with this service. Note that there may be
|
|
| 250 | - * {@link Event} objects that exist outside this service for events not (yet) registered here.
|
|
| 251 | - */
|
|
| 252 | - private final ConcurrentHashMap<Serializable, Event> eventsById;
|
|
| 253 | -
|
|
| 254 | - private final RemoteSailingServerSet remoteSailingServerSet;
|
|
| 255 | -
|
|
| 256 | - /**
|
|
| 257 | - * Holds the {@link Regatta} objects for those races registered with this service. Note that there may be
|
|
| 258 | - * {@link Regatta} objects that exist outside this service for regattas not (yet) registered here.
|
|
| 259 | - */
|
|
| 260 | - protected final ConcurrentHashMap<String, Regatta> regattasByName;
|
|
| 261 | -
|
|
| 262 | - private final NamedReentrantReadWriteLock regattasByNameLock;
|
|
| 263 | -
|
|
| 264 | - private final ConcurrentHashMap<RaceDefinition, CourseChangeReplicator> courseListeners;
|
|
| 265 | -
|
|
| 266 | - protected final ConcurrentHashMap<Regatta, Set<RaceTracker>> raceTrackersByRegatta;
|
|
| 267 | -
|
|
| 268 | - /**
|
|
| 269 | - * Although {@link #raceTrackersByRegatta} is a concurrent hash map, entering sets as values needs to be
|
|
| 270 | - * synchronized using this lock's write lock to avoid two value sets overwriting each other.
|
|
| 271 | - */
|
|
| 272 | - private final NamedReentrantReadWriteLock raceTrackersByRegattaLock;
|
|
| 273 | -
|
|
| 274 | - /**
|
|
| 275 | - * Remembers the trackers by paramURL/liveURI/storedURI to avoid duplication
|
|
| 276 | - */
|
|
| 277 | - protected final ConcurrentHashMap<Object, RaceTracker> raceTrackersByID;
|
|
| 278 | -
|
|
| 279 | - /**
|
|
| 280 | - * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} will check
|
|
| 281 | - * {@link #raceTrackersByID} for the presence of a tracker and won't create a new tracker if one for the
|
|
| 282 | - * connectivity parameters' ID already exists. This check and creation and addition to {@link #raceTrackersByID}
|
|
| 283 | - * requires locking in the face of concurrent calls to
|
|
| 284 | - * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)}. Using <code>synchronized</code> is
|
|
| 285 | - * not ideal due to its coarse-grained locking style which allows for little concurrency. Instead, this map is used
|
|
| 286 | - * to keep locks for any ID that any invocation of the
|
|
| 287 | - * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method is currently working on.
|
|
| 288 | - * Fetching or creating and putting a lock to this map happens in ({@link #getOrCreateRaceTrackersByIdLock}) which
|
|
| 289 | - * takes care of managing concurrent access to this concurrent map. When done, the
|
|
| 290 | - * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method cleans up by removing the
|
|
| 291 | - * lock again from this map, again using a synchronized method (
|
|
| 292 | - * {@link #unlockRaceTrackersById(Object, NamedReentrantReadWriteLock)}).
|
|
| 293 | - */
|
|
| 294 | - private final ConcurrentHashMap<Object, NamedReentrantReadWriteLock> raceTrackersByIDLocks;
|
|
| 295 | -
|
|
| 296 | - /**
|
|
| 297 | - * Leaderboards managed by this racing event service
|
|
| 298 | - */
|
|
| 299 | - private final ConcurrentHashMap<String, Leaderboard> leaderboardsByName;
|
|
| 300 | -
|
|
| 301 | - /**
|
|
| 302 | - * {@link #leaderboardsByName} is already a concurrent hash map; however, when renaming a leaderboard, this shall
|
|
| 303 | - * happen as an atomic transaction, not interruptible by other write accesses on the same map because otherwise
|
|
| 304 | - * assumptions made during the rename process wouldn't hold. See, in particular,
|
|
| 305 | - * {@link #renameLeaderboard(String, String)}.
|
|
| 306 | - */
|
|
| 307 | - private final NamedReentrantReadWriteLock leaderboardsByNameLock;
|
|
| 308 | -
|
|
| 309 | - private final ConcurrentHashMap<String, LeaderboardGroup> leaderboardGroupsByName;
|
|
| 310 | -
|
|
| 311 | - private final ConcurrentHashMap<UUID, LeaderboardGroup> leaderboardGroupsByID;
|
|
| 312 | -
|
|
| 313 | - /**
|
|
| 314 | - * See {@link #leaderboardsByNameLock}
|
|
| 315 | - */
|
|
| 316 | - private final NamedReentrantReadWriteLock leaderboardGroupsByNameLock;
|
|
| 317 | -
|
|
| 318 | - private final CompetitorStore competitorStore;
|
|
| 319 | -
|
|
| 320 | - /**
|
|
| 321 | - * A set based on a concurrent hash map, therefore being thread safe
|
|
| 322 | - */
|
|
| 323 | - private Set<DynamicTrackedRegatta> regattasObservedForDefaultLeaderboard = Collections
|
|
| 324 | - .newSetFromMap(new ConcurrentHashMap<DynamicTrackedRegatta, Boolean>());
|
|
| 325 | -
|
|
| 326 | - private final MongoObjectFactory mongoObjectFactory;
|
|
| 327 | -
|
|
| 328 | - private final DomainObjectFactory domainObjectFactory;
|
|
| 329 | -
|
|
| 330 | - private final ConcurrentHashMap<Regatta, DynamicTrackedRegatta> regattaTrackingCache;
|
|
| 331 | -
|
|
| 332 | - /**
|
|
| 333 | - * Protects write access transactions that do a previous read to {@link #regattaTrackingCache}; read-only access is
|
|
| 334 | - * already synchronized by using a concurrent hash map for {@link #regattaTrackingCache}.
|
|
| 335 | - */
|
|
| 336 | - private final NamedReentrantReadWriteLock regattaTrackingCacheLock;
|
|
| 337 | -
|
|
| 338 | - private final ConcurrentHashMap<OperationExecutionListener<RacingEventService>, OperationExecutionListener<RacingEventService>> operationExecutionListeners;
|
|
| 339 | -
|
|
| 340 | - /**
|
|
| 341 | - * Keys are the toString() representation of the {@link RaceDefinition#getId() IDs} of races passed to
|
|
| 342 | - * {@link #setRegattaForRace(Regatta, RaceDefinition)}.
|
|
| 343 | - */
|
|
| 344 | - private final ConcurrentHashMap<String, Regatta> persistentRegattasForRaceIDs;
|
|
| 345 | -
|
|
| 346 | - private final RaceLogReplicator raceLogReplicator;
|
|
| 347 | - private final RegattaLogReplicator regattaLogReplicator;
|
|
| 348 | -
|
|
| 349 | - private final RaceLogScoringReplicator raceLogScoringReplicator;
|
|
| 350 | -
|
|
| 351 | - private final MediaDB mediaDB;
|
|
| 352 | -
|
|
| 353 | - private final MediaLibrary mediaLibrary;
|
|
| 354 | -
|
|
| 355 | - /**
|
|
| 356 | - * Currently valid pairs of {@link DeviceConfigurationMatcher}s and {@link DeviceConfiguration}s. The contents of
|
|
| 357 | - * this map is persisted and replicated. See {@link DeviceConfigurationMapImpl}.
|
|
| 358 | - */
|
|
| 359 | - protected final DeviceConfigurationMapImpl configurationMap;
|
|
| 360 | -
|
|
| 361 | - private final WindStore windStore;
|
|
| 362 | - private final GPSFixStore gpsFixStore;
|
|
| 363 | -
|
|
| 364 | - /**
|
|
| 365 | - * This author should be used for server generated race log events
|
|
| 366 | - */
|
|
| 367 | - private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl(
|
|
| 368 | - RacingEventService.class.getName(), 0);
|
|
| 369 | -
|
|
| 370 | - private PolarDataService polarDataService;
|
|
| 371 | -
|
|
| 372 | - private final SimulationService simulationService;
|
|
| 373 | -
|
|
| 374 | - /**
|
|
| 375 | - * Allow only one master data import at a time to avoid situation where multiple Imports override each other in
|
|
| 376 | - * unpredictable fashion
|
|
| 377 | - */
|
|
| 378 | - private final DataImportLockWithProgress dataImportLock;
|
|
| 379 | -
|
|
| 380 | - /**
|
|
| 381 | - * If this service runs in the context of an OSGi environment, the activator should {@link #setBundleContext set the
|
|
| 382 | - * bundle context} on this object so that service lookups become possible.
|
|
| 383 | - */
|
|
| 384 | - private BundleContext bundleContext;
|
|
| 385 | -
|
|
| 386 | - private TypeBasedServiceFinderFactory serviceFinderFactory;
|
|
| 387 | -
|
|
| 388 | - /**
|
|
| 389 | - * The master from which this replicable is currently replicating, or <code>null</code> if this replicable is not
|
|
| 390 | - * currently replicated from any master.
|
|
| 391 | - */
|
|
| 392 | - private ReplicationMasterDescriptor replicatingFromMaster;
|
|
| 393 | -
|
|
| 394 | - private Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication;
|
|
| 395 | -
|
|
| 396 | - private ThreadLocal<Boolean> currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster = ThreadLocal
|
|
| 397 | - .withInitial(() -> false);
|
|
| 398 | -
|
|
| 399 | - private final Set<ClassLoader> masterDataClassLoaders = new HashSet<ClassLoader>();
|
|
| 400 | -
|
|
| 401 | - private final JoinedClassLoader joinedClassLoader;
|
|
| 402 | -
|
|
| 403 | - private SailingServerConfiguration sailingServerConfiguration;
|
|
| 404 | -
|
|
| 405 | - /**
|
|
| 406 | - * Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky
|
|
| 407 | - * in some cases because containment and initialization order of some types is fairly tightly coupled.
|
|
| 408 | - * There is a dependency of many such objects on an instance of {@link RaceLogResolver} which is implemented
|
|
| 409 | - * by {@link RacingEventServiceImpl}. However, therefore, this instance only becomes available in the
|
|
| 410 | - * innermost constructor.
|
|
| 411 | - *
|
|
| 412 | - * @author Axel Uhl (d043530)
|
|
| 413 | - *
|
|
| 414 | - */
|
|
| 415 | - public static interface ConstructorParameters {
|
|
| 416 | - DomainObjectFactory getDomainObjectFactory();
|
|
| 417 | - MongoObjectFactory getMongoObjectFactory();
|
|
| 418 | - com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
|
|
| 419 | - CompetitorStore getCompetitorStore();
|
|
| 420 | - }
|
|
| 421 | -
|
|
| 422 | - /**
|
|
| 423 | - * Constructs a {@link DomainFactory base domain factory} that uses this object's {@link #competitorStore competitor
|
|
| 424 | - * store} for competitor management. This base domain factory is then also used for the construction of the
|
|
| 425 | - * {@link DomainObjectFactory}. This constructor variant initially clears the persistent competitor collection,
|
|
| 426 | - * hence removes all previously persistent competitors. This is the default for testing and for backward
|
|
| 427 | - * compatibility with prior releases that did not support a persistent competitor collection.
|
|
| 428 | - */
|
|
| 429 | - public RacingEventServiceImpl() {
|
|
| 430 | - this(true, null);
|
|
| 431 | - }
|
|
| 432 | -
|
|
| 433 | - public RacingEventServiceImpl(WindStore windStore, GPSFixStore gpsFixStore,
|
|
| 434 | - TypeBasedServiceFinderFactory serviceFinderFactory) {
|
|
| 435 | - this(true, windStore, gpsFixStore, serviceFinderFactory);
|
|
| 436 | - }
|
|
| 437 | -
|
|
| 438 | - void setBundleContext(BundleContext bundleContext) {
|
|
| 439 | - this.bundleContext = bundleContext;
|
|
| 440 | - }
|
|
| 441 | -
|
|
| 442 | - /**
|
|
| 443 | - * Like {@link #RacingEventServiceImpl()}, but allows callers to specify that the persistent competitor collection
|
|
| 444 | - * be cleared before the service starts.
|
|
| 445 | - *
|
|
| 446 | - * @param clearPersistentCompetitorStore
|
|
| 447 | - * if <code>true</code>, the {@link PersistentCompetitorStore} is created empty, with the corresponding
|
|
| 448 | - * database collection cleared as well. Use with caution! When used with <code>false</code>, competitors
|
|
| 449 | - * created and stored during previous service executions will initially be loaded.
|
|
| 450 | - */
|
|
| 451 | - public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory) {
|
|
| 452 | - this((final RaceLogResolver raceLogResolver)-> {
|
|
| 453 | - return new ConstructorParameters() {
|
|
| 454 | - private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
|
|
| 455 | - private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore(
|
|
| 456 | - PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory),
|
|
| 457 | - clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver);
|
|
| 458 | -
|
|
| 459 | - @Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); }
|
|
| 460 | - @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
|
|
| 461 | - @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
|
|
| 462 | - @Override public CompetitorStore getCompetitorStore() { return competitorStore; }
|
|
| 463 | - };
|
|
| 464 | - }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory);
|
|
| 465 | - }
|
|
| 466 | -
|
|
| 467 | - private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore,
|
|
| 468 | - GPSFixStore gpsFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory) {
|
|
| 469 | - this((final RaceLogResolver raceLogResolver)-> {
|
|
| 470 | - return new ConstructorParameters() {
|
|
| 471 | - private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
|
|
| 472 | - private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore(
|
|
| 473 | - mongoObjectFactory,
|
|
| 474 | - clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver);
|
|
| 475 | -
|
|
| 476 | - @Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); }
|
|
| 477 | - @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
|
|
| 478 | - @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
|
|
| 479 | - @Override public CompetitorStore getCompetitorStore() { return competitorStore; }
|
|
| 480 | - };
|
|
| 481 | - }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, gpsFixStore, serviceFinderFactory);
|
|
| 482 | - }
|
|
| 483 | -
|
|
| 484 | - /**
|
|
| 485 | - * Uses the default factories for the tracking adapters and the {@link DomainFactory base domain factory} of the
|
|
| 486 | - * {@link PersistenceFactory#getDefaultDomainObjectFactory() default domain object factory}. This constructor should
|
|
| 487 | - * be used for testing because it provides a transient {@link CompetitorStore} as required for competitor
|
|
| 488 | - * persistence.
|
|
| 489 | - */
|
|
| 490 | - public RacingEventServiceImpl(Function<RaceLogResolver, DomainObjectFactory> domainObjectFactoryProvider,
|
|
| 491 | - final MongoObjectFactory mongoObjectFactory, MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) {
|
|
| 492 | - this((final RaceLogResolver raceLogResolver)-> {
|
|
| 493 | - return new ConstructorParameters() {
|
|
| 494 | - private final DomainObjectFactory domainObjectFactory = domainObjectFactoryProvider.apply(raceLogResolver);
|
|
| 495 | -
|
|
| 496 | - @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
|
|
| 497 | - @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
|
|
| 498 | - @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
|
|
| 499 | - @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
|
|
| 500 | - };
|
|
| 501 | - }, mediaDB, windStore, gpsFixStore, null);
|
|
| 502 | - }
|
|
| 503 | -
|
|
| 504 | - public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
|
|
| 505 | - MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) {
|
|
| 506 | - this((final RaceLogResolver raceLogResolver)-> {
|
|
| 507 | - return new ConstructorParameters() {
|
|
| 508 | - @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
|
|
| 509 | - @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
|
|
| 510 | - @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
|
|
| 511 | - @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
|
|
| 512 | - };
|
|
| 513 | - }, mediaDB, windStore, gpsFixStore, null);
|
|
| 514 | - }
|
|
| 515 | -
|
|
| 516 | - /**
|
|
| 517 | - * @param windStore
|
|
| 518 | - * if <code>null</code>, a default {@link MongoWindStore} will be used, based on the persistence set-up
|
|
| 519 | - * of this service
|
|
| 520 | - * @param serviceFinderFactory
|
|
| 521 | - * used to find the services handling specific types of tracking devices, such as the persistent storage
|
|
| 522 | - * of {@link DeviceIdentifier}s of specific device types or the managing of the device-to-competitor
|
|
| 523 | - * associations per race tracked.
|
|
| 524 | - */
|
|
| 525 | - public RacingEventServiceImpl(Function<RaceLogResolver, ConstructorParameters> constructorParametersProvider, MediaDB mediaDb,
|
|
| 526 | - WindStore windStore, GPSFixStore gpsFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) {
|
|
| 527 | - logger.info("Created " + this);
|
|
| 528 | - final ConstructorParameters constructorParameters = constructorParametersProvider.apply(this);
|
|
| 529 | - this.domainObjectFactory = constructorParameters.getDomainObjectFactory();
|
|
| 530 | - this.masterDataClassLoaders.add(this.getClass().getClassLoader());
|
|
| 531 | - joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
|
|
| 532 | - this.operationsSentToMasterForReplication = new HashSet<>();
|
|
| 533 | - this.baseDomainFactory = constructorParameters.getBaseDomainFactory();
|
|
| 534 | - this.mongoObjectFactory = constructorParameters.getMongoObjectFactory();
|
|
| 535 | - this.mediaDB = mediaDb;
|
|
| 536 | - this.competitorStore = constructorParameters.getCompetitorStore();
|
|
| 537 | - if (windStore == null) {
|
|
| 538 | - try {
|
|
| 539 | - windStore = MongoWindStoreFactory.INSTANCE.getMongoWindStore(mongoObjectFactory, domainObjectFactory);
|
|
| 540 | - } catch (Exception e) {
|
|
| 541 | - throw new RuntimeException(e);
|
|
| 542 | - }
|
|
| 543 | - }
|
|
| 544 | - this.competitorStore.addCompetitorUpdateListener(new CompetitorUpdateListener() {
|
|
| 545 | - @Override
|
|
| 546 | - public void competitorUpdated(Competitor competitor) {
|
|
| 547 | - replicate(new UpdateCompetitor(competitor.getId().toString(), competitor.getName(), competitor
|
|
| 548 | - .getColor(), competitor.getEmail(), competitor.getBoat().getSailID(), competitor.getTeam().getNationality(),
|
|
| 549 | - competitor.getTeam().getImage(), competitor.getFlagImage(),
|
|
| 550 | - competitor.getTimeOnTimeFactor(), competitor.getTimeOnDistanceAllowancePerNauticalMile()));
|
|
| 551 | - }
|
|
| 552 | - });
|
|
| 553 | - this.windStore = windStore;
|
|
| 554 | - this.dataImportLock = new DataImportLockWithProgress();
|
|
| 555 | -
|
|
| 556 | - remoteSailingServerSet = new RemoteSailingServerSet(scheduler);
|
|
| 557 | - regattasByName = new ConcurrentHashMap<String, Regatta>();
|
|
| 558 | - regattasByNameLock = new NamedReentrantReadWriteLock("regattasByName for " + this, /* fair */false);
|
|
| 559 | - eventsById = new ConcurrentHashMap<Serializable, Event>();
|
|
| 560 | - regattaTrackingCache = new ConcurrentHashMap<>();
|
|
| 561 | - regattaTrackingCacheLock = new NamedReentrantReadWriteLock("regattaTrackingCache for " + this, /* fair */false);
|
|
| 562 | - raceTrackersByRegatta = new ConcurrentHashMap<>();
|
|
| 563 | - raceTrackersByRegattaLock = new NamedReentrantReadWriteLock("raceTrackersByRegatta for " + this, /* fair */
|
|
| 564 | - false);
|
|
| 565 | - raceTrackersByID = new ConcurrentHashMap<>();
|
|
| 566 | - raceTrackersByIDLocks = new ConcurrentHashMap<>();
|
|
| 567 | - leaderboardGroupsByName = new ConcurrentHashMap<>();
|
|
| 568 | - leaderboardGroupsByID = new ConcurrentHashMap<>();
|
|
| 569 | - leaderboardGroupsByNameLock = new NamedReentrantReadWriteLock("leaderboardGroupsByName for " + this, /* fair */
|
|
| 570 | - false);
|
|
| 571 | - leaderboardsByName = new ConcurrentHashMap<String, Leaderboard>();
|
|
| 572 | - leaderboardsByNameLock = new NamedReentrantReadWriteLock("leaderboardsByName for " + this, /* fair */false);
|
|
| 573 | - operationExecutionListeners = new ConcurrentHashMap<>();
|
|
| 574 | - courseListeners = new ConcurrentHashMap<>();
|
|
| 575 | - persistentRegattasForRaceIDs = new ConcurrentHashMap<>();
|
|
| 576 | - final int SIMULATION_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/3, 1);
|
|
| 577 | - Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */SIMULATION_THREAD_POOL_SIZE,
|
|
| 578 | - /* maximumPoolSize */SIMULATION_THREAD_POOL_SIZE,
|
|
| 579 | - /* keepAliveTime */60, TimeUnit.SECONDS,
|
|
| 580 | - /* workQueue */new LinkedBlockingQueue<Runnable>());
|
|
| 581 | - // TODO: initialize smart-future-cache for simulation-results and add to simulation-service
|
|
| 582 | - simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this);
|
|
| 583 | - this.raceLogReplicator = new RaceLogReplicator(this);
|
|
| 584 | - this.regattaLogReplicator = new RegattaLogReplicator(this);
|
|
| 585 | - this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
|
|
| 586 | - this.mediaLibrary = new MediaLibrary();
|
|
| 587 | - if (gpsFixStore == null) {
|
|
| 588 | - try {
|
|
| 589 | - gpsFixStore = MongoGPSFixStoreFactory.INSTANCE.getMongoGPSFixStore(mongoObjectFactory,
|
|
| 590 | - domainObjectFactory, serviceFinderFactory);
|
|
| 591 | - } catch (Exception e) {
|
|
| 592 | - e.printStackTrace();
|
|
| 593 | - throw new RuntimeException(e);
|
|
| 594 | - }
|
|
| 595 | - }
|
|
| 596 | - this.gpsFixStore = gpsFixStore;
|
|
| 597 | - this.configurationMap = new DeviceConfigurationMapImpl();
|
|
| 598 | - this.serviceFinderFactory = serviceFinderFactory;
|
|
| 599 | -
|
|
| 600 | - sailingServerConfiguration = domainObjectFactory.loadServerConfiguration();
|
|
| 601 | - final Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = loadStoredEvents();
|
|
| 602 | - loadStoredRegattas();
|
|
| 603 | - loadRaceIDToRegattaAssociations();
|
|
| 604 | - loadStoredLeaderboardsAndGroups();
|
|
| 605 | - loadLinksFromEventsToLeaderboardGroups();
|
|
| 606 | - loadMediaLibary();
|
|
| 607 | - loadStoredDeviceConfigurations();
|
|
| 608 | - loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh();
|
|
| 609 | -
|
|
| 610 | - // Stores all events which run through a data migration
|
|
| 611 | - // Remark: must be called after loadLinksFromEventsToLeaderboardGroups(), otherwise would loose the Event -> LeaderboardGroup relation
|
|
| 612 | - for (Pair<Event, Boolean> eventAndRequireStoreFlag : loadedEventsWithRequireStoreFlag) {
|
|
| 613 | - if (eventAndRequireStoreFlag.getB()) {
|
|
| 614 | - mongoObjectFactory.storeEvent(eventAndRequireStoreFlag.getA());
|
|
| 615 | - }
|
|
| 616 | - }
|
|
| 617 | - }
|
|
| 618 | -
|
|
| 619 | - @Override
|
|
| 620 | - public boolean isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster() {
|
|
| 621 | - return currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.get();
|
|
| 622 | - }
|
|
| 623 | -
|
|
| 624 | - @Override
|
|
| 625 | - public void setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(
|
|
| 626 | - boolean currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster) {
|
|
| 627 | - this.currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster
|
|
| 628 | - .set(currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster);
|
|
| 629 | - }
|
|
| 630 | -
|
|
| 631 | - @Override
|
|
| 632 | - public PolarDataService getPolarDataService() {
|
|
| 633 | - return polarDataService;
|
|
| 634 | - }
|
|
| 635 | -
|
|
| 636 | - @Override
|
|
| 637 | - public SimulationService getSimulationService() {
|
|
| 638 | - return simulationService;
|
|
| 639 | - }
|
|
| 640 | -
|
|
| 641 | - @Override
|
|
| 642 | - public void clearState() throws Exception {
|
|
| 643 | - for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) {
|
|
| 644 | - removeLeaderboardGroup(leaderboardGroupName);
|
|
| 645 | - }
|
|
| 646 | - for (String leaderboardName : new ArrayList<>(this.leaderboardsByName.keySet())) {
|
|
| 647 | - removeLeaderboard(leaderboardName);
|
|
| 648 | - }
|
|
| 649 | - for (Regatta regatta : new ArrayList<>(this.regattasByName.values())) {
|
|
| 650 | - stopTracking(regatta);
|
|
| 651 | - removeRegatta(regatta);
|
|
| 652 | - }
|
|
| 653 | - for (Event event : new ArrayList<>(this.eventsById.values())) {
|
|
| 654 | - removeEvent(event.getId());
|
|
| 655 | - }
|
|
| 656 | - for (MediaTrack mediaTrack : this.mediaLibrary.allTracks()) {
|
|
| 657 | - mediaTrackDeleted(mediaTrack);
|
|
| 658 | - }
|
|
| 659 | - // TODO clear user store? See bug 2430.
|
|
| 660 | - this.competitorStore.clear();
|
|
| 661 | - }
|
|
| 662 | -
|
|
| 663 | - @Override
|
|
| 664 | - public com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory() {
|
|
| 665 | - return baseDomainFactory;
|
|
| 666 | - }
|
|
| 667 | -
|
|
| 668 | - @Override
|
|
| 669 | - public MongoObjectFactory getMongoObjectFactory() {
|
|
| 670 | - return mongoObjectFactory;
|
|
| 671 | - }
|
|
| 672 | -
|
|
| 673 | - @Override
|
|
| 674 | - public DomainObjectFactory getDomainObjectFactory() {
|
|
| 675 | - return domainObjectFactory;
|
|
| 676 | - }
|
|
| 677 | -
|
|
| 678 | - private void loadRaceIDToRegattaAssociations() {
|
|
| 679 | - persistentRegattasForRaceIDs.putAll(domainObjectFactory.loadRaceIDToRegattaAssociations(this));
|
|
| 680 | - }
|
|
| 681 | -
|
|
| 682 | - private void loadStoredRegattas() {
|
|
| 683 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 684 | - try {
|
|
| 685 | - for (Regatta regatta : domainObjectFactory.loadAllRegattas(this)) {
|
|
| 686 | - logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode()
|
|
| 687 | - + ") into regattasByName");
|
|
| 688 | - regattasByName.put(regatta.getName(), regatta);
|
|
| 689 | - regatta.addRegattaListener(this);
|
|
| 690 | - onRegattaLikeAdded(regatta);
|
|
| 691 | - regatta.addRaceColumnListener(raceLogReplicator);
|
|
| 692 | - regatta.addRaceColumnListener(raceLogScoringReplicator);
|
|
| 693 | - }
|
|
| 694 | - } finally {
|
|
| 695 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 696 | - }
|
|
| 697 | - }
|
|
| 698 | -
|
|
| 699 | - private Iterable<Pair<Event, Boolean>> loadStoredEvents() {
|
|
| 700 | - Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = domainObjectFactory.loadAllEvents();
|
|
| 701 | - for (Pair<Event, Boolean> eventAndFlag : loadedEventsWithRequireStoreFlag) {
|
|
| 702 | - Event event = eventAndFlag.getA();
|
|
| 703 | - if (event.getId() != null)
|
|
| 704 | - eventsById.put(event.getId(), event);
|
|
| 705 | - }
|
|
| 706 | - return loadedEventsWithRequireStoreFlag;
|
|
| 707 | - }
|
|
| 708 | -
|
|
| 709 | - private void loadLinksFromEventsToLeaderboardGroups() {
|
|
| 710 | - domainObjectFactory.loadLeaderboardGroupLinksForEvents(/* eventResolver */this, /* leaderboardGroupResolver */
|
|
| 711 | - this);
|
|
| 712 | - }
|
|
| 713 | -
|
|
| 714 | - private void loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh() {
|
|
| 715 | - for (RemoteSailingServerReference sailingServer : domainObjectFactory.loadAllRemoteSailingServerReferences()) {
|
|
| 716 | - remoteSailingServerSet.add(sailingServer);
|
|
| 717 | - }
|
|
| 718 | - }
|
|
| 719 | -
|
|
| 720 | - /**
|
|
| 721 | - * Collects media track references from the configured sources (mongo DB by default, ftp folder yet to be
|
|
| 722 | - * implemented). The method is expected to be called initially blocking the API until finished.
|
|
| 723 | - *
|
|
| 724 | - * Subsequent calls (assumed to be triggered from the admin console or in scheduled intervals) don't need to block.
|
|
| 725 | - * In that case, the API will simply serve the current state.
|
|
| 726 | - *
|
|
| 727 | - */
|
|
| 728 | - private void loadMediaLibary() {
|
|
| 729 | - Collection<MediaTrack> allDbMediaTracks = mediaDB.loadAllMediaTracks();
|
|
| 730 | - mediaTracksAdded(allDbMediaTracks);
|
|
| 731 | - }
|
|
| 732 | -
|
|
| 733 | - private void loadStoredDeviceConfigurations() {
|
|
| 734 | - for (Entry<DeviceConfigurationMatcher, DeviceConfiguration> entry : domainObjectFactory
|
|
| 735 | - .loadAllDeviceConfigurations()) {
|
|
| 736 | - configurationMap.put(entry.getKey(), entry.getValue());
|
|
| 737 | - }
|
|
| 738 | - }
|
|
| 739 | -
|
|
| 740 | - @Override
|
|
| 741 | - public void addLeaderboard(Leaderboard leaderboard) {
|
|
| 742 | - LockUtil.lockForWrite(leaderboardsByNameLock);
|
|
| 743 | - try {
|
|
| 744 | - leaderboardsByName.put(leaderboard.getName(), leaderboard);
|
|
| 745 | - } finally {
|
|
| 746 | - LockUtil.unlockAfterWrite(leaderboardsByNameLock);
|
|
| 747 | - }
|
|
| 748 | - // RaceColumns of RegattaLeaderboards are tracked via its Regatta!
|
|
| 749 | - if (leaderboard instanceof FlexibleLeaderboard) {
|
|
| 750 | - onRegattaLikeAdded(((FlexibleLeaderboard) leaderboard).getRegattaLike());
|
|
| 751 | - leaderboard.addRaceColumnListener(raceLogReplicator);
|
|
| 752 | - leaderboard.addRaceColumnListener(raceLogScoringReplicator);
|
|
| 753 | - }
|
|
| 754 | - }
|
|
| 755 | -
|
|
| 756 | - private void loadStoredLeaderboardsAndGroups() {
|
|
| 757 | - logger.info("loading stored leaderboards and groups");
|
|
| 758 | - // Loading all leaderboard groups and the contained leaderboards
|
|
| 759 | - for (LeaderboardGroup leaderboardGroup : domainObjectFactory.getAllLeaderboardGroups(this, this)) {
|
|
| 760 | - logger.info("loaded leaderboard group " + leaderboardGroup.getName() + " into " + this);
|
|
| 761 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 762 | - try {
|
|
| 763 | - leaderboardGroupsByName.put(leaderboardGroup.getName(), leaderboardGroup);
|
|
| 764 | - leaderboardGroupsByID.put(leaderboardGroup.getId(), leaderboardGroup);
|
|
| 765 | - } finally {
|
|
| 766 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 767 | - }
|
|
| 768 | - }
|
|
| 769 | - // Loading the remaining leaderboards
|
|
| 770 | - domainObjectFactory.getLeaderboardsNotInGroup(this, this);
|
|
| 771 | - logger.info("done with loading stored leaderboards and groups");
|
|
| 772 | - }
|
|
| 773 | -
|
|
| 774 | - @Override
|
|
| 775 | - public FlexibleLeaderboard addFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName,
|
|
| 776 | - int[] discardThresholds, ScoringScheme scoringScheme, Serializable courseAreaId) {
|
|
| 777 | - logger.info("adding flexible leaderboard " + leaderboardName);
|
|
| 778 | - CourseArea courseArea = getCourseArea(courseAreaId);
|
|
| 779 | - FlexibleLeaderboard result = new FlexibleLeaderboardImpl(getRaceLogStore(), getRegattaLogStore(),
|
|
| 780 | - leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardThresholds), scoringScheme,
|
|
| 781 | - courseArea);
|
|
| 782 | - result.setDisplayName(leaderboardDisplayName);
|
|
| 783 | - if (getLeaderboardByName(leaderboardName) != null) {
|
|
| 784 | - throw new IllegalArgumentException("Leaderboard with name " + leaderboardName + " already exists");
|
|
| 785 | - }
|
|
| 786 | - addLeaderboard(result);
|
|
| 787 | - mongoObjectFactory.storeLeaderboard(result);
|
|
| 788 | - return result;
|
|
| 789 | - }
|
|
| 790 | -
|
|
| 791 | - @Override
|
|
| 792 | - public CourseArea getCourseArea(Serializable courseAreaId) {
|
|
| 793 | - for (Event event : getAllEvents()) {
|
|
| 794 | - for (CourseArea courseArea : event.getVenue().getCourseAreas()) {
|
|
| 795 | - if (courseArea.getId().equals(courseAreaId)) {
|
|
| 796 | - return courseArea;
|
|
| 797 | - }
|
|
| 798 | - }
|
|
| 799 | - }
|
|
| 800 | - return null;
|
|
| 801 | - }
|
|
| 802 | -
|
|
| 803 | - @Override
|
|
| 804 | - public RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName,
|
|
| 805 | - int[] discardThresholds) {
|
|
| 806 | - Regatta regatta = getRegatta(regattaIdentifier);
|
|
| 807 | - logger.info("adding regatta leaderboard for regatta "
|
|
| 808 | - + (regatta == null ? "null" : (regatta.getName() + " (" + regatta.hashCode() + ")")) + " to " + this);
|
|
| 809 | - RegattaLeaderboard result = null;
|
|
| 810 | - if (regatta != null) {
|
|
| 811 | - result = new RegattaLeaderboardImpl(regatta, new ThresholdBasedResultDiscardingRuleImpl(discardThresholds));
|
|
| 812 | - result.setDisplayName(leaderboardDisplayName);
|
|
| 813 | - if (getLeaderboardByName(result.getName()) != null) {
|
|
| 814 | - throw new IllegalArgumentException("Leaderboard with name " + result.getName() + " already exists in "
|
|
| 815 | - + this);
|
|
| 816 | - }
|
|
| 817 | - addLeaderboard(result);
|
|
| 818 | - mongoObjectFactory.storeLeaderboard(result);
|
|
| 819 | - } else {
|
|
| 820 | - logger.warning("Cannot find regatta " + regattaIdentifier
|
|
| 821 | - + ". Hence, cannot create regatta leaderboard for it.");
|
|
| 822 | - }
|
|
| 823 | - return result;
|
|
| 824 | - }
|
|
| 825 | -
|
|
| 826 | - @Override
|
|
| 827 | - public RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace) {
|
|
| 828 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 829 | - if (leaderboard != null) {
|
|
| 830 | - if (leaderboard instanceof FlexibleLeaderboard) {
|
|
| 831 | - // uses the default fleet as the single fleet for the new column
|
|
| 832 | - RaceColumn result = ((FlexibleLeaderboard) leaderboard).addRaceColumn(columnName, medalRace);
|
|
| 833 | - updateStoredLeaderboard((FlexibleLeaderboard) leaderboard);
|
|
| 834 | - return result;
|
|
| 835 | - } else {
|
|
| 836 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName
|
|
| 837 | - + " is not a FlexibleLeaderboard");
|
|
| 838 | - }
|
|
| 839 | - } else {
|
|
| 840 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 841 | - }
|
|
| 842 | - }
|
|
| 843 | -
|
|
| 844 | - @Override
|
|
| 845 | - public void moveLeaderboardColumnUp(String leaderboardName, String columnName) {
|
|
| 846 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 847 | - if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) {
|
|
| 848 | - ((FlexibleLeaderboard) leaderboard).moveRaceColumnUp(columnName);
|
|
| 849 | - updateStoredLeaderboard((FlexibleLeaderboard) leaderboard);
|
|
| 850 | - } else {
|
|
| 851 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 852 | - }
|
|
| 853 | - }
|
|
| 854 | -
|
|
| 855 | - @Override
|
|
| 856 | - public void moveLeaderboardColumnDown(String leaderboardName, String columnName) {
|
|
| 857 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 858 | - if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) {
|
|
| 859 | - ((FlexibleLeaderboard) leaderboard).moveRaceColumnDown(columnName);
|
|
| 860 | - updateStoredLeaderboard((FlexibleLeaderboard) leaderboard);
|
|
| 861 | - } else {
|
|
| 862 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 863 | - }
|
|
| 864 | - }
|
|
| 865 | -
|
|
| 866 | - @Override
|
|
| 867 | - public void removeLeaderboardColumn(String leaderboardName, String columnName) {
|
|
| 868 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 869 | - if (leaderboard == null) {
|
|
| 870 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 871 | - } else if (!(leaderboard instanceof FlexibleLeaderboard)) {
|
|
| 872 | - throw new IllegalArgumentException("Columns cannot be removed from Leaderboard named " + leaderboardName);
|
|
| 873 | - } else {
|
|
| 874 | - ((FlexibleLeaderboard) leaderboard).removeRaceColumn(columnName);
|
|
| 875 | - updateStoredLeaderboard((FlexibleLeaderboard) leaderboard);
|
|
| 876 | - }
|
|
| 877 | - }
|
|
| 878 | -
|
|
| 879 | - @Override
|
|
| 880 | - public void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName) {
|
|
| 881 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 882 | - if (leaderboard != null) {
|
|
| 883 | - final RaceColumn raceColumn = leaderboard.getRaceColumnByName(oldColumnName);
|
|
| 884 | - if (raceColumn instanceof FlexibleRaceColumn) {
|
|
| 885 | - // remove race log under old identifier; the race log identifier changes
|
|
| 886 | - for (Fleet fleet : raceColumn.getFleets()) {
|
|
| 887 | - getMongoObjectFactory().removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
|
| 888 | - }
|
|
| 889 | - ((FlexibleRaceColumn) raceColumn).setName(newColumnName);
|
|
| 890 | - // store the race logs again under the new identifiers
|
|
| 891 | - storeRaceLogs(raceColumn);
|
|
| 892 | - updateStoredLeaderboard(leaderboard);
|
|
| 893 | - } else {
|
|
| 894 | - throw new IllegalArgumentException("Race column " + oldColumnName + " cannot be renamed");
|
|
| 895 | - }
|
|
| 896 | - } else {
|
|
| 897 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 898 | - }
|
|
| 899 | - }
|
|
| 900 | -
|
|
| 901 | - /**
|
|
| 902 | - * When a race column is renamed, its race log identifiers change. Therefore, the race logs need to be stored under
|
|
| 903 | - * the new identifier again to be consistent with the in-memory image again.
|
|
| 904 | - */
|
|
| 905 | - private void storeRaceLogs(RaceColumn raceColumn) {
|
|
| 906 | - for (Fleet fleet : raceColumn.getFleets()) {
|
|
| 907 | - RaceLogIdentifier identifier = raceColumn.getRaceLogIdentifier(fleet);
|
|
| 908 | - RaceLogEventVisitor storeVisitor = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStoreVisitor(
|
|
| 909 | - identifier, getMongoObjectFactory());
|
|
| 910 | - RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
|
| 911 | - raceLog.lockForRead();
|
|
| 912 | - try {
|
|
| 913 | - for (RaceLogEvent e : raceLog.getRawFixes()) {
|
|
| 914 | - e.accept(storeVisitor);
|
|
| 915 | - }
|
|
| 916 | - } finally {
|
|
| 917 | - raceLog.unlockAfterRead();
|
|
| 918 | - }
|
|
| 919 | - }
|
|
| 920 | - }
|
|
| 921 | -
|
|
| 922 | - @Override
|
|
| 923 | - public void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor) {
|
|
| 924 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 925 | - if (leaderboard != null) {
|
|
| 926 | - final RaceColumn raceColumn = leaderboard.getRaceColumnByName(columnName);
|
|
| 927 | - if (raceColumn != null) {
|
|
| 928 | - raceColumn.setFactor(factor);
|
|
| 929 | - updateStoredLeaderboard(leaderboard);
|
|
| 930 | - } else {
|
|
| 931 | - throw new IllegalArgumentException("Race column " + columnName + " not found in leaderboard "
|
|
| 932 | - + leaderboardName);
|
|
| 933 | - }
|
|
| 934 | - } else {
|
|
| 935 | - throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found");
|
|
| 936 | - }
|
|
| 937 | - }
|
|
| 938 | -
|
|
| 939 | - @Override
|
|
| 940 | - public void renameLeaderboard(String oldName, String newName) {
|
|
| 941 | - final Leaderboard toRename = leaderboardsByName.get(oldName);
|
|
| 942 | - LockUtil.lockForWrite(leaderboardsByNameLock);
|
|
| 943 | - try {
|
|
| 944 | - if (toRename == null) {
|
|
| 945 | - throw new IllegalArgumentException("No leaderboard with name " + oldName + " found");
|
|
| 946 | - }
|
|
| 947 | - if (leaderboardsByName.containsKey(newName)) {
|
|
| 948 | - throw new IllegalArgumentException("Leaderboard with name " + newName + " already exists");
|
|
| 949 | - }
|
|
| 950 | - if (toRename instanceof Renamable) {
|
|
| 951 | - ((Renamable) toRename).setName(newName);
|
|
| 952 | - leaderboardsByName.remove(oldName);
|
|
| 953 | - leaderboardsByName.put(newName, toRename);
|
|
| 954 | - } else {
|
|
| 955 | - throw new IllegalArgumentException("Leaderboard with name " + newName + " is of type "
|
|
| 956 | - + toRename.getClass().getSimpleName() + " and therefore cannot be renamed");
|
|
| 957 | - }
|
|
| 958 | - } finally {
|
|
| 959 | - LockUtil.unlockAfterWrite(leaderboardsByNameLock);
|
|
| 960 | - }
|
|
| 961 | - // don't need the lock anymore to update DB
|
|
| 962 | - if (toRename instanceof Renamable) {
|
|
| 963 | - mongoObjectFactory.renameLeaderboard(oldName, newName);
|
|
| 964 | - syncGroupsAfterLeaderboardChange(toRename, true);
|
|
| 965 | - }
|
|
| 966 | - }
|
|
| 967 | -
|
|
| 968 | - @Override
|
|
| 969 | - public void updateStoredLeaderboard(Leaderboard leaderboard) {
|
|
| 970 | - getMongoObjectFactory().storeLeaderboard(leaderboard);
|
|
| 971 | - syncGroupsAfterLeaderboardChange(leaderboard, true);
|
|
| 972 | - }
|
|
| 973 | -
|
|
| 974 | - @Override
|
|
| 975 | - public void updateStoredRegatta(Regatta regatta) {
|
|
| 976 | - if (regatta.isPersistent()) {
|
|
| 977 | - mongoObjectFactory.storeRegatta(regatta);
|
|
| 978 | - }
|
|
| 979 | - }
|
|
| 980 | -
|
|
| 981 | - /**
|
|
| 982 | - * Checks all groups, if they contain a leaderboard with the name of the <code>updatedLeaderboard</code> and
|
|
| 983 | - * replaces the one in the group with the updated one.<br />
|
|
| 984 | - * This synchronizes things like the RaceIdentifier in the leaderboard columns.
|
|
| 985 | - */
|
|
| 986 | - private void syncGroupsAfterLeaderboardChange(Leaderboard updatedLeaderboard, boolean doDatabaseUpdate) {
|
|
| 987 | - boolean groupNeedsUpdate = false;
|
|
| 988 | - for (LeaderboardGroup leaderboardGroup : leaderboardGroupsByName.values()) {
|
|
| 989 | - for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
|
| 990 | - if (leaderboard == updatedLeaderboard) {
|
|
| 991 | - int index = leaderboardGroup.getIndexOf(leaderboard);
|
|
| 992 | - leaderboardGroup.removeLeaderboard(leaderboard);
|
|
| 993 | - leaderboardGroup.addLeaderboardAt(updatedLeaderboard, index);
|
|
| 994 | - groupNeedsUpdate = true;
|
|
| 995 | - // TODO we assume that the leaderboard names are unique, so we can break the inner loop here
|
|
| 996 | - break;
|
|
| 997 | - }
|
|
| 998 | - }
|
|
| 999 | -
|
|
| 1000 | - if (doDatabaseUpdate && groupNeedsUpdate) {
|
|
| 1001 | - mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup);
|
|
| 1002 | - }
|
|
| 1003 | - groupNeedsUpdate = false;
|
|
| 1004 | - }
|
|
| 1005 | - }
|
|
| 1006 | -
|
|
| 1007 | - @Override
|
|
| 1008 | - public void removeLeaderboard(String leaderboardName) {
|
|
| 1009 | - Leaderboard leaderboard = removeLeaderboardFromLeaderboardsByName(leaderboardName);
|
|
| 1010 | - if (leaderboard != null) {
|
|
| 1011 | - leaderboard.removeRaceColumnListener(raceLogReplicator);
|
|
| 1012 | - leaderboard.removeRaceColumnListener(raceLogScoringReplicator);
|
|
| 1013 | - mongoObjectFactory.removeLeaderboard(leaderboardName);
|
|
| 1014 | - syncGroupsAfterLeaderboardRemove(leaderboardName, true);
|
|
| 1015 | - if (leaderboard instanceof FlexibleLeaderboard) {
|
|
| 1016 | - onRegattaLikeRemoved(((FlexibleLeaderboard) leaderboard).getRegattaLike());
|
|
| 1017 | - }
|
|
| 1018 | - leaderboard.destroy();
|
|
| 1019 | - }
|
|
| 1020 | - }
|
|
| 1021 | -
|
|
| 1022 | - private Leaderboard removeLeaderboardFromLeaderboardsByName(String leaderboardName) {
|
|
| 1023 | - LockUtil.lockForWrite(leaderboardsByNameLock);
|
|
| 1024 | - try {
|
|
| 1025 | - return leaderboardsByName.remove(leaderboardName);
|
|
| 1026 | - } finally {
|
|
| 1027 | - LockUtil.unlockAfterWrite(leaderboardsByNameLock);
|
|
| 1028 | - }
|
|
| 1029 | - }
|
|
| 1030 | -
|
|
| 1031 | - /**
|
|
| 1032 | - * Checks all groups, if they contain a leaderboard with the <code>removedLeaderboardName</code> and removes it from
|
|
| 1033 | - * the group.
|
|
| 1034 | - *
|
|
| 1035 | - * @param removedLeaderboardName
|
|
| 1036 | - */
|
|
| 1037 | - private void syncGroupsAfterLeaderboardRemove(String removedLeaderboardName, boolean doDatabaseUpdate) {
|
|
| 1038 | - boolean groupNeedsUpdate = false;
|
|
| 1039 | - for (LeaderboardGroup leaderboardGroup : leaderboardGroupsByName.values()) {
|
|
| 1040 | - for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
|
| 1041 | - if (leaderboard.getName().equals(removedLeaderboardName)) {
|
|
| 1042 | - leaderboardGroup.removeLeaderboard(leaderboard);
|
|
| 1043 | - groupNeedsUpdate = true;
|
|
| 1044 | - // TODO we assume that the leaderboard names are unique, so we can break the inner loop here
|
|
| 1045 | - break;
|
|
| 1046 | - }
|
|
| 1047 | - }
|
|
| 1048 | -
|
|
| 1049 | - if (doDatabaseUpdate && groupNeedsUpdate) {
|
|
| 1050 | - mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup);
|
|
| 1051 | - }
|
|
| 1052 | - groupNeedsUpdate = false;
|
|
| 1053 | - }
|
|
| 1054 | - }
|
|
| 1055 | -
|
|
| 1056 | - @Override
|
|
| 1057 | - public Leaderboard getLeaderboardByName(String name) {
|
|
| 1058 | - return leaderboardsByName.get(name);
|
|
| 1059 | - }
|
|
| 1060 | -
|
|
| 1061 | - @Override
|
|
| 1062 | - public Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog) {
|
|
| 1063 | - GPSFixTrack<Mark, GPSFix> track = null;
|
|
| 1064 | - // If no spanning track is found, the fix closest to the time point requested is used instead
|
|
| 1065 | - GPSFix nonSpanningFallback = null;
|
|
| 1066 | - for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
|
|
| 1067 | - GPSFixTrack<Mark, GPSFix> trackCandidate = trackedRace.getTrack(mark);
|
|
| 1068 | - if (trackCandidate != null) {
|
|
| 1069 | - if (spansTimePoint(trackCandidate, timePoint)) {
|
|
| 1070 | - track = trackCandidate;
|
|
| 1071 | - break;
|
|
| 1072 | - } else {
|
|
| 1073 | - nonSpanningFallback = improveTimewiseClosestFix(nonSpanningFallback, trackCandidate, timePoint);
|
|
| 1074 | - }
|
|
| 1075 | - }
|
|
| 1076 | - }
|
|
| 1077 | - if (track == null) { // no spanning track found in any tracked race, or no tracked races found
|
|
| 1078 | - // try to load from store
|
|
| 1079 | - DynamicGPSFixTrackImpl<Mark> loadedTrack = new DynamicGPSFixTrackImpl<Mark>(mark, 0);
|
|
| 1080 | - track = loadedTrack;
|
|
| 1081 | - Set<AbstractLog<?, ?>> logs = new HashSet<>();
|
|
| 1082 | - logs.add(leaderboard.getRegattaLike().getRegattaLog());
|
|
| 1083 | - if (raceLog == null) { // no race log explicitly provided --> use all race logs
|
|
| 1084 | - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
|
| 1085 | - for (Fleet fleet : raceColumn.getFleets()) {
|
|
| 1086 | - logs.add(raceColumn.getRaceLog(fleet));
|
|
| 1087 | - }
|
|
| 1088 | - }
|
|
| 1089 | - } else {
|
|
| 1090 | - logs.add(raceLog);
|
|
| 1091 | - }
|
|
| 1092 | - for (AbstractLog<?, ?> log : logs) {
|
|
| 1093 | - try {
|
|
| 1094 | - getGPSFixStore().loadMarkTrack(loadedTrack, log, mark);
|
|
| 1095 | - } catch (Exception e) {
|
|
| 1096 | - logger.log(Level.WARNING, "Couldn't load mark track for mark " + mark + " from log " + log, e);
|
|
| 1097 | - }
|
|
| 1098 | - }
|
|
| 1099 | - }
|
|
| 1100 | - Position result = track.getEstimatedPosition(timePoint, /* extrapolate */ false);
|
|
| 1101 | - if (result == null) {
|
|
| 1102 | - result = nonSpanningFallback == null ? null : nonSpanningFallback.getPosition();
|
|
| 1103 | - }
|
|
| 1104 | - return result;
|
|
| 1105 | - }
|
|
| 1106 | -
|
|
| 1107 | - private GPSFix improveTimewiseClosestFix(GPSFix nonSpanningFallback, GPSFixTrack<Mark, GPSFix> track, final TimePoint timePoint) {
|
|
| 1108 | - GPSFix lastAtOrBefore = track.getLastFixAtOrBefore(timePoint);
|
|
| 1109 | - GPSFix firstAtOrAfter = track.getFirstFixAtOrAfter(timePoint);
|
|
| 1110 | - // find the fix closes to timePoint, sorting null values to the end and fixes near timePoint to the beginning
|
|
| 1111 | - final List<GPSFix> list = Arrays.asList(nonSpanningFallback, lastAtOrBefore, firstAtOrAfter);
|
|
| 1112 | - list.sort(new Comparator<GPSFix>() {
|
|
| 1113 | - @Override
|
|
| 1114 | - public int compare(GPSFix o1, GPSFix o2) {
|
|
| 1115 | - final int result;
|
|
| 1116 | - if (o1 == null) {
|
|
| 1117 | - if (o2 == null) {
|
|
| 1118 | - result = 0;
|
|
| 1119 | - } else {
|
|
| 1120 | - result = 1;
|
|
| 1121 | - }
|
|
| 1122 | - } else if (o2 == null) {
|
|
| 1123 | - result = -1;
|
|
| 1124 | - } else {
|
|
| 1125 | - result = new Long(Math.abs(o1.getTimePoint().until(timePoint).asMillis())).compareTo(
|
|
| 1126 | - Math.abs(o2.getTimePoint().until(timePoint).asMillis()));
|
|
| 1127 | - }
|
|
| 1128 | - return result;
|
|
| 1129 | - }
|
|
| 1130 | - });
|
|
| 1131 | - return list.get(0);
|
|
| 1132 | - }
|
|
| 1133 | -
|
|
| 1134 | - private boolean spansTimePoint(GPSFixTrack<Mark, GPSFix> track, TimePoint timePoint) {
|
|
| 1135 | - return track.getLastFixAtOrBefore(timePoint) != null && track.getFirstFixAtOrAfter(timePoint) != null;
|
|
| 1136 | - }
|
|
| 1137 | -
|
|
| 1138 | - @Override
|
|
| 1139 | - public Map<String, Leaderboard> getLeaderboards() {
|
|
| 1140 | - return Collections.unmodifiableMap(new HashMap<String, Leaderboard>(leaderboardsByName));
|
|
| 1141 | - }
|
|
| 1142 | -
|
|
| 1143 | - @Override
|
|
| 1144 | - public SailingServerConfiguration getSailingServerConfiguration() {
|
|
| 1145 | - return sailingServerConfiguration;
|
|
| 1146 | - }
|
|
| 1147 | -
|
|
| 1148 | - @Override
|
|
| 1149 | - public void updateServerConfiguration(SailingServerConfiguration serverConfiguration) {
|
|
| 1150 | - this.sailingServerConfiguration = serverConfiguration;
|
|
| 1151 | - mongoObjectFactory.storeServerConfiguration(serverConfiguration);
|
|
| 1152 | - }
|
|
| 1153 | -
|
|
| 1154 | - @Override
|
|
| 1155 | - public Map<RemoteSailingServerReference, com.sap.sse.common.Util.Pair<Iterable<EventBase>, Exception>> getPublicEventsOfAllSailingServers() {
|
|
| 1156 | - return remoteSailingServerSet.getCachedEventsForRemoteSailingServers(); // FIXME should probably add our own
|
|
| 1157 | - // stuff here... Is it enough to pass on
|
|
| 1158 | - // the remote reference URL to the
|
|
| 1159 | - // client for leaderboard group URL
|
|
| 1160 | - // construction?
|
|
| 1161 | - }
|
|
| 1162 | -
|
|
| 1163 | - @Override
|
|
| 1164 | - public RemoteSailingServerReference addRemoteSailingServerReference(String name, URL url) {
|
|
| 1165 | - RemoteSailingServerReference result = new RemoteSailingServerReferenceImpl(name, url);
|
|
| 1166 | - remoteSailingServerSet.add(result);
|
|
| 1167 | - mongoObjectFactory.storeSailingServer(result);
|
|
| 1168 | - return result;
|
|
| 1169 | - }
|
|
| 1170 | -
|
|
| 1171 | - @Override
|
|
| 1172 | - public Iterable<RemoteSailingServerReference> getLiveRemoteServerReferences() {
|
|
| 1173 | - return remoteSailingServerSet.getLiveRemoteServerReferences();
|
|
| 1174 | - }
|
|
| 1175 | -
|
|
| 1176 | - @Override
|
|
| 1177 | - public RemoteSailingServerReference getRemoteServerReferenceByName(String remoteServerReferenceName) {
|
|
| 1178 | - return remoteSailingServerSet.getServerReferenceByName(remoteServerReferenceName);
|
|
| 1179 | - }
|
|
| 1180 | -
|
|
| 1181 | - @Override
|
|
| 1182 | - public com.sap.sse.common.Util.Pair<Iterable<EventBase>, Exception> updateRemoteServerEventCacheSynchronously(
|
|
| 1183 | - RemoteSailingServerReference ref) {
|
|
| 1184 | - return remoteSailingServerSet.getEventsOrException(ref);
|
|
| 1185 | - }
|
|
| 1186 | -
|
|
| 1187 | - @Override
|
|
| 1188 | - public void removeRemoteSailingServerReference(String name) {
|
|
| 1189 | - remoteSailingServerSet.remove(name);
|
|
| 1190 | - mongoObjectFactory.removeSailingServer(name);
|
|
| 1191 | - }
|
|
| 1192 | -
|
|
| 1193 | - @Override
|
|
| 1194 | - public Iterable<Event> getAllEvents() {
|
|
| 1195 | - return Collections.unmodifiableCollection(new ArrayList<Event>(eventsById.values()));
|
|
| 1196 | - }
|
|
| 1197 | -
|
|
| 1198 | - @Override
|
|
| 1199 | - public Event getEvent(Serializable id) {
|
|
| 1200 | - return id == null ? null : eventsById.get(id);
|
|
| 1201 | - }
|
|
| 1202 | -
|
|
| 1203 | - @Override
|
|
| 1204 | - public Iterable<Regatta> getAllRegattas() {
|
|
| 1205 | - return Collections.unmodifiableCollection(new ArrayList<Regatta>(regattasByName.values()));
|
|
| 1206 | - }
|
|
| 1207 | -
|
|
| 1208 | - @Override
|
|
| 1209 | - public boolean isRaceBeingTracked(Regatta regattaContext, RaceDefinition r) {
|
|
| 1210 | - Set<RaceTracker> trackers = raceTrackersByRegatta.get(regattaContext);
|
|
| 1211 | - if (trackers != null) {
|
|
| 1212 | - for (RaceTracker tracker : trackers) {
|
|
| 1213 | - final Set<RaceDefinition> races = tracker.getRaces();
|
|
| 1214 | - if (races != null && races.contains(r)) {
|
|
| 1215 | - return true;
|
|
| 1216 | - }
|
|
| 1217 | - }
|
|
| 1218 | - }
|
|
| 1219 | - return false;
|
|
| 1220 | - }
|
|
| 1221 | -
|
|
| 1222 | - @Override
|
|
| 1223 | - public Regatta getRegattaByName(String name) {
|
|
| 1224 | - return name == null ? null : regattasByName.get(name);
|
|
| 1225 | - }
|
|
| 1226 | -
|
|
| 1227 | - @Override
|
|
| 1228 | - public Regatta getOrCreateDefaultRegatta(String name, String boatClassName, Serializable id) {
|
|
| 1229 | - Regatta result = regattasByName.get(name);
|
|
| 1230 | - if (result == null) {
|
|
| 1231 | - result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, getBaseDomainFactory()
|
|
| 1232 | - .getOrCreateBoatClass(boatClassName), /* startDate */null, /* endDate */null, this,
|
|
| 1233 | - getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), id, null);
|
|
| 1234 | - logger.info("Created default regatta " + result.getName() + " (" + hashCode() + ") on " + this);
|
|
| 1235 | - onRegattaLikeAdded(result);
|
|
| 1236 | - cacheAndReplicateDefaultRegatta(result);
|
|
| 1237 | - }
|
|
| 1238 | - return result;
|
|
| 1239 | - }
|
|
| 1240 | -
|
|
| 1241 | - private void onRegattaLikeAdded(IsRegattaLike isRegattaLike) {
|
|
| 1242 | - isRegattaLike.addListener(regattaLogReplicator);
|
|
| 1243 | - }
|
|
| 1244 | -
|
|
| 1245 | - private void onRegattaLikeRemoved(IsRegattaLike isRegattaLike) {
|
|
| 1246 | - isRegattaLike.removeListener(regattaLogReplicator);
|
|
| 1247 | - getRegattaLogStore().removeRegattaLog(isRegattaLike.getRegattaLikeIdentifier());
|
|
| 1248 | - }
|
|
| 1249 | -
|
|
| 1250 | - @Override
|
|
| 1251 | - public Regatta createRegatta(String fullRegattaName, String boatClassName, TimePoint startDate, TimePoint endDate,
|
|
| 1252 | - Serializable id, Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme,
|
|
| 1253 | - Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) {
|
|
| 1254 | - com.sap.sse.common.Util.Pair<Regatta, Boolean> regattaWithCreatedFlag = getOrCreateRegattaWithoutReplication(
|
|
| 1255 | - fullRegattaName, boatClassName, startDate, endDate, id, series, persistent, scoringScheme,
|
|
| 1256 | - defaultCourseAreaId, useStartTimeInference, rankingMetricConstructor);
|
|
| 1257 | - Regatta regatta = regattaWithCreatedFlag.getA();
|
|
| 1258 | - if (regattaWithCreatedFlag.getB()) {
|
|
| 1259 | - onRegattaLikeAdded(regatta);
|
|
| 1260 | - replicateSpecificRegattaWithoutRaceColumns(regatta);
|
|
| 1261 | - }
|
|
| 1262 | - return regatta;
|
|
| 1263 | - }
|
|
| 1264 | -
|
|
| 1265 | - @Override
|
|
| 1266 | - public void addRegattaWithoutReplication(Regatta regatta) {
|
|
| 1267 | - UUID defaultCourseAreaId = null;
|
|
| 1268 | - if (regatta.getDefaultCourseArea() != null) {
|
|
| 1269 | - defaultCourseAreaId = regatta.getDefaultCourseArea().getId();
|
|
| 1270 | - }
|
|
| 1271 | - boolean wasAdded = addAndConnectRegatta(regatta.isPersistent(), defaultCourseAreaId, regatta);
|
|
| 1272 | - if (!wasAdded) {
|
|
| 1273 | - logger.info("Regatta with name " + regatta.getName() + " already existed, so it hasn't been added.");
|
|
| 1274 | - }
|
|
| 1275 | - }
|
|
| 1276 | -
|
|
| 1277 | - private RaceLogStore getRaceLogStore() {
|
|
| 1278 | - return MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory);
|
|
| 1279 | - }
|
|
| 1280 | -
|
|
| 1281 | - private RegattaLogStore getRegattaLogStore() {
|
|
| 1282 | - return MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory);
|
|
| 1283 | - }
|
|
| 1284 | -
|
|
| 1285 | - @Override
|
|
| 1286 | - public com.sap.sse.common.Util.Pair<Regatta, Boolean> getOrCreateRegattaWithoutReplication(String fullRegattaName,
|
|
| 1287 | - String boatClassName, TimePoint startDate, TimePoint endDate, Serializable id,
|
|
| 1288 | - Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme,
|
|
| 1289 | - Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) {
|
|
| 1290 | - CourseArea courseArea = getCourseArea(defaultCourseAreaId);
|
|
| 1291 | - Regatta regatta = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), fullRegattaName,
|
|
| 1292 | - getBaseDomainFactory().getOrCreateBoatClass(boatClassName), startDate, endDate, series, persistent,
|
|
| 1293 | - scoringScheme, id, courseArea, useStartTimeInference, rankingMetricConstructor);
|
|
| 1294 | - boolean wasCreated = addAndConnectRegatta(persistent, defaultCourseAreaId, regatta);
|
|
| 1295 | - if (wasCreated) {
|
|
| 1296 | - logger.info("Created regatta " + regatta.getName() + " (" + hashCode() + ") on " + this);
|
|
| 1297 | - }
|
|
| 1298 | - return new com.sap.sse.common.Util.Pair<Regatta, Boolean>(regatta, wasCreated);
|
|
| 1299 | - }
|
|
| 1300 | -
|
|
| 1301 | - private boolean addAndConnectRegatta(boolean persistent, Serializable defaultCourseAreaId, Regatta regatta) {
|
|
| 1302 | - boolean wasCreated = false;
|
|
| 1303 | - // try a quick read protected by the concurrent hash map implementation
|
|
| 1304 | - if (!regattasByName.containsKey(regatta.getName())) {
|
|
| 1305 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 1306 | - try {
|
|
| 1307 | - // check again, now that we hold the exclusive write lock
|
|
| 1308 | - if (!regattasByName.containsKey(regatta.getName())) {
|
|
| 1309 | - wasCreated = true;
|
|
| 1310 | - logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode()
|
|
| 1311 | - + ") into regattasByName of " + this);
|
|
| 1312 | - regattasByName.put(regatta.getName(), regatta);
|
|
| 1313 | - regatta.addRegattaListener(this);
|
|
| 1314 | - regatta.addRaceColumnListener(raceLogReplicator);
|
|
| 1315 | - regatta.addRaceColumnListener(raceLogScoringReplicator);
|
|
| 1316 | - }
|
|
| 1317 | - } finally {
|
|
| 1318 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 1319 | - }
|
|
| 1320 | - }
|
|
| 1321 | - if (persistent) {
|
|
| 1322 | - updateStoredRegatta(regatta);
|
|
| 1323 | - }
|
|
| 1324 | - for (Event event : getAllEvents()) {
|
|
| 1325 | - for (CourseArea eventCourseArea : event.getVenue().getCourseAreas()) {
|
|
| 1326 | - if (defaultCourseAreaId != null && eventCourseArea.getId().equals(defaultCourseAreaId)) {
|
|
| 1327 | - event.addRegatta(regatta);
|
|
| 1328 | - }
|
|
| 1329 | - }
|
|
| 1330 | - }
|
|
| 1331 | - return wasCreated;
|
|
| 1332 | - }
|
|
| 1333 | -
|
|
| 1334 | - @Override
|
|
| 1335 | - public void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition) {
|
|
| 1336 | - Regatta regatta = getRegatta(addToRegatta);
|
|
| 1337 | - regatta.addRace(raceDefinition); // will trigger the raceAdded operation because this service is listening on
|
|
| 1338 | - // all its regattas
|
|
| 1339 | - }
|
|
| 1340 | -
|
|
| 1341 | - /**
|
|
| 1342 | - * If the <code>regatta</code> {@link Regatta#isPersistent() is a persistent one}, the association of the race with
|
|
| 1343 | - * the regatta is remembered persistently so that {@link #getRememberedRegattaForRace(Serializable)} will provide
|
|
| 1344 | - * it.
|
|
| 1345 | - */
|
|
| 1346 | - @Override
|
|
| 1347 | - public void raceAdded(Regatta regatta, RaceDefinition raceDefinition) {
|
|
| 1348 | - if (regatta.isPersistent()) {
|
|
| 1349 | - setRegattaForRace(regatta, raceDefinition);
|
|
| 1350 | - }
|
|
| 1351 | - final CourseChangeReplicator listener = new CourseChangeReplicator(this, regatta, raceDefinition);
|
|
| 1352 | - courseListeners.put(raceDefinition, listener);
|
|
| 1353 | - raceDefinition.getCourse().addCourseListener(listener);
|
|
| 1354 | - replicate(new AddRaceDefinition(regatta.getRegattaIdentifier(), raceDefinition));
|
|
| 1355 | - }
|
|
| 1356 | -
|
|
| 1357 | - @Override
|
|
| 1358 | - public void raceRemoved(Regatta regatta, RaceDefinition raceDefinition) {
|
|
| 1359 | - raceDefinition.getCourse().removeCourseListener(courseListeners.remove(raceDefinition));
|
|
| 1360 | - }
|
|
| 1361 | -
|
|
| 1362 | - private NamedReentrantReadWriteLock lockRaceTrackersById(Object trackerId) {
|
|
| 1363 | - NamedReentrantReadWriteLock lock;
|
|
| 1364 | - synchronized (raceTrackersByIDLocks) {
|
|
| 1365 | - lock = raceTrackersByIDLocks.get(trackerId);
|
|
| 1366 | - if (lock == null) {
|
|
| 1367 | - lock = new NamedReentrantReadWriteLock("raceTrackersByIDLock for " + trackerId, /* fair */false);
|
|
| 1368 | - raceTrackersByIDLocks.put(trackerId, lock);
|
|
| 1369 | - }
|
|
| 1370 | - }
|
|
| 1371 | - LockUtil.lockForWrite(lock);
|
|
| 1372 | - return lock;
|
|
| 1373 | - }
|
|
| 1374 | -
|
|
| 1375 | - /**
|
|
| 1376 | - * @param lock
|
|
| 1377 | - * need to pass the lock obtained from {@link #lockRaceTrackersById(Object)} because a competing thread
|
|
| 1378 | - * may already have removed the lock from the {@link #raceTrackersByIDLocks} map
|
|
| 1379 | - */
|
|
| 1380 | - private void unlockRaceTrackersById(Object trackerId, NamedReentrantReadWriteLock lock) {
|
|
| 1381 | - LockUtil.unlockAfterWrite(lock);
|
|
| 1382 | - synchronized (raceTrackersByIDLocks) {
|
|
| 1383 | - raceTrackersByIDLocks.remove(trackerId);
|
|
| 1384 | - }
|
|
| 1385 | - }
|
|
| 1386 | -
|
|
| 1387 | - @Override
|
|
| 1388 | - public RaceHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params,
|
|
| 1389 | - long timeoutInMilliseconds) throws Exception {
|
|
| 1390 | - final Object trackerID = params.getTrackerID();
|
|
| 1391 | - NamedReentrantReadWriteLock raceTrackersByIdLock = lockRaceTrackersById(trackerID);
|
|
| 1392 | - try {
|
|
| 1393 | - RaceTracker tracker = raceTrackersByID.get(trackerID);
|
|
| 1394 | - if (tracker == null) {
|
|
| 1395 | - Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo);
|
|
| 1396 | - if (regatta == null) {
|
|
| 1397 | - // create tracker and use an existing or create a default regatta
|
|
| 1398 | - tracker = params.createRaceTracker(this, windStore, gpsFixStore, /* raceLogResolver */ this);
|
|
| 1399 | - } else {
|
|
| 1400 | - // use the regatta selected by the RaceIdentifier regattaToAddTo
|
|
| 1401 | - tracker = params.createRaceTracker(regatta, this, windStore, gpsFixStore, /* raceLogResolver */ this);
|
|
| 1402 | - assert tracker.getRegatta() == regatta;
|
|
| 1403 | - }
|
|
| 1404 | - LockUtil.lockForWrite(raceTrackersByRegattaLock);
|
|
| 1405 | - try {
|
|
| 1406 | - raceTrackersByID.put(trackerID, tracker);
|
|
| 1407 | - Set<RaceTracker> trackers = raceTrackersByRegatta.get(tracker.getRegatta());
|
|
| 1408 | - if (trackers == null) {
|
|
| 1409 | - trackers = Collections.newSetFromMap(new ConcurrentHashMap<RaceTracker, Boolean>());
|
|
| 1410 | - raceTrackersByRegatta.put(tracker.getRegatta(), trackers);
|
|
| 1411 | - }
|
|
| 1412 | - trackers.add(tracker);
|
|
| 1413 | - } finally {
|
|
| 1414 | - LockUtil.unlockAfterWrite(raceTrackersByRegattaLock);
|
|
| 1415 | - }
|
|
| 1416 | - // TODO we assume here that the regatta name is unique which necessitates adding the boat class name to
|
|
| 1417 | - // it in RegattaImpl constructor
|
|
| 1418 | - String regattaName = tracker.getRegatta().getName();
|
|
| 1419 | - Regatta regattaWithName = regattasByName.get(regattaName);
|
|
| 1420 | - // TODO we assume here that the regatta name is unique which necessitates adding the boat class name to
|
|
| 1421 | - // it in RegattaImpl constructor
|
|
| 1422 | - if (regattaWithName != null) {
|
|
| 1423 | - if (regattaWithName != tracker.getRegatta()) {
|
|
| 1424 | - if (Util.isEmpty(regattaWithName.getAllRaces())) {
|
|
| 1425 | - // probably, tracker removed the last races from the old regatta and created a new one
|
|
| 1426 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 1427 | - try {
|
|
| 1428 | - regattasByName.remove(regattaName);
|
|
| 1429 | - cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
|
| 1430 | - } finally {
|
|
| 1431 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 1432 | - }
|
|
| 1433 | - } else {
|
|
| 1434 | - throw new RuntimeException("Internal error. Two regatta objects with equal name "
|
|
| 1435 | - + regattaName);
|
|
| 1436 | - }
|
|
| 1437 | - }
|
|
| 1438 | - } else {
|
|
| 1439 | - cacheAndReplicateDefaultRegatta(tracker.getRegatta());
|
|
| 1440 | - }
|
|
| 1441 | - } else {
|
|
| 1442 | - logger.warning("Race tracker with ID "+trackerID+" already found; not tracking twice to avoid race duplication");
|
|
| 1443 | - WindStore existingTrackersWindStore = tracker.getWindStore();
|
|
| 1444 | - if (!existingTrackersWindStore.equals(windStore)) {
|
|
| 1445 | - logger.warning("Wind store mismatch. Requested wind store: " + windStore
|
|
| 1446 | - + ". Wind store in use by existing tracker: " + existingTrackersWindStore);
|
|
| 1447 | - }
|
|
| 1448 | - GPSFixStore existingTrackersGPSFixStore = tracker.getGPSFixStore();
|
|
| 1449 | - if (!existingTrackersGPSFixStore.equals(gpsFixStore)) {
|
|
| 1450 | - logger.warning("GPSFix store mismatch. Requested GPSFix store: " + gpsFixStore
|
|
| 1451 | - + ". GPSFix store in use by existing tracker: " + existingTrackersGPSFixStore);
|
|
| 1452 | - }
|
|
| 1453 | - }
|
|
| 1454 | - if (timeoutInMilliseconds != -1) {
|
|
| 1455 | - scheduleAbortTrackerAfterInitialTimeout(tracker, timeoutInMilliseconds);
|
|
| 1456 | - }
|
|
| 1457 | - return tracker.getRacesHandle();
|
|
| 1458 | - } finally {
|
|
| 1459 | - unlockRaceTrackersById(trackerID, raceTrackersByIdLock);
|
|
| 1460 | - }
|
|
| 1461 | - }
|
|
| 1462 | -
|
|
| 1463 | - /**
|
|
| 1464 | - * The regatta and all its contained {@link Regatta#getAllRaces() races} are replicated to all replicas.
|
|
| 1465 | - *
|
|
| 1466 | - * @param regatta
|
|
| 1467 | - * the series of this regatta must not have any {@link Series#getRaceColumns() race columns associated
|
|
| 1468 | - * (yet)}.
|
|
| 1469 | - */
|
|
| 1470 | - private void replicateSpecificRegattaWithoutRaceColumns(Regatta regatta) {
|
|
| 1471 | - Serializable courseAreaId = null;
|
|
| 1472 | - if (regatta.getDefaultCourseArea() != null) {
|
|
| 1473 | - courseAreaId = regatta.getDefaultCourseArea().getId();
|
|
| 1474 | - }
|
|
| 1475 | - replicate(new AddSpecificRegatta(regatta.getName(), regatta.getBoatClass() == null ? null : regatta
|
|
| 1476 | - .getBoatClass().getName(), regatta.getStartDate(), regatta.getEndDate(), regatta.getId(),
|
|
| 1477 | - getSeriesWithoutRaceColumnsConstructionParametersAsMap(regatta), regatta.isPersistent(),
|
|
| 1478 | - regatta.getScoringScheme(), courseAreaId, regatta.useStartTimeInference(), regatta.getRankingMetricType()));
|
|
| 1479 | - RegattaIdentifier regattaIdentifier = regatta.getRegattaIdentifier();
|
|
| 1480 | - for (RaceDefinition race : regatta.getAllRaces()) {
|
|
| 1481 | - replicate(new AddRaceDefinition(regattaIdentifier, race));
|
|
| 1482 | - }
|
|
| 1483 | - }
|
|
| 1484 | -
|
|
| 1485 | - private RegattaCreationParametersDTO getSeriesWithoutRaceColumnsConstructionParametersAsMap(Regatta regatta) {
|
|
| 1486 | - LinkedHashMap<String, SeriesCreationParametersDTO> result = new LinkedHashMap<String, SeriesCreationParametersDTO>();
|
|
| 1487 | - for (Series s : regatta.getSeries()) {
|
|
| 1488 | - assert Util.isEmpty(s.getRaceColumns());
|
|
| 1489 | - List<FleetDTO> fleetNamesAndOrdering = new ArrayList<FleetDTO>();
|
|
| 1490 | - for (Fleet f : s.getFleets()) {
|
|
| 1491 | - fleetNamesAndOrdering.add(getBaseDomainFactory().convertToFleetDTO(f));
|
|
| 1492 | - }
|
|
| 1493 | - result.put(
|
|
| 1494 | - s.getName(),
|
|
| 1495 | - new SeriesCreationParametersDTO(fleetNamesAndOrdering, s.isMedal(), s.isStartsWithZeroScore(), s
|
|
| 1496 | - .isFirstColumnIsNonDiscardableCarryForward(), s.getResultDiscardingRule() == null ? null
|
|
| 1497 | - : s.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces(), s
|
|
| 1498 | - .hasSplitFleetContiguousScoring()));
|
|
| 1499 | - }
|
|
| 1500 | - return new RegattaCreationParametersDTO(result);
|
|
| 1501 | - }
|
|
| 1502 | -
|
|
| 1503 | - /**
|
|
| 1504 | - * If <code>regatta</code> is not yet in {@link #regattasByName}, it is added, this service is
|
|
| 1505 | - * {@link Regatta#addRegattaListener(RegattaListener) added} as regatta listener, and the regatta and all its
|
|
| 1506 | - * contained {@link Regatta#getAllRaces() races} are replicated to all replica.
|
|
| 1507 | - */
|
|
| 1508 | - private void cacheAndReplicateDefaultRegatta(Regatta regatta) {
|
|
| 1509 | - // try a quick read first, protected by regattasByName being a concurrent hash set
|
|
| 1510 | - if (!regattasByName.containsKey(regatta.getName())) {
|
|
| 1511 | - // now we need to obtain exclusive write access; in between, some other thread may have added a regatta by
|
|
| 1512 | - // that
|
|
| 1513 | - // name, so we need to check again:
|
|
| 1514 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 1515 | - try {
|
|
| 1516 | - if (!regattasByName.containsKey(regatta.getName())) {
|
|
| 1517 | - logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode()
|
|
| 1518 | - + ") into regattasByName of " + this);
|
|
| 1519 | - regattasByName.put(regatta.getName(), regatta);
|
|
| 1520 | - regatta.addRegattaListener(this);
|
|
| 1521 | - regatta.addRaceColumnListener(raceLogReplicator);
|
|
| 1522 | - regatta.addRaceColumnListener(raceLogScoringReplicator);
|
|
| 1523 | -
|
|
| 1524 | - replicate(new AddDefaultRegatta(regatta.getName(), regatta.getBoatClass() == null ? null : regatta
|
|
| 1525 | - .getBoatClass().getName(), regatta.getStartDate(), regatta.getEndDate(), regatta.getId()));
|
|
| 1526 | - RegattaIdentifier regattaIdentifier = regatta.getRegattaIdentifier();
|
|
| 1527 | - for (RaceDefinition race : regatta.getAllRaces()) {
|
|
| 1528 | - replicate(new AddRaceDefinition(regattaIdentifier, race));
|
|
| 1529 | - }
|
|
| 1530 | - }
|
|
| 1531 | - } finally {
|
|
| 1532 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 1533 | - }
|
|
| 1534 | - }
|
|
| 1535 | - }
|
|
| 1536 | -
|
|
| 1537 | - @Override
|
|
| 1538 | - public DynamicTrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore,
|
|
| 1539 | - GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
|
|
| 1540 | - long millisecondsOverWhichToAverageSpeed, boolean useMarkPassingCalculator) {
|
|
| 1541 | - DynamicTrackedRegatta trackedRegatta = getOrCreateTrackedRegatta(getRegatta(raceIdentifier));
|
|
| 1542 | - RaceDefinition race = getRace(raceIdentifier);
|
|
| 1543 | - return trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), windStore, gpsFixStore,
|
|
| 1544 | - delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
|
|
| 1545 | - /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this);
|
|
| 1546 | - }
|
|
| 1547 | -
|
|
| 1548 | - private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(
|
|
| 1549 | - DynamicTrackedRegatta trackedRegatta) {
|
|
| 1550 | - if (regattasObservedForDefaultLeaderboard.add(trackedRegatta)) {
|
|
| 1551 | - trackedRegatta.addRaceListener(new RaceAdditionListener());
|
|
| 1552 | - }
|
|
| 1553 | - }
|
|
| 1554 | -
|
|
| 1555 | - private void stopObservingRegattaForRedaultLeaderboardAndAutoLeaderboardLinking(DynamicTrackedRegatta trackedRegatta) {
|
|
| 1556 | - regattasObservedForDefaultLeaderboard.remove(trackedRegatta);
|
|
| 1557 | - }
|
|
| 1558 | -
|
|
| 1559 | - /**
|
|
| 1560 | - * A listener class used to ensure that when a tracked race is added to any {@link TrackedRegatta} managed by this
|
|
| 1561 | - * service, the service adds the tracked race to the default leaderboard and links it to the leaderboard columns
|
|
| 1562 | - * that were previously connected to it. Additionally, a {@link RaceChangeListener} is added to the
|
|
| 1563 | - * {@link TrackedRace} which is responsible for triggering the replication of all relevant changes to the tracked
|
|
| 1564 | - * race. When a tracked race is removed, the {@link TrackedRaceReplicator} that was added as listener to that
|
|
| 1565 | - * tracked race is removed again.
|
|
| 1566 | - *
|
|
| 1567 | - * A {@link PolarFixCacheUpdater} is added to every race so that polar fixes are aggregated when new GPS fixes
|
|
| 1568 | - * arrive.
|
|
| 1569 | - *
|
|
| 1570 | - * @author Axel Uhl (d043530)
|
|
| 1571 | - *
|
|
| 1572 | - */
|
|
| 1573 | - private class RaceAdditionListener implements RaceListener, Serializable {
|
|
| 1574 | - private static final long serialVersionUID = 1036955460477000265L;
|
|
| 1575 | -
|
|
| 1576 | - private final Map<TrackedRace, TrackedRaceReplicator> trackedRaceReplicators;
|
|
| 1577 | -
|
|
| 1578 | - private final Map<TrackedRace, PolarFixCacheUpdater> polarFixCacheUpdaters;
|
|
| 1579 | -
|
|
| 1580 | - public RaceAdditionListener() {
|
|
| 1581 | - this.trackedRaceReplicators = new HashMap<TrackedRace, TrackedRaceReplicator>();
|
|
| 1582 | - this.polarFixCacheUpdaters = new HashMap<TrackedRace, PolarFixCacheUpdater>();
|
|
| 1583 | - }
|
|
| 1584 | -
|
|
| 1585 | - @Override
|
|
| 1586 | - public void raceRemoved(TrackedRace trackedRace) {
|
|
| 1587 | - TrackedRaceReplicator trackedRaceReplicator = trackedRaceReplicators.remove(trackedRace);
|
|
| 1588 | - if (trackedRaceReplicator != null) {
|
|
| 1589 | - trackedRace.removeListener(trackedRaceReplicator);
|
|
| 1590 | - }
|
|
| 1591 | - PolarFixCacheUpdater polarFixCacheUpdater = polarFixCacheUpdaters.remove(trackedRace);
|
|
| 1592 | - if (polarFixCacheUpdater != null) {
|
|
| 1593 | - trackedRace.removeListener(polarFixCacheUpdater);
|
|
| 1594 | - }
|
|
| 1595 | - }
|
|
| 1596 | -
|
|
| 1597 | - @Override
|
|
| 1598 | - public void raceAdded(TrackedRace trackedRace) {
|
|
| 1599 | - // replicate the addition of the tracked race:
|
|
| 1600 | - CreateTrackedRace op = new CreateTrackedRace(trackedRace.getRaceIdentifier(), trackedRace.getWindStore(),
|
|
| 1601 | - trackedRace.getGPSFixStore(), trackedRace.getDelayToLiveInMillis(),
|
|
| 1602 | - trackedRace.getMillisecondsOverWhichToAverageWind(),
|
|
| 1603 | - trackedRace.getMillisecondsOverWhichToAverageSpeed());
|
|
| 1604 | - replicate(op);
|
|
| 1605 | - linkRaceToConfiguredLeaderboardColumns(trackedRace);
|
|
| 1606 | - TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace);
|
|
| 1607 | - trackedRaceReplicators.put(trackedRace, trackedRaceReplicator);
|
|
| 1608 | - trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */true, true);
|
|
| 1609 | -
|
|
| 1610 | - PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace);
|
|
| 1611 | - polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater);
|
|
| 1612 | - trackedRace.addListener(polarFixCacheUpdater);
|
|
| 1613 | -
|
|
| 1614 | - if (polarDataService != null) {
|
|
| 1615 | - trackedRace.setPolarDataService(polarDataService);
|
|
| 1616 | - }
|
|
| 1617 | - }
|
|
| 1618 | - }
|
|
| 1619 | -
|
|
| 1620 | - private class PolarFixCacheUpdater extends AbstractRaceChangeListener {
|
|
| 1621 | -
|
|
| 1622 | - private final TrackedRace race;
|
|
| 1623 | -
|
|
| 1624 | - public PolarFixCacheUpdater(TrackedRace race) {
|
|
| 1625 | - this.race = race;
|
|
| 1626 | - }
|
|
| 1627 | -
|
|
| 1628 | - @Override
|
|
| 1629 | - public void competitorPositionChanged(GPSFixMoving fix, Competitor item) {
|
|
| 1630 | - if (polarDataService != null) {
|
|
| 1631 | - polarDataService.competitorPositionChanged(fix, item, race);
|
|
| 1632 | - }
|
|
| 1633 | - }
|
|
| 1634 | -
|
|
| 1635 | - @Override
|
|
| 1636 | - public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
|
| 1637 | - if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING
|
|
| 1638 | - && newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) {
|
|
| 1639 | - if (polarDataService != null) {
|
|
| 1640 | - polarDataService.raceFinishedLoading(race);
|
|
| 1641 | - }
|
|
| 1642 | - }
|
|
| 1643 | - }
|
|
| 1644 | -
|
|
| 1645 | - }
|
|
| 1646 | -
|
|
| 1647 | - private class TrackedRaceReplicator implements RaceChangeListener {
|
|
| 1648 | - private final TrackedRace trackedRace;
|
|
| 1649 | -
|
|
| 1650 | - public TrackedRaceReplicator(TrackedRace trackedRace) {
|
|
| 1651 | - this.trackedRace = trackedRace;
|
|
| 1652 | - }
|
|
| 1653 | -
|
|
| 1654 | - @Override
|
|
| 1655 | - public void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude) {
|
|
| 1656 | - replicate(new UpdateWindSourcesToExclude(getRaceIdentifier(), windSourcesToExclude));
|
|
| 1657 | - }
|
|
| 1658 | -
|
|
| 1659 | - @Override
|
|
| 1660 | - public void startOfTrackingChanged(TimePoint startOfTracking) {
|
|
| 1661 | - replicate(new UpdateStartOfTracking(getRaceIdentifier(), startOfTracking));
|
|
| 1662 | - }
|
|
| 1663 | -
|
|
| 1664 | - @Override
|
|
| 1665 | - public void endOfTrackingChanged(TimePoint endOfTracking) {
|
|
| 1666 | - replicate(new UpdateEndOfTracking(getRaceIdentifier(), endOfTracking));
|
|
| 1667 | - }
|
|
| 1668 | -
|
|
| 1669 | - @Override
|
|
| 1670 | - public void startTimeReceivedChanged(TimePoint startTimeReceived) {
|
|
| 1671 | - replicate(new UpdateStartTimeReceived(getRaceIdentifier(), startTimeReceived));
|
|
| 1672 | - }
|
|
| 1673 | -
|
|
| 1674 | - @Override
|
|
| 1675 | - public void startOfRaceChanged(TimePoint oldStartOfRace, TimePoint newStartOfRace) {
|
|
| 1676 | - // no action required; the update signaled by this call is implicit; for explicit updates
|
|
| 1677 | - // see raceTimesChanged(TimePoint, TimePoint, TimePoint).
|
|
| 1678 | - }
|
|
| 1679 | -
|
|
| 1680 | - @Override
|
|
| 1681 | - public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
|
|
| 1682 | - // no-op; the course change is replicated by the separate CourseChangeReplicator
|
|
| 1683 | - }
|
|
| 1684 | -
|
|
| 1685 | - @Override
|
|
| 1686 | - public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
|
|
| 1687 | - // no-op; the course change is replicated by the separate CourseChangeReplicator
|
|
| 1688 | - }
|
|
| 1689 | -
|
|
| 1690 | - @Override
|
|
| 1691 | - public void delayToLiveChanged(long delayToLiveInMillis) {
|
|
| 1692 | - replicate(new UpdateRaceDelayToLive(getRaceIdentifier(), delayToLiveInMillis));
|
|
| 1693 | - }
|
|
| 1694 | -
|
|
| 1695 | - @Override
|
|
| 1696 | - public void windDataReceived(Wind wind, WindSource windSource) {
|
|
| 1697 | - replicate(new RecordWindFix(getRaceIdentifier(), windSource, wind));
|
|
| 1698 | - }
|
|
| 1699 | -
|
|
| 1700 | - @Override
|
|
| 1701 | - public void windDataRemoved(Wind wind, WindSource windSource) {
|
|
| 1702 | - replicate(new RemoveWindFix(getRaceIdentifier(), windSource, wind));
|
|
| 1703 | - }
|
|
| 1704 | -
|
|
| 1705 | - @Override
|
|
| 1706 | - public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
|
| 1707 | - replicate(new UpdateWindAveragingTime(getRaceIdentifier(), newMillisecondsOverWhichToAverage));
|
|
| 1708 | - }
|
|
| 1709 | -
|
|
| 1710 | - @Override
|
|
| 1711 | - public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
|
|
| 1712 | - replicate(new RecordCompetitorGPSFix(getRaceIdentifier(), competitor, fix));
|
|
| 1713 | - }
|
|
| 1714 | -
|
|
| 1715 | - @Override
|
|
| 1716 | - public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
|
| 1717 | - replicate(new UpdateTrackedRaceStatus(getRaceIdentifier(), newStatus));
|
|
| 1718 | - }
|
|
| 1719 | -
|
|
| 1720 | - @Override
|
|
| 1721 | - public void markPositionChanged(GPSFix fix, Mark mark, boolean firstInTrack) {
|
|
| 1722 | - final RecordMarkGPSFix operation;
|
|
| 1723 | - if (firstInTrack) {
|
|
| 1724 | - operation = new RecordMarkGPSFixForNewMarkTrack(getRaceIdentifier(), mark, fix);
|
|
| 1725 | - } else {
|
|
| 1726 | - operation = new RecordMarkGPSFixForExistingTrack(getRaceIdentifier(), mark, fix);
|
|
| 1727 | - }
|
|
| 1728 | - replicate(operation);
|
|
| 1729 | - }
|
|
| 1730 | -
|
|
| 1731 | - @Override
|
|
| 1732 | - public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings,
|
|
| 1733 | - Iterable<MarkPassing> markPassings) {
|
|
| 1734 | - replicate(new UpdateMarkPassings(getRaceIdentifier(), competitor, markPassings));
|
|
| 1735 | - }
|
|
| 1736 | -
|
|
| 1737 | - @Override
|
|
| 1738 | - public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
|
| 1739 | - replicate(new UpdateWindAveragingTime(getRaceIdentifier(), newMillisecondsOverWhichToAverage));
|
|
| 1740 | - }
|
|
| 1741 | -
|
|
| 1742 | - private RegattaAndRaceIdentifier getRaceIdentifier() {
|
|
| 1743 | - return trackedRace.getRaceIdentifier();
|
|
| 1744 | - }
|
|
| 1745 | -
|
|
| 1746 | - }
|
|
| 1747 | -
|
|
| 1748 | - /**
|
|
| 1749 | - * Based on the <code>trackedRace</code>'s {@link TrackedRace#getRaceIdentifier() race identifier}, the tracked race
|
|
| 1750 | - * is (re-)associated to all {@link RaceColumn race columns} that currently have no
|
|
| 1751 | - * {@link RaceColumn#getTrackedRace(Fleet) tracked race assigned} and whose
|
|
| 1752 | - * {@link RaceColumn#getRaceIdentifier(Fleet) race identifier} equals that of <code>trackedRace</code>.
|
|
| 1753 | - */
|
|
| 1754 | - private void linkRaceToConfiguredLeaderboardColumns(TrackedRace trackedRace) {
|
|
| 1755 | - boolean leaderboardHasChanged = false;
|
|
| 1756 | - RegattaAndRaceIdentifier trackedRaceIdentifier = trackedRace.getRaceIdentifier();
|
|
| 1757 | - for (Leaderboard leaderboard : getLeaderboards().values()) {
|
|
| 1758 | - for (RaceColumn column : leaderboard.getRaceColumns()) {
|
|
| 1759 | - for (Fleet fleet : column.getFleets()) {
|
|
| 1760 | - if (trackedRaceIdentifier.equals(column.getRaceIdentifier(fleet))
|
|
| 1761 | - && column.getTrackedRace(fleet) == null) {
|
|
| 1762 | - column.setTrackedRace(fleet, trackedRace);
|
|
| 1763 | - leaderboardHasChanged = true;
|
|
| 1764 | - replicate(new ConnectTrackedRaceToLeaderboardColumn(leaderboard.getName(), column.getName(),
|
|
| 1765 | - fleet.getName(), trackedRaceIdentifier));
|
|
| 1766 | - }
|
|
| 1767 | - }
|
|
| 1768 | - }
|
|
| 1769 | - if (leaderboardHasChanged) {
|
|
| 1770 | - // Update the corresponding groups, to keep them in sync
|
|
| 1771 | - syncGroupsAfterLeaderboardChange(leaderboard, /* doDatabaseUpdate */false);
|
|
| 1772 | - }
|
|
| 1773 | - }
|
|
| 1774 | - }
|
|
| 1775 | -
|
|
| 1776 | - @Override
|
|
| 1777 | - public void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException {
|
|
| 1778 | - final Set<RaceTracker> trackersForRegatta = raceTrackersByRegatta.get(regatta);
|
|
| 1779 | - if (trackersForRegatta != null) {
|
|
| 1780 | - for (RaceTracker raceTracker : trackersForRegatta) {
|
|
| 1781 | - final Set<RaceDefinition> races = raceTracker.getRaces();
|
|
| 1782 | - if (races != null) {
|
|
| 1783 | - for (RaceDefinition race : races) {
|
|
| 1784 | - stopTrackingWind(regatta, race);
|
|
| 1785 | - }
|
|
| 1786 | - }
|
|
| 1787 | - raceTracker.stop(/* preemptive */false);
|
|
| 1788 | - final Object trackerId = raceTracker.getID();
|
|
| 1789 | - final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId);
|
|
| 1790 | - try {
|
|
| 1791 | - raceTrackersByID.remove(trackerId);
|
|
| 1792 | - } finally {
|
|
| 1793 | - unlockRaceTrackersById(trackerId, lock);
|
|
| 1794 | - }
|
|
| 1795 | - raceTrackersByID.remove(trackerId);
|
|
| 1796 | - }
|
|
| 1797 | - LockUtil.lockForWrite(raceTrackersByRegattaLock);
|
|
| 1798 | - try {
|
|
| 1799 | - raceTrackersByRegatta.remove(regatta);
|
|
| 1800 | - } finally {
|
|
| 1801 | - LockUtil.unlockAfterWrite(raceTrackersByRegattaLock);
|
|
| 1802 | - }
|
|
| 1803 | - }
|
|
| 1804 | - }
|
|
| 1805 | -
|
|
| 1806 | - @Override
|
|
| 1807 | - public void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException {
|
|
| 1808 | - stopTracking(regatta);
|
|
| 1809 | - if (regatta != null) {
|
|
| 1810 | - if (regatta.getName() != null) {
|
|
| 1811 | - logger.info("Removing regatta " + regatta.getName() + " (" + regatta.hashCode() + ") from " + this);
|
|
| 1812 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 1813 | - try {
|
|
| 1814 | - regattasByName.remove(regatta.getName());
|
|
| 1815 | - } finally {
|
|
| 1816 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 1817 | - }
|
|
| 1818 | - LockUtil.lockForWrite(regattaTrackingCacheLock);
|
|
| 1819 | - try {
|
|
| 1820 | - regattaTrackingCache.remove(regatta);
|
|
| 1821 | - } finally {
|
|
| 1822 | - LockUtil.unlockAfterWrite(regattaTrackingCacheLock);
|
|
| 1823 | - }
|
|
| 1824 | - regatta.removeRegattaListener(this);
|
|
| 1825 | - regatta.removeRaceColumnListener(raceLogReplicator);
|
|
| 1826 | - regatta.removeRaceColumnListener(raceLogScoringReplicator);
|
|
| 1827 | - }
|
|
| 1828 | - for (RaceDefinition race : regatta.getAllRaces()) {
|
|
| 1829 | - stopTrackingWind(regatta, race);
|
|
| 1830 | - }
|
|
| 1831 | - }
|
|
| 1832 | - }
|
|
| 1833 | -
|
|
| 1834 | - /**
|
|
| 1835 | - * The tracker will initially try to connect to the tracking infrastructure to obtain basic race master data. If
|
|
| 1836 | - * this fails after some timeout, to avoid garbage and lingering threads, the task scheduled by this method will
|
|
| 1837 | - * check after the timeout expires if race master data was successfully received. If so, the tracker continues
|
|
| 1838 | - * normally. Otherwise, the tracker is shut down orderly by calling {@link RaceTracker#stop(boolean) stopping}.
|
|
| 1839 | - *
|
|
| 1840 | - * @return the scheduled task, in case the caller wants to {@link ScheduledFuture#cancel(boolean) cancel} it, e.g.,
|
|
| 1841 | - * when the tracker is stopped or has successfully received the race
|
|
| 1842 | - */
|
|
| 1843 | - private ScheduledFuture<?> scheduleAbortTrackerAfterInitialTimeout(final RaceTracker tracker,
|
|
| 1844 | - final long timeoutInMilliseconds) {
|
|
| 1845 | - ScheduledFuture<?> task = getScheduler().schedule(new Runnable() {
|
|
| 1846 | - @Override
|
|
| 1847 | - public void run() {
|
|
| 1848 | - if (tracker.getRaces() == null || tracker.getRaces().isEmpty()) {
|
|
| 1849 | - try {
|
|
| 1850 | - Regatta regatta = tracker.getRegatta();
|
|
| 1851 | - logger.log(Level.SEVERE, "RaceDefinition for a race in regatta " + regatta.getName()
|
|
| 1852 | - + " not obtained within " + timeoutInMilliseconds
|
|
| 1853 | - + "ms. Aborting tracker for this race.");
|
|
| 1854 | - Set<RaceTracker> trackersForRegatta = raceTrackersByRegatta.get(regatta);
|
|
| 1855 | - if (trackersForRegatta != null) {
|
|
| 1856 | - trackersForRegatta.remove(tracker);
|
|
| 1857 | - }
|
|
| 1858 | - tracker.stop(/* preemptive */true);
|
|
| 1859 | - final Object trackerId = tracker.getID();
|
|
| 1860 | - final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId);
|
|
| 1861 | - try {
|
|
| 1862 | - raceTrackersByID.remove(trackerId);
|
|
| 1863 | - } finally {
|
|
| 1864 | - unlockRaceTrackersById(trackerId, lock);
|
|
| 1865 | - }
|
|
| 1866 | - if (trackersForRegatta == null || trackersForRegatta.isEmpty()) {
|
|
| 1867 | - stopTracking(regatta);
|
|
| 1868 | - }
|
|
| 1869 | - } catch (Exception e) {
|
|
| 1870 | - logger.log(Level.SEVERE, "scheduleAbortTrackerAfterInitialTimeout", e);
|
|
| 1871 | - e.printStackTrace();
|
|
| 1872 | - }
|
|
| 1873 | - }
|
|
| 1874 | - }
|
|
| 1875 | - }, /* delay */timeoutInMilliseconds, /* unit */TimeUnit.MILLISECONDS);
|
|
| 1876 | - return task;
|
|
| 1877 | - }
|
|
| 1878 | -
|
|
| 1879 | - @Override
|
|
| 1880 | - public void stopTracking(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,
|
|
| 1881 | - InterruptedException {
|
|
| 1882 | - logger.info("Stopping tracking for " + race + "...");
|
|
| 1883 | - final Set<RaceTracker> trackerSet = raceTrackersByRegatta.get(regatta);
|
|
| 1884 | - if (trackerSet != null) {
|
|
| 1885 | - Iterator<RaceTracker> trackerIter = trackerSet.iterator();
|
|
| 1886 | - while (trackerIter.hasNext()) {
|
|
| 1887 | - RaceTracker raceTracker = trackerIter.next();
|
|
| 1888 | - if (raceTracker.getRaces() != null && raceTracker.getRaces().contains(race)) {
|
|
| 1889 | - logger.info("Found tracker to stop for races " + raceTracker.getRaces());
|
|
| 1890 | - raceTracker.stop(/* preemptive */false);
|
|
| 1891 | - trackerIter.remove();
|
|
| 1892 | - final Object trackerId = raceTracker.getID();
|
|
| 1893 | - final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId);
|
|
| 1894 | - try {
|
|
| 1895 | - raceTrackersByID.remove(trackerId);
|
|
| 1896 | - } finally {
|
|
| 1897 | - unlockRaceTrackersById(trackerId, lock);
|
|
| 1898 | - }
|
|
| 1899 | - }
|
|
| 1900 | - }
|
|
| 1901 | - } else {
|
|
| 1902 | - logger.warning("Didn't find any trackers for regatta " + regatta);
|
|
| 1903 | - }
|
|
| 1904 | - stopTrackingWind(regatta, race);
|
|
| 1905 | - // if the last tracked race was removed, confirm that tracking for the entire regatta has stopped
|
|
| 1906 | - if (trackerSet == null || trackerSet.isEmpty()) {
|
|
| 1907 | - stopTracking(regatta);
|
|
| 1908 | - }
|
|
| 1909 | - }
|
|
| 1910 | -
|
|
| 1911 | - @Override
|
|
| 1912 | - public void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException {
|
|
| 1913 | - Set<RegattaLeaderboard> leaderboardsToRemove = new HashSet<>();
|
|
| 1914 | - for (Leaderboard leaderboard : getLeaderboards().values()) {
|
|
| 1915 | - if (leaderboard instanceof RegattaLeaderboard) {
|
|
| 1916 | - RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard;
|
|
| 1917 | - if (regattaLeaderboard.getRegatta() == regatta) {
|
|
| 1918 | - leaderboardsToRemove.add(regattaLeaderboard);
|
|
| 1919 | - }
|
|
| 1920 | - }
|
|
| 1921 | - }
|
|
| 1922 | - for (RegattaLeaderboard regattaLeaderboardToRemove : leaderboardsToRemove) {
|
|
| 1923 | - removeLeaderboard(regattaLeaderboardToRemove.getName());
|
|
| 1924 | - }
|
|
| 1925 | - // avoid ConcurrentModificationException by copying the races to remove:
|
|
| 1926 | - Set<RaceDefinition> racesToRemove = new HashSet<>();
|
|
| 1927 | - Util.addAll(regatta.getAllRaces(), racesToRemove);
|
|
| 1928 | - for (RaceDefinition race : racesToRemove) {
|
|
| 1929 | - removeRace(regatta, race);
|
|
| 1930 | - mongoObjectFactory.removeRegattaForRaceID(race.getName(), regatta);
|
|
| 1931 | - persistentRegattasForRaceIDs.remove(race.getId().toString());
|
|
| 1932 | - }
|
|
| 1933 | - if (regatta.isPersistent()) {
|
|
| 1934 | - mongoObjectFactory.removeRegatta(regatta);
|
|
| 1935 | - }
|
|
| 1936 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 1937 | - try {
|
|
| 1938 | - regattasByName.remove(regatta.getName());
|
|
| 1939 | - } finally {
|
|
| 1940 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 1941 | - }
|
|
| 1942 | - regatta.removeRegattaListener(this);
|
|
| 1943 | - regatta.removeRaceColumnListener(raceLogReplicator);
|
|
| 1944 | - regatta.removeRaceColumnListener(raceLogScoringReplicator);
|
|
| 1945 | - onRegattaLikeRemoved(regatta);
|
|
| 1946 | - }
|
|
| 1947 | -
|
|
| 1948 | - @Override
|
|
| 1949 | - public void removeSeries(Series series) throws MalformedURLException, IOException, InterruptedException {
|
|
| 1950 | - Regatta regatta = series.getRegatta();
|
|
| 1951 | - regatta.removeSeries(series);
|
|
| 1952 | - if (regatta.isPersistent()) {
|
|
| 1953 | - mongoObjectFactory.storeRegatta(regatta);
|
|
| 1954 | - }
|
|
| 1955 | - }
|
|
| 1956 | -
|
|
| 1957 | - @Override
|
|
| 1958 | - public Regatta updateRegatta(RegattaIdentifier regattaIdentifier, TimePoint startDate, TimePoint endDate,
|
|
| 1959 | - Serializable newDefaultCourseAreaId, RegattaConfiguration newRegattaConfiguration,
|
|
| 1960 | - Iterable<? extends Series> series, boolean useStartTimeInference) {
|
|
| 1961 | - // We're not doing any renaming of the regatta itself, therefore we don't have to sync on the maps.
|
|
| 1962 | - Regatta regatta = getRegatta(regattaIdentifier);
|
|
| 1963 | - CourseArea newCourseArea = getCourseArea(newDefaultCourseAreaId);
|
|
| 1964 | - if (newCourseArea != regatta.getDefaultCourseArea()) {
|
|
| 1965 | - regatta.setDefaultCourseArea(newCourseArea);
|
|
| 1966 | - }
|
|
| 1967 | - regatta.setStartDate(startDate);
|
|
| 1968 | - regatta.setEndDate(endDate);
|
|
| 1969 | - if (regatta.useStartTimeInference() != useStartTimeInference) {
|
|
| 1970 | - regatta.setUseStartTimeInference(useStartTimeInference);
|
|
| 1971 | - final DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta);
|
|
| 1972 | - if (trackedRegatta != null) {
|
|
| 1973 | - trackedRegatta.lockTrackedRacesForRead();
|
|
| 1974 | - try {
|
|
| 1975 | - for (DynamicTrackedRace trackedRace : trackedRegatta.getTrackedRaces()) {
|
|
| 1976 | - // the start times of the regatta's tracked races now have to be re-evaluated the next time they
|
|
| 1977 | - // are queried
|
|
| 1978 | - trackedRace.invalidateStartTime();
|
|
| 1979 | - }
|
|
| 1980 | - } finally {
|
|
| 1981 | - trackedRegatta.unlockTrackedRacesAfterRead();
|
|
| 1982 | - }
|
|
| 1983 | - }
|
|
| 1984 | - }
|
|
| 1985 | - regatta.setRegattaConfiguration(newRegattaConfiguration);
|
|
| 1986 | - if (series != null) {
|
|
| 1987 | - for (Series seriesObj : series) {
|
|
| 1988 | - regatta.addSeries(seriesObj);
|
|
| 1989 | - }
|
|
| 1990 | - }
|
|
| 1991 | - regatta.adjustEventToRegattaAssociation(this);
|
|
| 1992 | - if (regatta.isPersistent()) {
|
|
| 1993 | - mongoObjectFactory.storeRegatta(regatta);
|
|
| 1994 | - }
|
|
| 1995 | - return regatta;
|
|
| 1996 | - }
|
|
| 1997 | -
|
|
| 1998 | - @Override
|
|
| 1999 | - public void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,
|
|
| 2000 | - InterruptedException {
|
|
| 2001 | - logger.info("Removing the race " + race + "...");
|
|
| 2002 | - stopAllTrackersForWhichRaceIsLastReachable(regatta, race);
|
|
| 2003 | - stopTrackingWind(regatta, race);
|
|
| 2004 | - TrackedRace trackedRace = getExistingTrackedRace(regatta, race);
|
|
| 2005 | - if (trackedRace != null) {
|
|
| 2006 | - TrackedRegatta trackedRegatta = getTrackedRegatta(regatta);
|
|
| 2007 | - final boolean isTrackedRacesEmpty;
|
|
| 2008 | - if (trackedRegatta != null) {
|
|
| 2009 | - trackedRegatta.lockTrackedRacesForWrite();
|
|
| 2010 | - try {
|
|
| 2011 | - trackedRegatta.removeTrackedRace(trackedRace);
|
|
| 2012 | - isTrackedRacesEmpty = Util.isEmpty(trackedRegatta.getTrackedRaces());
|
|
| 2013 | - } finally {
|
|
| 2014 | - trackedRegatta.unlockTrackedRacesAfterWrite();
|
|
| 2015 | - }
|
|
| 2016 | - } else {
|
|
| 2017 | - isTrackedRacesEmpty = false;
|
|
| 2018 | - }
|
|
| 2019 | - if (isTrackedRacesEmpty) {
|
|
| 2020 | - removeTrackedRegatta(regatta);
|
|
| 2021 | - }
|
|
| 2022 | - // remove tracked race from RaceColumns of regatta
|
|
| 2023 | - for (Series series : regatta.getSeries()) {
|
|
| 2024 | - for (RaceColumnInSeries raceColumn : series.getRaceColumns()) {
|
|
| 2025 | - for (Fleet fleet : series.getFleets()) {
|
|
| 2026 | - if (raceColumn.getTrackedRace(fleet) == trackedRace) {
|
|
| 2027 | - raceColumn.releaseTrackedRace(fleet);
|
|
| 2028 | - }
|
|
| 2029 | - }
|
|
| 2030 | - }
|
|
| 2031 | - }
|
|
| 2032 | - for (Leaderboard leaderboard : getLeaderboards().values()) {
|
|
| 2033 | - if (leaderboard instanceof FlexibleLeaderboard) { // RegattaLeaderboards have implicitly been updated by
|
|
| 2034 | - // the code above
|
|
| 2035 | - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
|
| 2036 | - for (Fleet fleet : raceColumn.getFleets()) {
|
|
| 2037 | - if (raceColumn.getTrackedRace(fleet) == trackedRace) {
|
|
| 2038 | - raceColumn.releaseTrackedRace(fleet); // but leave the RaceIdentifier on the race column
|
|
| 2039 | - // untouched, e.g., for later re-load
|
|
| 2040 | - }
|
|
| 2041 | - }
|
|
| 2042 | - }
|
|
| 2043 | - }
|
|
| 2044 | - }
|
|
| 2045 | - }
|
|
| 2046 | - // remove the race from the (default) regatta if the regatta is not persistently stored
|
|
| 2047 | - regatta.removeRace(race);
|
|
| 2048 | - if (!regatta.isPersistent() && Util.isEmpty(regatta.getAllRaces())) {
|
|
| 2049 | - logger.info("Removing regatta " + regatta.getName() + " (" + regatta.hashCode() + ") from service " + this);
|
|
| 2050 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 2051 | - try {
|
|
| 2052 | - regattasByName.remove(regatta.getName());
|
|
| 2053 | - } finally {
|
|
| 2054 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 2055 | - }
|
|
| 2056 | - regatta.removeRegattaListener(this);
|
|
| 2057 | - regatta.removeRaceColumnListener(raceLogReplicator);
|
|
| 2058 | - regatta.removeRaceColumnListener(raceLogScoringReplicator);
|
|
| 2059 | - }
|
|
| 2060 | - }
|
|
| 2061 | -
|
|
| 2062 | - /**
|
|
| 2063 | - * Doesn't stop any wind trackers
|
|
| 2064 | - */
|
|
| 2065 | - private void stopAllTrackersForWhichRaceIsLastReachable(Regatta regatta, RaceDefinition race)
|
|
| 2066 | - throws MalformedURLException, IOException, InterruptedException {
|
|
| 2067 | - if (raceTrackersByRegatta.containsKey(regatta)) {
|
|
| 2068 | - Iterator<RaceTracker> trackerIter = raceTrackersByRegatta.get(regatta).iterator();
|
|
| 2069 | - while (trackerIter.hasNext()) {
|
|
| 2070 | - RaceTracker raceTracker = trackerIter.next();
|
|
| 2071 | - if (raceTracker.getRaces() != null && raceTracker.getRaces().contains(race)) {
|
|
| 2072 | - boolean foundReachableRace = false;
|
|
| 2073 | - for (RaceDefinition raceTrackedByTracker : raceTracker.getRaces()) {
|
|
| 2074 | - if (raceTrackedByTracker != race && isReachable(regatta, raceTrackedByTracker)) {
|
|
| 2075 | - foundReachableRace = true;
|
|
| 2076 | - break;
|
|
| 2077 | - }
|
|
| 2078 | - }
|
|
| 2079 | - if (!foundReachableRace) {
|
|
| 2080 | - // firstly stop the tracker
|
|
| 2081 | - raceTracker.stop(/* preemptive */true);
|
|
| 2082 | - // remove it from the raceTrackers by Regatta
|
|
| 2083 | - trackerIter.remove();
|
|
| 2084 | - final Object trackerId = raceTracker.getID();
|
|
| 2085 | - final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId);
|
|
| 2086 | - try {
|
|
| 2087 | - raceTrackersByID.remove(trackerId);
|
|
| 2088 | - } finally {
|
|
| 2089 | - unlockRaceTrackersById(trackerId, lock);
|
|
| 2090 | - }
|
|
| 2091 | - // if the last tracked race was removed, remove the entire regatta
|
|
| 2092 | - if (raceTrackersByRegatta.get(regatta).isEmpty()) {
|
|
| 2093 | - stopTracking(regatta);
|
|
| 2094 | - }
|
|
| 2095 | - }
|
|
| 2096 | - }
|
|
| 2097 | - }
|
|
| 2098 | - }
|
|
| 2099 | - }
|
|
| 2100 | -
|
|
| 2101 | - private boolean isReachable(Regatta regatta, RaceDefinition race) {
|
|
| 2102 | - return Util.contains(regatta.getAllRaces(), race);
|
|
| 2103 | - }
|
|
| 2104 | -
|
|
| 2105 | - @Override
|
|
| 2106 | - public void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws Exception {
|
|
| 2107 | - for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) {
|
|
| 2108 | - windTrackerFactory.createWindTracker(getOrCreateTrackedRegatta(regatta), race, correctByDeclination);
|
|
| 2109 | - }
|
|
| 2110 | - }
|
|
| 2111 | -
|
|
| 2112 | - @Override
|
|
| 2113 | - public void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException {
|
|
| 2114 | - for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) {
|
|
| 2115 | - WindTracker windTracker = windTrackerFactory.getExistingWindTracker(race);
|
|
| 2116 | - if (windTracker != null) {
|
|
| 2117 | - windTracker.stop();
|
|
| 2118 | - }
|
|
| 2119 | - }
|
|
| 2120 | - }
|
|
| 2121 | -
|
|
| 2122 | - @Override
|
|
| 2123 | - public Iterable<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces() {
|
|
| 2124 | - List<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>> result = new ArrayList<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>>();
|
|
| 2125 | - for (Regatta regatta : getAllRegattas()) {
|
|
| 2126 | - for (RaceDefinition race : regatta.getAllRaces()) {
|
|
| 2127 | - for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) {
|
|
| 2128 | - WindTracker windTracker = windTrackerFactory.getExistingWindTracker(race);
|
|
| 2129 | - if (windTracker != null) {
|
|
| 2130 | - result.add(new com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>(regatta, race,
|
|
| 2131 | - windTracker.toString()));
|
|
| 2132 | - }
|
|
| 2133 | - }
|
|
| 2134 | - }
|
|
| 2135 | - }
|
|
| 2136 | - return result;
|
|
| 2137 | - }
|
|
| 2138 | -
|
|
| 2139 | - @Override
|
|
| 2140 | - public DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race) {
|
|
| 2141 | - return getOrCreateTrackedRegatta(regatta).getTrackedRace(race);
|
|
| 2142 | - }
|
|
| 2143 | -
|
|
| 2144 | - private DynamicTrackedRace getExistingTrackedRace(Regatta regatta, RaceDefinition race) {
|
|
| 2145 | - return getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race);
|
|
| 2146 | - }
|
|
| 2147 | -
|
|
| 2148 | - @Override
|
|
| 2149 | - public DynamicTrackedRegatta getOrCreateTrackedRegatta(Regatta regatta) {
|
|
| 2150 | - cacheAndReplicateDefaultRegatta(regatta);
|
|
| 2151 | - LockUtil.lockForWrite(regattaTrackingCacheLock);
|
|
| 2152 | - try {
|
|
| 2153 | - DynamicTrackedRegatta result = regattaTrackingCache.get(regatta);
|
|
| 2154 | - if (result == null) {
|
|
| 2155 | - logger.info("Creating DynamicTrackedRegattaImpl for regatta " + regatta.getName() + " with hashCode "
|
|
| 2156 | - + regatta.hashCode());
|
|
| 2157 | - result = new DynamicTrackedRegattaImpl(regatta);
|
|
| 2158 | - replicate(new TrackRegatta(regatta.getRegattaIdentifier()));
|
|
| 2159 | - regattaTrackingCache.put(regatta, result);
|
|
| 2160 | - ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(result);
|
|
| 2161 | - }
|
|
| 2162 | - return result;
|
|
| 2163 | - } finally {
|
|
| 2164 | - LockUtil.unlockAfterWrite(regattaTrackingCacheLock);
|
|
| 2165 | - }
|
|
| 2166 | - }
|
|
| 2167 | -
|
|
| 2168 | - @Override
|
|
| 2169 | - public DynamicTrackedRegatta getTrackedRegatta(com.sap.sailing.domain.base.Regatta regatta) {
|
|
| 2170 | - return regattaTrackingCache.get(regatta);
|
|
| 2171 | - }
|
|
| 2172 | -
|
|
| 2173 | - @Override
|
|
| 2174 | - public void removeTrackedRegatta(Regatta regatta) {
|
|
| 2175 | - logger.info("Removing regatta " + regatta.getName() + " from regattaTrackingCache");
|
|
| 2176 | - final DynamicTrackedRegatta trackedRegatta;
|
|
| 2177 | - LockUtil.lockForWrite(regattaTrackingCacheLock);
|
|
| 2178 | - try {
|
|
| 2179 | - trackedRegatta = regattaTrackingCache.remove(regatta);
|
|
| 2180 | - } finally {
|
|
| 2181 | - LockUtil.unlockAfterWrite(regattaTrackingCacheLock);
|
|
| 2182 | - }
|
|
| 2183 | - stopObservingRegattaForRedaultLeaderboardAndAutoLeaderboardLinking(trackedRegatta);
|
|
| 2184 | - }
|
|
| 2185 | -
|
|
| 2186 | - @Override
|
|
| 2187 | - public Regatta getRegatta(RegattaName regattaName) {
|
|
| 2188 | - return (Regatta) regattasByName.get(regattaName.getRegattaName());
|
|
| 2189 | - }
|
|
| 2190 | -
|
|
| 2191 | - @Override
|
|
| 2192 | - public Regatta getRegatta(RegattaIdentifier regattaIdentifier) {
|
|
| 2193 | - return (Regatta) regattaIdentifier.getRegatta(this);
|
|
| 2194 | - }
|
|
| 2195 | -
|
|
| 2196 | - @Override
|
|
| 2197 | - public DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
|
|
| 2198 | - DynamicTrackedRace result = null;
|
|
| 2199 | - Regatta regatta = regattasByName.get(raceIdentifier.getRegattaName());
|
|
| 2200 | - if (regatta != null) {
|
|
| 2201 | - DynamicTrackedRegatta trackedRegatta = regattaTrackingCache.get(regatta);
|
|
| 2202 | - if (trackedRegatta != null) {
|
|
| 2203 | - RaceDefinition race = getRace(raceIdentifier);
|
|
| 2204 | - if (race != null) {
|
|
| 2205 | - result = trackedRegatta.getTrackedRace(race);
|
|
| 2206 | - }
|
|
| 2207 | - }
|
|
| 2208 | - }
|
|
| 2209 | - return result;
|
|
| 2210 | - }
|
|
| 2211 | -
|
|
| 2212 | - @Override
|
|
| 2213 | - public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
|
|
| 2214 | - Regatta regatta = getRegattaByName(raceIdentifier.getRegattaName());
|
|
| 2215 | - DynamicTrackedRace trackedRace = null;
|
|
| 2216 | - if (regatta != null) {
|
|
| 2217 | - RaceDefinition race = regatta.getRaceByName(raceIdentifier.getRaceName());
|
|
| 2218 | - trackedRace = getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race);
|
|
| 2219 | - }
|
|
| 2220 | - return trackedRace;
|
|
| 2221 | - }
|
|
| 2222 | -
|
|
| 2223 | - @Override
|
|
| 2224 | - public RaceDefinition getRace(RegattaAndRaceIdentifier regattaNameAndRaceName) {
|
|
| 2225 | - RaceDefinition result = null;
|
|
| 2226 | - Regatta regatta = getRegatta(regattaNameAndRaceName);
|
|
| 2227 | - if (regatta != null) {
|
|
| 2228 | - result = regatta.getRaceByName(regattaNameAndRaceName.getRaceName());
|
|
| 2229 | - }
|
|
| 2230 | - return result;
|
|
| 2231 | - }
|
|
| 2232 | -
|
|
| 2233 | - @Override
|
|
| 2234 | - public Map<String, LeaderboardGroup> getLeaderboardGroups() {
|
|
| 2235 | - return Collections.unmodifiableMap(new HashMap<String, LeaderboardGroup>(leaderboardGroupsByName));
|
|
| 2236 | - }
|
|
| 2237 | -
|
|
| 2238 | - @Override
|
|
| 2239 | - public LeaderboardGroup getLeaderboardGroupByName(String groupName) {
|
|
| 2240 | - return leaderboardGroupsByName.get(groupName);
|
|
| 2241 | - }
|
|
| 2242 | -
|
|
| 2243 | - @Override
|
|
| 2244 | - public LeaderboardGroup getLeaderboardGroupByID(UUID leaderboardGroupID) {
|
|
| 2245 | - return leaderboardGroupsByID.get(leaderboardGroupID);
|
|
| 2246 | - }
|
|
| 2247 | -
|
|
| 2248 | - @Override
|
|
| 2249 | - public LeaderboardGroup addLeaderboardGroup(UUID id, String groupName, String description, String displayName,
|
|
| 2250 | - boolean displayGroupsInReverseOrder, List<String> leaderboardNames,
|
|
| 2251 | - int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType) {
|
|
| 2252 | - ArrayList<Leaderboard> leaderboards = new ArrayList<>();
|
|
| 2253 | - for (String leaderboardName : leaderboardNames) {
|
|
| 2254 | - Leaderboard leaderboard = leaderboardsByName.get(leaderboardName);
|
|
| 2255 | - if (leaderboard == null) {
|
|
| 2256 | - throw new IllegalArgumentException("No leaderboard with name " + leaderboardName + " found");
|
|
| 2257 | - } else {
|
|
| 2258 | - leaderboards.add(leaderboard);
|
|
| 2259 | - }
|
|
| 2260 | - }
|
|
| 2261 | - LeaderboardGroup result = new LeaderboardGroupImpl(id, groupName, description, displayName,
|
|
| 2262 | - displayGroupsInReverseOrder, leaderboards);
|
|
| 2263 | - if (overallLeaderboardScoringSchemeType != null) {
|
|
| 2264 | - // create overall leaderboard and its discards settings
|
|
| 2265 | - addOverallLeaderboardToLeaderboardGroup(result,
|
|
| 2266 | - getBaseDomainFactory().createScoringScheme(overallLeaderboardScoringSchemeType),
|
|
| 2267 | - overallLeaderboardDiscardThresholds);
|
|
| 2268 | - }
|
|
| 2269 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 2270 | - try {
|
|
| 2271 | - if (leaderboardGroupsByName.containsKey(groupName)) {
|
|
| 2272 | - throw new IllegalArgumentException("Leaderboard group with name " + groupName + " already exists");
|
|
| 2273 | - }
|
|
| 2274 | - leaderboardGroupsByName.put(groupName, result);
|
|
| 2275 | - leaderboardGroupsByID.put(result.getId(), result);
|
|
| 2276 | - } finally {
|
|
| 2277 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 2278 | - }
|
|
| 2279 | - mongoObjectFactory.storeLeaderboardGroup(result);
|
|
| 2280 | - return result;
|
|
| 2281 | - }
|
|
| 2282 | -
|
|
| 2283 | - @Override
|
|
| 2284 | - public void addLeaderboardGroupWithoutReplication(LeaderboardGroup leaderboardGroup) {
|
|
| 2285 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 2286 | - try {
|
|
| 2287 | - String groupName = leaderboardGroup.getName();
|
|
| 2288 | - if (leaderboardGroupsByName.containsKey(groupName)) {
|
|
| 2289 | - throw new IllegalArgumentException("Leaderboard group with name " + groupName + " already exists");
|
|
| 2290 | - }
|
|
| 2291 | - leaderboardGroupsByName.put(groupName, leaderboardGroup);
|
|
| 2292 | - leaderboardGroupsByID.put(leaderboardGroup.getId(), leaderboardGroup);
|
|
| 2293 | - } finally {
|
|
| 2294 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 2295 | - }
|
|
| 2296 | - if (leaderboardGroup.hasOverallLeaderboard()) {
|
|
| 2297 | - addLeaderboard(leaderboardGroup.getOverallLeaderboard());
|
|
| 2298 | - }
|
|
| 2299 | - mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup);
|
|
| 2300 | - }
|
|
| 2301 | -
|
|
| 2302 | - @Override
|
|
| 2303 | - public void removeLeaderboardGroup(String groupName) {
|
|
| 2304 | - final LeaderboardGroup leaderboardGroup;
|
|
| 2305 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 2306 | - try {
|
|
| 2307 | - leaderboardGroup = leaderboardGroupsByName.remove(groupName);
|
|
| 2308 | - if (leaderboardGroup != null) {
|
|
| 2309 | - leaderboardGroupsByID.remove(leaderboardGroup.getId());
|
|
| 2310 | - }
|
|
| 2311 | - } finally {
|
|
| 2312 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 2313 | - }
|
|
| 2314 | - mongoObjectFactory.removeLeaderboardGroup(groupName);
|
|
| 2315 | - if (leaderboardGroup != null && leaderboardGroup.getOverallLeaderboard() != null) {
|
|
| 2316 | - removeLeaderboard(leaderboardGroup.getOverallLeaderboard().getName());
|
|
| 2317 | - }
|
|
| 2318 | - }
|
|
| 2319 | -
|
|
| 2320 | - @Override
|
|
| 2321 | - public void renameLeaderboardGroup(String oldName, String newName) {
|
|
| 2322 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 2323 | - try {
|
|
| 2324 | - final LeaderboardGroup toRename = leaderboardGroupsByName.get(oldName);
|
|
| 2325 | - if (toRename == null) {
|
|
| 2326 | - throw new IllegalArgumentException("No leaderboard group with name " + oldName + " found");
|
|
| 2327 | - }
|
|
| 2328 | - if (leaderboardGroupsByName.containsKey(newName)) {
|
|
| 2329 | - throw new IllegalArgumentException("Leaderboard group with name " + newName + " already exists");
|
|
| 2330 | - }
|
|
| 2331 | - leaderboardGroupsByName.remove(oldName);
|
|
| 2332 | - toRename.setName(newName);
|
|
| 2333 | - leaderboardGroupsByName.put(newName, toRename);
|
|
| 2334 | - } finally {
|
|
| 2335 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 2336 | - }
|
|
| 2337 | - mongoObjectFactory.renameLeaderboardGroup(oldName, newName);
|
|
| 2338 | - }
|
|
| 2339 | -
|
|
| 2340 | - @Override
|
|
| 2341 | - public void updateLeaderboardGroup(String oldName, String newName, String description, String displayName,
|
|
| 2342 | - List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds,
|
|
| 2343 | - ScoringSchemeType overallLeaderboardScoringSchemeType) {
|
|
| 2344 | - if (!oldName.equals(newName)) {
|
|
| 2345 | - renameLeaderboardGroup(oldName, newName);
|
|
| 2346 | - }
|
|
| 2347 | - LeaderboardGroup group = getLeaderboardGroupByName(newName);
|
|
| 2348 | - if (!description.equals(group.getDescription())) {
|
|
| 2349 | - group.setDescriptiom(description);
|
|
| 2350 | - }
|
|
| 2351 | - if (!Util.equalsWithNull(displayName, group.getDisplayName())) {
|
|
| 2352 | - group.setDisplayName(displayName);
|
|
| 2353 | - }
|
|
| 2354 | - group.clearLeaderboards();
|
|
| 2355 | - for (String leaderboardName : leaderboardNames) {
|
|
| 2356 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 2357 | - if (leaderboard != null) {
|
|
| 2358 | - group.addLeaderboard(leaderboard);
|
|
| 2359 | - }
|
|
| 2360 | - }
|
|
| 2361 | - Leaderboard overallLeaderboard = group.getOverallLeaderboard();
|
|
| 2362 | - if (overallLeaderboard != null) {
|
|
| 2363 | - if (overallLeaderboardScoringSchemeType == null) {
|
|
| 2364 | - group.setOverallLeaderboard(null);
|
|
| 2365 | - removeLeaderboard(overallLeaderboard.getName());
|
|
| 2366 | - } else {
|
|
| 2367 | - // update existing overall leaderboard's discards settings; scoring scheme cannot be updated in-place
|
|
| 2368 | - overallLeaderboard.setCrossLeaderboardResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(
|
|
| 2369 | - overallLeaderboardDiscardThresholds));
|
|
| 2370 | - updateStoredLeaderboard(overallLeaderboard);
|
|
| 2371 | - }
|
|
| 2372 | - } else if (overallLeaderboard == null && overallLeaderboardScoringSchemeType != null) {
|
|
| 2373 | - addOverallLeaderboardToLeaderboardGroup(group,
|
|
| 2374 | - getBaseDomainFactory().createScoringScheme(overallLeaderboardScoringSchemeType),
|
|
| 2375 | - overallLeaderboardDiscardThresholds);
|
|
| 2376 | - }
|
|
| 2377 | - updateStoredLeaderboardGroup(group);
|
|
| 2378 | - }
|
|
| 2379 | -
|
|
| 2380 | - private void addOverallLeaderboardToLeaderboardGroup(LeaderboardGroup leaderboardGroup,
|
|
| 2381 | - ScoringScheme scoringScheme, int[] discardThresholds) {
|
|
| 2382 | - Leaderboard overallLeaderboard = new LeaderboardGroupMetaLeaderboard(leaderboardGroup, scoringScheme,
|
|
| 2383 | - new ThresholdBasedResultDiscardingRuleImpl(discardThresholds));
|
|
| 2384 | - leaderboardGroup.setOverallLeaderboard(overallLeaderboard);
|
|
| 2385 | - addLeaderboard(overallLeaderboard);
|
|
| 2386 | - updateStoredLeaderboard(overallLeaderboard);
|
|
| 2387 | - }
|
|
| 2388 | -
|
|
| 2389 | - @Override
|
|
| 2390 | - public void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup) {
|
|
| 2391 | - mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup);
|
|
| 2392 | - }
|
|
| 2393 | -
|
|
| 2394 | - private ScheduledExecutorService getScheduler() {
|
|
| 2395 | - return scheduler;
|
|
| 2396 | - }
|
|
| 2397 | -
|
|
| 2398 | - @Override
|
|
| 2399 | - public ObjectInputStream createObjectInputStreamResolvingAgainstCache(InputStream is) throws IOException {
|
|
| 2400 | - return getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory(is);
|
|
| 2401 | - }
|
|
| 2402 | -
|
|
| 2403 | - @Override
|
|
| 2404 | - public ClassLoader getDeserializationClassLoader() {
|
|
| 2405 | - return joinedClassLoader;
|
|
| 2406 | - }
|
|
| 2407 | -
|
|
| 2408 | - @Override
|
|
| 2409 | - public Serializable getId() {
|
|
| 2410 | - return getClass().getName();
|
|
| 2411 | - }
|
|
| 2412 | -
|
|
| 2413 | - @Override
|
|
| 2414 | - public Iterable<OperationExecutionListener<RacingEventService>> getOperationExecutionListeners() {
|
|
| 2415 | - return operationExecutionListeners.keySet();
|
|
| 2416 | - }
|
|
| 2417 | -
|
|
| 2418 | - @Override
|
|
| 2419 | - public void addOperationExecutionListener(OperationExecutionListener<RacingEventService> listener) {
|
|
| 2420 | - operationExecutionListeners.put(listener, listener);
|
|
| 2421 | - }
|
|
| 2422 | -
|
|
| 2423 | - @Override
|
|
| 2424 | - public void removeOperationExecutionListener(OperationExecutionListener<RacingEventService> listener) {
|
|
| 2425 | - operationExecutionListeners.remove(listener);
|
|
| 2426 | - }
|
|
| 2427 | -
|
|
| 2428 | - @Override
|
|
| 2429 | - public void serializeForInitialReplicationInternal(ObjectOutputStream oos) throws IOException {
|
|
| 2430 | - StringBuffer logoutput = new StringBuffer();
|
|
| 2431 | -
|
|
| 2432 | - logger.info("Serializing regattas...");
|
|
| 2433 | - oos.writeObject(regattasByName);
|
|
| 2434 | - logoutput.append("Serialized " + regattasByName.size() + " regattas\n");
|
|
| 2435 | - for (Regatta regatta : regattasByName.values()) {
|
|
| 2436 | - logoutput.append(String.format("%3s\n", regatta.toString()));
|
|
| 2437 | - }
|
|
| 2438 | -
|
|
| 2439 | - logger.info("Serializing events...");
|
|
| 2440 | - oos.writeObject(eventsById);
|
|
| 2441 | - logoutput.append("\nSerialized " + eventsById.size() + " events\n");
|
|
| 2442 | - for (Event event : eventsById.values()) {
|
|
| 2443 | - logoutput.append(String.format("%3s\n", event.toString()));
|
|
| 2444 | - }
|
|
| 2445 | -
|
|
| 2446 | - logger.info("Serializing regattas observed...");
|
|
| 2447 | - oos.writeObject(regattasObservedForDefaultLeaderboard);
|
|
| 2448 | - logger.info("Serializing regatta tracking cache...");
|
|
| 2449 | - oos.writeObject(regattaTrackingCache);
|
|
| 2450 | - logger.info("Serializing leaderboard groups...");
|
|
| 2451 | - oos.writeObject(leaderboardGroupsByName);
|
|
| 2452 | - logoutput.append("Serialized " + leaderboardGroupsByName.size() + " leaderboard groups\n");
|
|
| 2453 | - for (LeaderboardGroup lg : leaderboardGroupsByName.values()) {
|
|
| 2454 | - logoutput.append(String.format("%3s\n", lg.toString()));
|
|
| 2455 | - }
|
|
| 2456 | - logger.info("Serializing leaderboards...");
|
|
| 2457 | - oos.writeObject(leaderboardsByName);
|
|
| 2458 | - logoutput.append("Serialized " + leaderboardsByName.size() + " leaderboards\n");
|
|
| 2459 | - for (Leaderboard lg : leaderboardsByName.values()) {
|
|
| 2460 | - logoutput.append(String.format("%3s\n", lg.toString()));
|
|
| 2461 | - }
|
|
| 2462 | - logger.info("Serializing media library...");
|
|
| 2463 | - mediaLibrary.serialize(oos);
|
|
| 2464 | - logoutput.append("Serialized " + mediaLibrary.allTracks().size() + " media tracks\n");
|
|
| 2465 | - for (MediaTrack lg : mediaLibrary.allTracks()) {
|
|
| 2466 | - logoutput.append(String.format("%3s\n", lg.toString()));
|
|
| 2467 | - }
|
|
| 2468 | - logger.info("Serializing persisted competitors...");
|
|
| 2469 | - oos.writeObject(competitorStore);
|
|
| 2470 | - logoutput.append("Serialized " + competitorStore.size() + " persisted competitors\n");
|
|
| 2471 | -
|
|
| 2472 | - logger.info("Serializing configuration map...");
|
|
| 2473 | - oos.writeObject(configurationMap);
|
|
| 2474 | - logoutput.append("Serialized " + configurationMap.size() + " configuration entries\n");
|
|
| 2475 | - for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) {
|
|
| 2476 | - logoutput.append(String.format("%3s\n", matcher.toString()));
|
|
| 2477 | - }
|
|
| 2478 | -
|
|
| 2479 | - logger.info("Serializing remote sailing server references...");
|
|
| 2480 | - final ArrayList<RemoteSailingServerReference> remoteServerReferences = new ArrayList<>(remoteSailingServerSet
|
|
| 2481 | - .getCachedEventsForRemoteSailingServers().keySet());
|
|
| 2482 | - oos.writeObject(remoteServerReferences);
|
|
| 2483 | - logoutput.append("Serialized " + remoteServerReferences.size() + " remote sailing server references\n");
|
|
| 2484 | -
|
|
| 2485 | - logger.info(logoutput.toString());
|
|
| 2486 | - }
|
|
| 2487 | -
|
|
| 2488 | - @SuppressWarnings("unchecked")
|
|
| 2489 | - // all the casts of ois.readObject()'s return value to Map<..., ...>
|
|
| 2490 | - // the type-parameters in the casts of the de-serialized collection objects can't be checked
|
|
| 2491 | - @Override
|
|
| 2492 | - public void initiallyFillFromInternal(ObjectInputStream ois) throws IOException, ClassNotFoundException,
|
|
| 2493 | - InterruptedException {
|
|
| 2494 | - logger.info("Performing initial replication load on " + this);
|
|
| 2495 | - // Use this object's class's class loader as the context class loader which will then be used for
|
|
| 2496 | - // de-serialization; this will cause all classes to be visible that this bundle
|
|
| 2497 | - // (com.sap.sailing.server) can see
|
|
| 2498 | - StringBuffer logoutput = new StringBuffer();
|
|
| 2499 | - logger.info("Reading all regattas...");
|
|
| 2500 | - regattasByName.putAll((Map<String, Regatta>) ois.readObject());
|
|
| 2501 | - logoutput.append("Received " + regattasByName.size() + " NEW regattas\n");
|
|
| 2502 | - for (Regatta regatta : regattasByName.values()) {
|
|
| 2503 | - logoutput.append(String.format("%3s\n", regatta.toString()));
|
|
| 2504 | - }
|
|
| 2505 | -
|
|
| 2506 | - logger.info("Reading all events...");
|
|
| 2507 | - eventsById.putAll((Map<Serializable, Event>) ois.readObject());
|
|
| 2508 | - logoutput.append("\nReceived " + eventsById.size() + " NEW events\n");
|
|
| 2509 | - for (Event event : eventsById.values()) {
|
|
| 2510 | - logoutput.append(String.format("%3s\n", event.toString()));
|
|
| 2511 | - }
|
|
| 2512 | -
|
|
| 2513 | - // it is important that the leaderboards and tracked regattas are cleared before auto-linking to
|
|
| 2514 | - // old leaderboards takes place which then don't match the new ones
|
|
| 2515 | - logger.info("Reading all dynamic tracked regattas...");
|
|
| 2516 | - for (DynamicTrackedRegatta trackedRegattaToObserve : (Set<DynamicTrackedRegatta>) ois.readObject()) {
|
|
| 2517 | - ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(trackedRegattaToObserve);
|
|
| 2518 | - }
|
|
| 2519 | -
|
|
| 2520 | - logger.info("Reading all of the regatta tracking cache...");
|
|
| 2521 | - regattaTrackingCache.putAll((Map<Regatta, DynamicTrackedRegatta>) ois.readObject());
|
|
| 2522 | - logoutput.append("Received " + regattaTrackingCache.size() + " NEW regatta tracking cache entries\n");
|
|
| 2523 | -
|
|
| 2524 | - logger.info("Reading leaderboard groups...");
|
|
| 2525 | - leaderboardGroupsByName.putAll((Map<String, LeaderboardGroup>) ois.readObject());
|
|
| 2526 | - logoutput.append("Received " + leaderboardGroupsByName.size() + " NEW leaderboard groups\n");
|
|
| 2527 | - for (LeaderboardGroup lg : leaderboardGroupsByName.values()) {
|
|
| 2528 | - leaderboardGroupsByID.put(lg.getId(), lg);
|
|
| 2529 | - logoutput.append(String.format("%3s\n", lg.toString()));
|
|
| 2530 | - }
|
|
| 2531 | -
|
|
| 2532 | - logger.info("Reading leaderboards by name...");
|
|
| 2533 | - leaderboardsByName.putAll((Map<String, Leaderboard>) ois.readObject());
|
|
| 2534 | - logoutput.append("Received " + leaderboardsByName.size() + " NEW leaderboards\n");
|
|
| 2535 | - for (Leaderboard leaderboard : leaderboardsByName.values()) {
|
|
| 2536 | - logoutput.append(String.format("%3s\n", leaderboard.toString()));
|
|
| 2537 | - }
|
|
| 2538 | -
|
|
| 2539 | - // now fix ScoreCorrectionListener setup for LeaderboardGroupMetaLeaderboard instances:
|
|
| 2540 | - for (Leaderboard leaderboard : leaderboardsByName.values()) {
|
|
| 2541 | - if (leaderboard instanceof LeaderboardGroupMetaLeaderboard) {
|
|
| 2542 | - ((LeaderboardGroupMetaLeaderboard) leaderboard)
|
|
| 2543 | - .registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
|
| 2544 | - } else if (leaderboard instanceof FlexibleLeaderboard) {
|
|
| 2545 | - // and re-establish the RaceLogReplicator as listener on FlexibleLeaderboard objects
|
|
| 2546 | - leaderboard.addRaceColumnListener(raceLogReplicator);
|
|
| 2547 | - }
|
|
| 2548 | - }
|
|
| 2549 | -
|
|
| 2550 | - logger.info("Reading media library...");
|
|
| 2551 | - mediaLibrary.deserialize(ois);
|
|
| 2552 | - logoutput.append("Received " + mediaLibrary.allTracks().size() + " NEW media tracks\n");
|
|
| 2553 | - for (MediaTrack mediatrack : mediaLibrary.allTracks()) {
|
|
| 2554 | - logoutput.append(String.format("%3s\n", mediatrack.toString()));
|
|
| 2555 | - }
|
|
| 2556 | -
|
|
| 2557 | - // only copy the competitors from the deserialized competitor store; don't use it because it will have set
|
|
| 2558 | - // a default Mongo object factory
|
|
| 2559 | - logger.info("Reading competitors...");
|
|
| 2560 | - for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) {
|
|
| 2561 | - DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor;
|
|
| 2562 | - // the following should actually be redundant because during de-serialization the Competitor objects,
|
|
| 2563 | - // whose classes implement IsManagedByCache, should already have been got/created from/in the
|
|
| 2564 | - // competitor store
|
|
| 2565 | - competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(),
|
|
| 2566 | - dynamicCompetitor.getColor(), dynamicCompetitor.getEmail(), dynamicCompetitor.getFlagImage(),
|
|
| 2567 | - dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat(), dynamicCompetitor.getTimeOnTimeFactor(),
|
|
| 2568 | - dynamicCompetitor.getTimeOnDistanceAllowancePerNauticalMile());
|
|
| 2569 | - }
|
|
| 2570 | - logoutput.append("Received " + competitorStore.size() + " NEW competitors\n");
|
|
| 2571 | -
|
|
| 2572 | - logger.info("Reading device configurations...");
|
|
| 2573 | - configurationMap.putAll((DeviceConfigurationMapImpl) ois.readObject());
|
|
| 2574 | - logoutput.append("Received " + configurationMap.size() + " NEW configuration entries\n");
|
|
| 2575 | - for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) {
|
|
| 2576 | - logoutput.append(String.format("%3s\n", matcher.toString()));
|
|
| 2577 | - }
|
|
| 2578 | -
|
|
| 2579 | - logger.info("Reading remote sailing server references...");
|
|
| 2580 | - for (RemoteSailingServerReference remoteSailingServerReference : (Iterable<RemoteSailingServerReference>) ois
|
|
| 2581 | - .readObject()) {
|
|
| 2582 | - remoteSailingServerSet.add(remoteSailingServerReference);
|
|
| 2583 | - logoutput.append("Received remote sailing server reference " + remoteSailingServerReference);
|
|
| 2584 | - }
|
|
| 2585 | -
|
|
| 2586 | - // make sure to initialize listeners correctly
|
|
| 2587 | - for (Regatta regatta : regattasByName.values()) {
|
|
| 2588 | - RegattaImpl regattaImpl = (RegattaImpl) regatta;
|
|
| 2589 | - regattaImpl.initializeSeriesAfterDeserialize();
|
|
| 2590 | - regattaImpl.addRaceColumnListener(raceLogReplicator);
|
|
| 2591 | - }
|
|
| 2592 | - // re-establish RaceLogResolver references to this RacingEventService in all TrackedRace instances
|
|
| 2593 | - for (DynamicTrackedRegatta trackedRegatta : regattaTrackingCache.values()) {
|
|
| 2594 | - trackedRegatta.lockTrackedRacesForRead();
|
|
| 2595 | - try {
|
|
| 2596 | - for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) {
|
|
| 2597 | - ((TrackedRaceImpl) trackedRace).setRaceLogResolver(this);
|
|
| 2598 | - }
|
|
| 2599 | - } finally {
|
|
| 2600 | - trackedRegatta.unlockTrackedRacesAfterRead();
|
|
| 2601 | - }
|
|
| 2602 | - }
|
|
| 2603 | - logger.info(logoutput.toString());
|
|
| 2604 | - }
|
|
| 2605 | -
|
|
| 2606 | - @Override
|
|
| 2607 | - public void clearReplicaState() throws MalformedURLException, IOException, InterruptedException {
|
|
| 2608 | - logger.info("Clearing all data structures...");
|
|
| 2609 | - LockUtil.lockForWrite(regattasByNameLock);
|
|
| 2610 | - try {
|
|
| 2611 | - regattasByName.clear();
|
|
| 2612 | - } finally {
|
|
| 2613 | - LockUtil.unlockAfterWrite(regattasByNameLock);
|
|
| 2614 | - }
|
|
| 2615 | - regattasObservedForDefaultLeaderboard.clear();
|
|
| 2616 | -
|
|
| 2617 | - if (raceTrackersByRegatta != null && !raceTrackersByRegatta.isEmpty()) {
|
|
| 2618 | - for (DynamicTrackedRegatta regatta : regattaTrackingCache.values()) {
|
|
| 2619 | - final Set<RaceTracker> trackers = raceTrackersByRegatta.get(regatta.getRegatta());
|
|
| 2620 | - if (trackers != null) {
|
|
| 2621 | - for (RaceTracker tracker : trackers) {
|
|
| 2622 | - tracker.stop(/* preemptive */true);
|
|
| 2623 | - }
|
|
| 2624 | - }
|
|
| 2625 | - }
|
|
| 2626 | - }
|
|
| 2627 | - LockUtil.lockForWrite(regattaTrackingCacheLock);
|
|
| 2628 | - try {
|
|
| 2629 | - regattaTrackingCache.clear();
|
|
| 2630 | - } finally {
|
|
| 2631 | - LockUtil.unlockAfterWrite(regattaTrackingCacheLock);
|
|
| 2632 | - }
|
|
| 2633 | - LockUtil.lockForWrite(raceTrackersByRegattaLock);
|
|
| 2634 | - try {
|
|
| 2635 | - raceTrackersByRegatta.clear();
|
|
| 2636 | - } finally {
|
|
| 2637 | - LockUtil.unlockAfterWrite(raceTrackersByRegattaLock);
|
|
| 2638 | - }
|
|
| 2639 | - LockUtil.lockForWrite(leaderboardGroupsByNameLock);
|
|
| 2640 | - try {
|
|
| 2641 | - leaderboardGroupsByName.clear();
|
|
| 2642 | - leaderboardGroupsByID.clear();
|
|
| 2643 | - } finally {
|
|
| 2644 | - LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock);
|
|
| 2645 | - }
|
|
| 2646 | - LockUtil.lockForWrite(leaderboardsByNameLock);
|
|
| 2647 | - try {
|
|
| 2648 | - leaderboardsByName.clear();
|
|
| 2649 | - } finally {
|
|
| 2650 | - LockUtil.unlockAfterWrite(leaderboardsByNameLock);
|
|
| 2651 | - }
|
|
| 2652 | - eventsById.clear();
|
|
| 2653 | - mediaLibrary.clear();
|
|
| 2654 | - competitorStore.clear();
|
|
| 2655 | - remoteSailingServerSet.clear();
|
|
| 2656 | - }
|
|
| 2657 | -
|
|
| 2658 | - // Used for TESTING only
|
|
| 2659 | - @Override
|
|
| 2660 | - public Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
|
|
| 2661 | - String venue, boolean isPublic, UUID id) {
|
|
| 2662 | - Event result = createEventWithoutReplication(eventName, eventDescription, startDate, endDate, venue, isPublic,
|
|
| 2663 | - id, /* officialWebsiteURL */null, /* sailorsInfoWebsiteURLAsString */null,
|
|
| 2664 | - /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList());
|
|
| 2665 | - replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id,
|
|
| 2666 | - /* officialWebsiteURLAsString */null, /* sailorsInfoWebsiteURLAsString */null,
|
|
| 2667 | - /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList()));
|
|
| 2668 | - return result;
|
|
| 2669 | - }
|
|
| 2670 | -
|
|
| 2671 | - @Override
|
|
| 2672 | - public void addEventWithoutReplication(Event event) {
|
|
| 2673 | - addEvent(event);
|
|
| 2674 | - }
|
|
| 2675 | -
|
|
| 2676 | - @Override
|
|
| 2677 | - public Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate,
|
|
| 2678 | - TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL,
|
|
| 2679 | - Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
|
|
| 2680 | - Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id);
|
|
| 2681 | - addEvent(result);
|
|
| 2682 | - result.setDescription(eventDescription);
|
|
| 2683 | - result.setOfficialWebsiteURL(officialWebsiteURL);
|
|
| 2684 | - result.setImages(images);
|
|
| 2685 | - result.setVideos(videos);
|
|
| 2686 | - return result;
|
|
| 2687 | - }
|
|
| 2688 | -
|
|
| 2689 | - private void addEvent(Event result) {
|
|
| 2690 | - if (eventsById.containsKey(result.getId())) {
|
|
| 2691 | - throw new IllegalArgumentException("Event with ID " + result.getId()
|
|
| 2692 | - + " already exists which is pretty surprising...");
|
|
| 2693 | - }
|
|
| 2694 | - eventsById.put(result.getId(), result);
|
|
| 2695 | - mongoObjectFactory.storeEvent(result);
|
|
| 2696 | - }
|
|
| 2697 | -
|
|
| 2698 | - @Override
|
|
| 2699 | - public void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
|
|
| 2700 | - String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL,
|
|
| 2701 | - Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
|
|
| 2702 | - final Event event = eventsById.get(id);
|
|
| 2703 | - if (event == null) {
|
|
| 2704 | - throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist.");
|
|
| 2705 | - }
|
|
| 2706 | - event.setName(eventName);
|
|
| 2707 | - event.setDescription(eventDescription);
|
|
| 2708 | - event.setStartDate(startDate);
|
|
| 2709 | - event.setEndDate(endDate);
|
|
| 2710 | - event.setPublic(isPublic);
|
|
| 2711 | - event.getVenue().setName(venueName);
|
|
| 2712 | - List<LeaderboardGroup> leaderboardGroups = new ArrayList<>();
|
|
| 2713 | - for (UUID lgid : leaderboardGroupIds) {
|
|
| 2714 | - LeaderboardGroup lg = getLeaderboardGroupByID(lgid);
|
|
| 2715 | - if (lg != null) {
|
|
| 2716 | - leaderboardGroups.add(lg);
|
|
| 2717 | - } else {
|
|
| 2718 | - logger.info("Couldn't find leaderboard group with ID " + lgid + " while updating event "
|
|
| 2719 | - + event.getName());
|
|
| 2720 | - }
|
|
| 2721 | - }
|
|
| 2722 | - event.setLeaderboardGroups(leaderboardGroups);
|
|
| 2723 | - event.setOfficialWebsiteURL(officialWebsiteURL);
|
|
| 2724 | - event.setSailorsInfoWebsiteURL(sailorsInfoWebsiteURL);
|
|
| 2725 | - event.setImages(images);
|
|
| 2726 | - event.setVideos(videos);
|
|
| 2727 | - // TODO consider use diffutils to compute diff between old and new leaderboard groups list and apply the patch
|
|
| 2728 | - // to keep changes minimial
|
|
| 2729 | - mongoObjectFactory.storeEvent(event);
|
|
| 2730 | - }
|
|
| 2731 | -
|
|
| 2732 | - @Override
|
|
| 2733 | - public void renameEvent(UUID id, String newName) {
|
|
| 2734 | - final Event toRename = eventsById.get(id);
|
|
| 2735 | - if (toRename == null) {
|
|
| 2736 | - throw new IllegalArgumentException("No sailing event with ID " + id + " found.");
|
|
| 2737 | - }
|
|
| 2738 | - toRename.setName(newName);
|
|
| 2739 | - mongoObjectFactory.renameEvent(id, newName);
|
|
| 2740 | - replicate(new RenameEvent(id, newName));
|
|
| 2741 | - }
|
|
| 2742 | -
|
|
| 2743 | - @Override
|
|
| 2744 | - public void removeEvent(UUID id) {
|
|
| 2745 | - removeEventFromEventsById(id);
|
|
| 2746 | - mongoObjectFactory.removeEvent(id);
|
|
| 2747 | - replicate(new RemoveEvent(id));
|
|
| 2748 | - }
|
|
| 2749 | -
|
|
| 2750 | - protected void removeEventFromEventsById(Serializable id) {
|
|
| 2751 | - eventsById.remove(id);
|
|
| 2752 | - }
|
|
| 2753 | -
|
|
| 2754 | - @Override
|
|
| 2755 | - public Regatta getRememberedRegattaForRace(Serializable raceID) {
|
|
| 2756 | - return persistentRegattasForRaceIDs.get(raceID.toString());
|
|
| 2757 | - }
|
|
| 2758 | -
|
|
| 2759 | - /**
|
|
| 2760 | - * Persistently remembers the association of the race with its {@link RaceDefinition#getId()} to the
|
|
| 2761 | - * <code>regatta</code> with its {@link Regatta#getRegattaIdentifier() identifier} so that the next time
|
|
| 2762 | - * {@link #getRememberedRegattaForRace(RaceDefinition)} is called with <code>race</code> as argument,
|
|
| 2763 | - * <code>regatta</code> will be returned.
|
|
| 2764 | - */
|
|
| 2765 | - private void setRegattaForRace(Regatta regatta, RaceDefinition race) {
|
|
| 2766 | - setRegattaForRace(regatta, race.getId().toString());
|
|
| 2767 | - }
|
|
| 2768 | -
|
|
| 2769 | - @Override
|
|
| 2770 | - public void setRegattaForRace(Regatta regatta, String raceIdAsString) {
|
|
| 2771 | - persistentRegattasForRaceIDs.put(raceIdAsString, regatta);
|
|
| 2772 | - mongoObjectFactory.storeRegattaForRaceID(raceIdAsString, regatta);
|
|
| 2773 | - }
|
|
| 2774 | -
|
|
| 2775 | - @Override
|
|
| 2776 | - public CourseArea[] addCourseAreas(UUID eventId, String[] courseAreaNames, UUID[] courseAreaIds) {
|
|
| 2777 | - final CourseArea[] courseAreas = addCourseAreasWithoutReplication(eventId, courseAreaIds, courseAreaNames);
|
|
| 2778 | - replicate(new AddCourseAreas(eventId, courseAreaNames, courseAreaIds));
|
|
| 2779 | - return courseAreas;
|
|
| 2780 | - }
|
|
| 2781 | -
|
|
| 2782 | - @Override
|
|
| 2783 | - public CourseArea[] addCourseAreasWithoutReplication(UUID eventId, UUID[] courseAreaIds, String[] courseAreaNames) {
|
|
| 2784 | - final CourseArea[] result = new CourseArea[courseAreaNames.length];
|
|
| 2785 | - for (int i=0; i<courseAreaIds.length; i++) {
|
|
| 2786 | - final CourseArea courseArea = getBaseDomainFactory().getOrCreateCourseArea(courseAreaIds[i], courseAreaNames[i]);
|
|
| 2787 | - final Event event = eventsById.get(eventId);
|
|
| 2788 | - if (event == null) {
|
|
| 2789 | - throw new IllegalArgumentException("No sailing event with ID " + eventId + " found.");
|
|
| 2790 | - }
|
|
| 2791 | - event.getVenue().addCourseArea(courseArea);
|
|
| 2792 | - mongoObjectFactory.storeEvent(event);
|
|
| 2793 | - result[i] = courseArea;
|
|
| 2794 | - }
|
|
| 2795 | - return result;
|
|
| 2796 | - }
|
|
| 2797 | -
|
|
| 2798 | - @Override
|
|
| 2799 | - public CourseArea[] removeCourseAreaWithoutReplication(UUID eventId, UUID[] courseAreaIds) {
|
|
| 2800 | - final Event event = eventsById.get(eventId);
|
|
| 2801 | - if (event == null) {
|
|
| 2802 | - throw new IllegalArgumentException("No sailing event with ID " + eventId + " found.");
|
|
| 2803 | - }
|
|
| 2804 | - final CourseArea[] courseAreasRemoved = new CourseArea[courseAreaIds.length];
|
|
| 2805 | - int i=0;
|
|
| 2806 | - for (final UUID courseAreaId : courseAreaIds) {
|
|
| 2807 | - final CourseArea courseArea = getBaseDomainFactory().getExistingCourseAreaById(courseAreaId);
|
|
| 2808 | - if (courseArea == null) {
|
|
| 2809 | - throw new IllegalArgumentException("No course area with ID " + courseAreaId + " found.");
|
|
| 2810 | - }
|
|
| 2811 | - courseAreasRemoved[i++] = courseArea;
|
|
| 2812 | - event.getVenue().removeCourseArea(courseArea);
|
|
| 2813 | - mongoObjectFactory.storeEvent(event);
|
|
| 2814 | - }
|
|
| 2815 | - return courseAreasRemoved;
|
|
| 2816 | - }
|
|
| 2817 | -
|
|
| 2818 | - @Override
|
|
| 2819 | - public void mediaTrackAdded(MediaTrack mediaTrack) {
|
|
| 2820 | - if (mediaTrack.dbId == null) {
|
|
| 2821 | - mediaTrack.dbId = mediaDB.insertMediaTrack(mediaTrack.title, mediaTrack.url, mediaTrack.startTime,
|
|
| 2822 | - mediaTrack.duration, mediaTrack.mimeType, mediaTrack.assignedRaces);
|
|
| 2823 | - }
|
|
| 2824 | - mediaLibrary.addMediaTrack(mediaTrack);
|
|
| 2825 | - replicate(new AddMediaTrackOperation(mediaTrack));
|
|
| 2826 | - }
|
|
| 2827 | -
|
|
| 2828 | - @Override
|
|
| 2829 | - public void mediaTracksAdded(Collection<MediaTrack> mediaTracks) {
|
|
| 2830 | - mediaLibrary.addMediaTracks(mediaTracks);
|
|
| 2831 | - }
|
|
| 2832 | -
|
|
| 2833 | - @Override
|
|
| 2834 | - public void mediaTrackTitleChanged(MediaTrack mediaTrack) {
|
|
| 2835 | - mediaDB.updateTitle(mediaTrack.dbId, mediaTrack.title);
|
|
| 2836 | - mediaLibrary.titleChanged(mediaTrack);
|
|
| 2837 | - replicate(new UpdateMediaTrackTitleOperation(mediaTrack));
|
|
| 2838 | - }
|
|
| 2839 | -
|
|
| 2840 | - @Override
|
|
| 2841 | - public void mediaTrackUrlChanged(MediaTrack mediaTrack) {
|
|
| 2842 | - mediaDB.updateUrl(mediaTrack.dbId, mediaTrack.url);
|
|
| 2843 | - mediaLibrary.urlChanged(mediaTrack);
|
|
| 2844 | - replicate(new UpdateMediaTrackUrlOperation(mediaTrack));
|
|
| 2845 | - }
|
|
| 2846 | -
|
|
| 2847 | - @Override
|
|
| 2848 | - public void mediaTrackStartTimeChanged(MediaTrack mediaTrack) {
|
|
| 2849 | - mediaDB.updateStartTime(mediaTrack.dbId, mediaTrack.startTime);
|
|
| 2850 | - mediaLibrary.startTimeChanged(mediaTrack);
|
|
| 2851 | - replicate(new UpdateMediaTrackStartTimeOperation(mediaTrack));
|
|
| 2852 | - }
|
|
| 2853 | -
|
|
| 2854 | - @Override
|
|
| 2855 | - public void mediaTrackDurationChanged(MediaTrack mediaTrack) {
|
|
| 2856 | - mediaDB.updateDuration(mediaTrack.dbId, mediaTrack.duration);
|
|
| 2857 | - mediaLibrary.durationChanged(mediaTrack);
|
|
| 2858 | - replicate(new UpdateMediaTrackDurationOperation(mediaTrack));
|
|
| 2859 | - }
|
|
| 2860 | -
|
|
| 2861 | - @Override
|
|
| 2862 | - public void mediaTrackAssignedRacesChanged(MediaTrack mediaTrack) {
|
|
| 2863 | - mediaDB.updateRace(mediaTrack.dbId, mediaTrack.assignedRaces);
|
|
| 2864 | - mediaLibrary.assignedRacesChanged(mediaTrack);
|
|
| 2865 | - replicate(new UpdateMediaTrackRacesOperation(mediaTrack));
|
|
| 2866 | -
|
|
| 2867 | - }
|
|
| 2868 | -
|
|
| 2869 | - @Override
|
|
| 2870 | - public void mediaTrackDeleted(MediaTrack mediaTrack) {
|
|
| 2871 | - mediaDB.deleteMediaTrack(mediaTrack.dbId);
|
|
| 2872 | - mediaLibrary.deleteMediaTrack(mediaTrack);
|
|
| 2873 | - replicate(new RemoveMediaTrackOperation(mediaTrack));
|
|
| 2874 | - }
|
|
| 2875 | -
|
|
| 2876 | - @Override
|
|
| 2877 | - public void mediaTracksImported(Collection<MediaTrack> mediaTracksToImport, boolean override) {
|
|
| 2878 | - for (MediaTrack trackToImport : mediaTracksToImport) {
|
|
| 2879 | - MediaTrack existingTrack = mediaLibrary.lookupMediaTrack(trackToImport);
|
|
| 2880 | - if (existingTrack == null) {
|
|
| 2881 | - mediaDB.insertMediaTrackWithId(trackToImport.dbId, trackToImport.title, trackToImport.url,
|
|
| 2882 | - trackToImport.startTime, trackToImport.duration, trackToImport.mimeType,
|
|
| 2883 | - trackToImport.assignedRaces);
|
|
| 2884 | - mediaTrackAdded(trackToImport);
|
|
| 2885 | - } else if (override) {
|
|
| 2886 | -
|
|
| 2887 | - // Using fine-grained update methods.
|
|
| 2888 | - // Rationale: Changes on more than one track property are rare
|
|
| 2889 | - // and don't justify the introduction of a new set
|
|
| 2890 | - // of methods (including replication).
|
|
| 2891 | - if (!Util.equalsWithNull(existingTrack.title, trackToImport.title)) {
|
|
| 2892 | - mediaTrackTitleChanged(trackToImport);
|
|
| 2893 | - }
|
|
| 2894 | - if (!Util.equalsWithNull(existingTrack.url, trackToImport.url)) {
|
|
| 2895 | - mediaTrackUrlChanged(trackToImport);
|
|
| 2896 | - }
|
|
| 2897 | - if (!Util.equalsWithNull(existingTrack.startTime, trackToImport.startTime)) {
|
|
| 2898 | - mediaTrackStartTimeChanged(trackToImport);
|
|
| 2899 | - }
|
|
| 2900 | - if (!Util.equalsWithNull(existingTrack.duration, trackToImport.duration)) {
|
|
| 2901 | - mediaTrackDurationChanged(trackToImport);
|
|
| 2902 | - }
|
|
| 2903 | - if (!Util.equalsWithNull(existingTrack.assignedRaces, trackToImport.assignedRaces)) {
|
|
| 2904 | - mediaTrackAssignedRacesChanged(trackToImport);
|
|
| 2905 | - }
|
|
| 2906 | - }
|
|
| 2907 | - }
|
|
| 2908 | - }
|
|
| 2909 | -
|
|
| 2910 | - @Override
|
|
| 2911 | - public Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier) {
|
|
| 2912 | - return mediaLibrary.findMediaTracksForRace(regattaAndRaceIdentifier);
|
|
| 2913 | - }
|
|
| 2914 | -
|
|
| 2915 | - @Override
|
|
| 2916 | - public Collection<MediaTrack> getMediaTracksInTimeRange(RegattaAndRaceIdentifier regattaAndRaceIdentifier) {
|
|
| 2917 | - TrackedRace trackedRace = getExistingTrackedRace(regattaAndRaceIdentifier);
|
|
| 2918 | - if (trackedRace != null) {
|
|
| 2919 | - if (trackedRace.isLive(MillisecondsTimePoint.now())) {
|
|
| 2920 | - return mediaLibrary.findLiveMediaTracks();
|
|
| 2921 | - } else {
|
|
| 2922 | - TimePoint raceStart = trackedRace.getStartOfRace() == null ? trackedRace.getStartOfTracking()
|
|
| 2923 | - : trackedRace.getStartOfRace();
|
|
| 2924 | - TimePoint raceEnd = trackedRace.getEndOfRace() == null ? trackedRace.getEndOfTracking() : trackedRace
|
|
| 2925 | - .getEndOfRace();
|
|
| 2926 | - return mediaLibrary.findMediaTracksInTimeRange(raceStart, raceEnd);
|
|
| 2927 | - }
|
|
| 2928 | - } else {
|
|
| 2929 | - return Collections.emptyList();
|
|
| 2930 | - }
|
|
| 2931 | - }
|
|
| 2932 | -
|
|
| 2933 | - @Override
|
|
| 2934 | - public Collection<MediaTrack> getAllMediaTracks() {
|
|
| 2935 | - return mediaLibrary.allTracks();
|
|
| 2936 | - }
|
|
| 2937 | -
|
|
| 2938 | - public String toString() {
|
|
| 2939 | - return "RacingEventService: " + this.hashCode() + " Build: " + ServerInfo.getBuildVersion();
|
|
| 2940 | - }
|
|
| 2941 | -
|
|
| 2942 | - @Override
|
|
| 2943 | - public void reloadRaceLog(String leaderboardName, String raceColumnName, String fleetName) {
|
|
| 2944 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 2945 | - if (leaderboard != null) {
|
|
| 2946 | - RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
|
|
| 2947 | - if (raceColumn != null) {
|
|
| 2948 | - Fleet fleetImpl = raceColumn.getFleetByName(fleetName);
|
|
| 2949 | - RaceLog racelog = raceColumn.getRaceLog(fleetImpl);
|
|
| 2950 | - if (racelog != null) {
|
|
| 2951 | - raceColumn.reloadRaceLog(fleetImpl);
|
|
| 2952 | - logger.info("Reloaded race log for fleet " + fleetImpl + " for race column " + raceColumn.getName()
|
|
| 2953 | - + " for leaderboard " + leaderboard.getName());
|
|
| 2954 | - }
|
|
| 2955 | - }
|
|
| 2956 | - }
|
|
| 2957 | - }
|
|
| 2958 | -
|
|
| 2959 | - @Override
|
|
| 2960 | - public ConcurrentHashMap<String, Regatta> getPersistentRegattasForRaceIDs() {
|
|
| 2961 | - return persistentRegattasForRaceIDs;
|
|
| 2962 | - }
|
|
| 2963 | -
|
|
| 2964 | - @Override
|
|
| 2965 | - public WindStore getWindStore() {
|
|
| 2966 | - return windStore;
|
|
| 2967 | - }
|
|
| 2968 | -
|
|
| 2969 | - @Override
|
|
| 2970 | - public DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier) {
|
|
| 2971 | - return configurationMap.getByMatch(identifier);
|
|
| 2972 | - }
|
|
| 2973 | -
|
|
| 2974 | - @Override
|
|
| 2975 | - public void createOrUpdateDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) {
|
|
| 2976 | - configurationMap.put(matcher, configuration);
|
|
| 2977 | - mongoObjectFactory.storeDeviceConfiguration(matcher, configuration);
|
|
| 2978 | - replicate(new CreateOrUpdateDeviceConfiguration(matcher, configuration));
|
|
| 2979 | - }
|
|
| 2980 | -
|
|
| 2981 | - @Override
|
|
| 2982 | - public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) {
|
|
| 2983 | - configurationMap.remove(matcher);
|
|
| 2984 | - mongoObjectFactory.removeDeviceConfiguration(matcher);
|
|
| 2985 | - replicate(new RemoveDeviceConfiguration(matcher));
|
|
| 2986 | - }
|
|
| 2987 | -
|
|
| 2988 | - @Override
|
|
| 2989 | - public Map<DeviceConfigurationMatcher, DeviceConfiguration> getAllDeviceConfigurations() {
|
|
| 2990 | - return new HashMap<DeviceConfigurationMatcher, DeviceConfiguration>(configurationMap);
|
|
| 2991 | - }
|
|
| 2992 | -
|
|
| 2993 | - @Override
|
|
| 2994 | - public TimePoint setStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName,
|
|
| 2995 | - String authorName, int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime,
|
|
| 2996 | - RacingProcedureType racingProcedure) {
|
|
| 2997 | - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
|
|
| 2998 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 2999 | - final TimePoint result;
|
|
| 3000 | - if (leaderboard instanceof HasRegattaLike && raceLog != null) {
|
|
| 3001 | - RaceState state = RaceStateImpl.create(/* race log resolver */ this, raceLog, new LogEventAuthorImpl(authorName, authorPriority));
|
|
| 3002 | - if (passId > raceLog.getCurrentPassId()) {
|
|
| 3003 | - state.setAdvancePass(logicalTimePoint);
|
|
| 3004 | - }
|
|
| 3005 | - state.setRacingProcedure(logicalTimePoint, racingProcedure);
|
|
| 3006 | - state.forceNewStartTime(logicalTimePoint, startTime);
|
|
| 3007 | - result = state.getStartTime();
|
|
| 3008 | - } else {
|
|
| 3009 | - result = null;
|
|
| 3010 | - }
|
|
| 3011 | - return result;
|
|
| 3012 | - }
|
|
| 3013 | -
|
|
| 3014 | - public RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName) {
|
|
| 3015 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 3016 | - if (leaderboard != null) {
|
|
| 3017 | - RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
|
|
| 3018 | - if (raceColumn != null) {
|
|
| 3019 | - Fleet fleetImpl = raceColumn.getFleetByName(fleetName);
|
|
| 3020 | - return raceColumn.getRaceLog(fleetImpl);
|
|
| 3021 | - }
|
|
| 3022 | - }
|
|
| 3023 | - return null;
|
|
| 3024 | - }
|
|
| 3025 | -
|
|
| 3026 | - @Override
|
|
| 3027 | - public com.sap.sse.common.Util.Triple<TimePoint, Integer, RacingProcedureType> getStartTimeAndProcedure(
|
|
| 3028 | - String leaderboardName, String raceColumnName, String fleetName) {
|
|
| 3029 | - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
|
|
| 3030 | - Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
|
|
| 3031 | - final Triple<TimePoint, Integer, RacingProcedureType> result;
|
|
| 3032 | - if (leaderboard instanceof HasRegattaLike && raceLog != null) {
|
|
| 3033 | - ReadonlyRaceState state = ReadonlyRaceStateImpl.create(/* race log resolver */ this, raceLog);
|
|
| 3034 | - result = new com.sap.sse.common.Util.Triple<TimePoint, Integer, RacingProcedureType>(state.getStartTime(),
|
|
| 3035 | - raceLog.getCurrentPassId(), state.getRacingProcedure().getType());
|
|
| 3036 | - } else {
|
|
| 3037 | - result = null;
|
|
| 3038 | - }
|
|
| 3039 | - return result;
|
|
| 3040 | - }
|
|
| 3041 | -
|
|
| 3042 | - private Iterable<WindTrackerFactory> getWindTrackerFactories() {
|
|
| 3043 | - final Set<WindTrackerFactory> result;
|
|
| 3044 | - if (bundleContext == null) {
|
|
| 3045 | - result = Collections.singleton((WindTrackerFactory) ExpeditionWindTrackerFactory.getInstance());
|
|
| 3046 | - } else {
|
|
| 3047 | - ServiceTracker<WindTrackerFactory, WindTrackerFactory> tracker = new ServiceTracker<WindTrackerFactory, WindTrackerFactory>(
|
|
| 3048 | - bundleContext, WindTrackerFactory.class.getName(), null);
|
|
| 3049 | - tracker.open();
|
|
| 3050 | - result = new HashSet<>();
|
|
| 3051 | - for (WindTrackerFactory factory : tracker.getServices(new WindTrackerFactory[0])) {
|
|
| 3052 | - result.add(factory);
|
|
| 3053 | - }
|
|
| 3054 | - }
|
|
| 3055 | - return result;
|
|
| 3056 | - }
|
|
| 3057 | -
|
|
| 3058 | - @Override
|
|
| 3059 | - public GPSFixStore getGPSFixStore() {
|
|
| 3060 | - return gpsFixStore;
|
|
| 3061 | - }
|
|
| 3062 | -
|
|
| 3063 | - @Override
|
|
| 3064 | - public RaceTracker getRaceTrackerById(Object id) {
|
|
| 3065 | - return raceTrackersByID.get(id);
|
|
| 3066 | - }
|
|
| 3067 | -
|
|
| 3068 | - @Override
|
|
| 3069 | - public AbstractLogEventAuthor getServerAuthor() {
|
|
| 3070 | - return raceLogEventAuthorForServer;
|
|
| 3071 | - }
|
|
| 3072 | -
|
|
| 3073 | - @Override
|
|
| 3074 | - public CompetitorStore getCompetitorStore() {
|
|
| 3075 | - return competitorStore;
|
|
| 3076 | - }
|
|
| 3077 | -
|
|
| 3078 | - @Override
|
|
| 3079 | - public TypeBasedServiceFinderFactory getTypeBasedServiceFinderFactory() {
|
|
| 3080 | - return serviceFinderFactory;
|
|
| 3081 | - }
|
|
| 3082 | -
|
|
| 3083 | - @Override
|
|
| 3084 | - public DataImportLockWithProgress getDataImportLock() {
|
|
| 3085 | - return dataImportLock;
|
|
| 3086 | - }
|
|
| 3087 | -
|
|
| 3088 | - @Override
|
|
| 3089 | - public DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId,
|
|
| 3090 | - double overallProgressPct, String subProgressName, double subProgressPct) {
|
|
| 3091 | - // Create/Update locally
|
|
| 3092 | - DataImportProgress progress = createOrUpdateDataImportProgressWithoutReplication(importOperationId,
|
|
| 3093 | - overallProgressPct, subProgressName, subProgressPct);
|
|
| 3094 | - // Create/Update on replicas
|
|
| 3095 | - replicate(new CreateOrUpdateDataImportProgress(importOperationId, overallProgressPct, subProgressName,
|
|
| 3096 | - subProgressPct));
|
|
| 3097 | - return progress;
|
|
| 3098 | - }
|
|
| 3099 | -
|
|
| 3100 | - @Override
|
|
| 3101 | - public DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId,
|
|
| 3102 | - double overallProgressPct, String subProgressName, double subProgressPct) {
|
|
| 3103 | - DataImportProgress progress = dataImportLock.getProgress(importOperationId);
|
|
| 3104 | - boolean newObject = false;
|
|
| 3105 | - if (progress == null) {
|
|
| 3106 | - progress = new DataImportProgressImpl(importOperationId);
|
|
| 3107 | - newObject = true;
|
|
| 3108 | - }
|
|
| 3109 | - progress.setOverAllProgressPct(overallProgressPct);
|
|
| 3110 | - progress.setNameOfCurrentSubProgress(subProgressName);
|
|
| 3111 | - progress.setCurrentSubProgressPct(subProgressPct);
|
|
| 3112 | - if (newObject) {
|
|
| 3113 | - dataImportLock.addProgress(importOperationId, progress);
|
|
| 3114 | - }
|
|
| 3115 | - return progress;
|
|
| 3116 | - }
|
|
| 3117 | -
|
|
| 3118 | - @Override
|
|
| 3119 | - public void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage) {
|
|
| 3120 | - DataImportProgress progress = dataImportLock.getProgress(importOperationId);
|
|
| 3121 | - if (progress != null) {
|
|
| 3122 | - progress.setFailed();
|
|
| 3123 | - progress.setErrorMessage(errorMessage);
|
|
| 3124 | - }
|
|
| 3125 | - }
|
|
| 3126 | -
|
|
| 3127 | - @Override
|
|
| 3128 | - public void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage) {
|
|
| 3129 | - setDataImportFailedWithoutReplication(importOperationId, errorMessage);
|
|
| 3130 | - replicate(new DataImportFailed(importOperationId, errorMessage));
|
|
| 3131 | - }
|
|
| 3132 | -
|
|
| 3133 | - @Override
|
|
| 3134 | - public void setDataImportDeleteProgressFromMapTimerWithReplication(UUID importOperationId) {
|
|
| 3135 | - setDataImportDeleteProgressFromMapTimerWithoutReplication(importOperationId);
|
|
| 3136 | - replicate(new SetDataImportDeleteProgressFromMapTimer(importOperationId));
|
|
| 3137 | - }
|
|
| 3138 | -
|
|
| 3139 | - @Override
|
|
| 3140 | - public void setDataImportDeleteProgressFromMapTimerWithoutReplication(UUID importOperationId) {
|
|
| 3141 | - dataImportLock.setDeleteFromMapTimer(importOperationId);
|
|
| 3142 | - }
|
|
| 3143 | -
|
|
| 3144 | - @Override
|
|
| 3145 | - public Result<LeaderboardSearchResult> search(KeywordQuery query) {
|
|
| 3146 | - long start = System.currentTimeMillis();
|
|
| 3147 | - logger.info("Searching local server for " + query);
|
|
| 3148 | - Result<LeaderboardSearchResult> result = new RegattaByKeywordSearchService().search(this, query);
|
|
| 3149 | - logger.fine("Search for " + query + " took " + (System.currentTimeMillis() - start) + "ms");
|
|
| 3150 | - return result;
|
|
| 3151 | - }
|
|
| 3152 | -
|
|
| 3153 | - @Override
|
|
| 3154 | - public Result<LeaderboardSearchResultBase> searchRemotely(String remoteServerReferenceName, KeywordQuery query) {
|
|
| 3155 | - long start = System.currentTimeMillis();
|
|
| 3156 | - ResultImpl<LeaderboardSearchResultBase> result = null;
|
|
| 3157 | - RemoteSailingServerReference remoteRef = remoteSailingServerSet
|
|
| 3158 | - .getServerReferenceByName(remoteServerReferenceName);
|
|
| 3159 | - if (remoteRef == null) {
|
|
| 3160 | - result = null;
|
|
| 3161 | - } else {
|
|
| 3162 | - BufferedReader bufferedReader = null;
|
|
| 3163 | - try {
|
|
| 3164 | - try {
|
|
| 3165 | - final URL eventsURL = new URL(remoteRef.getURL(), "sailingserver/api/v1/search?q="
|
|
| 3166 | - + URLEncoder.encode(query.toString(), "UTF-8"));
|
|
| 3167 | - logger.info("Searching remote server " + remoteRef + " for " + query);
|
|
| 3168 | - URLConnection urlConnection = eventsURL.openConnection();
|
|
| 3169 | - urlConnection.connect();
|
|
| 3170 | - bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
|
|
| 3171 | - JSONParser parser = new JSONParser();
|
|
| 3172 | - Object eventsAsObject = parser.parse(bufferedReader);
|
|
| 3173 | - final LeaderboardGroupBaseJsonDeserializer leaderboardGroupBaseJsonDeserializer = new LeaderboardGroupBaseJsonDeserializer();
|
|
| 3174 | - LeaderboardSearchResultBaseJsonDeserializer deserializer = new LeaderboardSearchResultBaseJsonDeserializer(
|
|
| 3175 | - new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(
|
|
| 3176 | - DomainFactory.INSTANCE)), leaderboardGroupBaseJsonDeserializer),
|
|
| 3177 | - leaderboardGroupBaseJsonDeserializer);
|
|
| 3178 | - result = new ResultImpl<LeaderboardSearchResultBase>(query,
|
|
| 3179 | - new LeaderboardSearchResultBaseRanker<LeaderboardSearchResultBase>());
|
|
| 3180 | - JSONArray hitsAsJsonArray = (JSONArray) eventsAsObject;
|
|
| 3181 | - for (Object hitAsObject : hitsAsJsonArray) {
|
|
| 3182 | - JSONObject hitAsJson = (JSONObject) hitAsObject;
|
|
| 3183 | - LeaderboardSearchResultBase hit = deserializer.deserialize(hitAsJson);
|
|
| 3184 | - result.addHit(hit);
|
|
| 3185 | - }
|
|
| 3186 | - } finally {
|
|
| 3187 | - if (bufferedReader != null) {
|
|
| 3188 | - bufferedReader.close();
|
|
| 3189 | - }
|
|
| 3190 | - }
|
|
| 3191 | - } catch (IOException | ParseException e) {
|
|
| 3192 | - logger.log(Level.INFO,
|
|
| 3193 | - "Exception trying to fetch events from remote server " + remoteRef + ": " + e.getMessage(), e);
|
|
| 3194 | - }
|
|
| 3195 | - }
|
|
| 3196 | - logger.fine("Remote search on " + remoteRef + " for " + query + " took " + (System.currentTimeMillis() - start)
|
|
| 3197 | - + "ms");
|
|
| 3198 | - return result;
|
|
| 3199 | - }
|
|
| 3200 | -
|
|
| 3201 | - @Override
|
|
| 3202 | - public ReplicationMasterDescriptor getMasterDescriptor() {
|
|
| 3203 | - return replicatingFromMaster;
|
|
| 3204 | - }
|
|
| 3205 | -
|
|
| 3206 | - @Override
|
|
| 3207 | - public void startedReplicatingFrom(ReplicationMasterDescriptor master) {
|
|
| 3208 | - this.replicatingFromMaster = master;
|
|
| 3209 | - }
|
|
| 3210 | -
|
|
| 3211 | - @Override
|
|
| 3212 | - public void stoppedReplicatingFrom(ReplicationMasterDescriptor master) {
|
|
| 3213 | - this.replicatingFromMaster = null;
|
|
| 3214 | - }
|
|
| 3215 | -
|
|
| 3216 | - @Override
|
|
| 3217 | - public void addOperationSentToMasterForReplication(
|
|
| 3218 | - OperationWithResultWithIdWrapper<RacingEventService, ?> operationWithResultWithIdWrapper) {
|
|
| 3219 | - this.operationsSentToMasterForReplication.add(operationWithResultWithIdWrapper);
|
|
| 3220 | - }
|
|
| 3221 | -
|
|
| 3222 | - @Override
|
|
| 3223 | - public boolean hasSentOperationToMaster(OperationWithResult<RacingEventService, ?> operation) {
|
|
| 3224 | - return this.operationsSentToMasterForReplication.remove(operation);
|
|
| 3225 | - }
|
|
| 3226 | -
|
|
| 3227 | - @Override
|
|
| 3228 | - public FileStorageManagementService getFileStorageManagementService() {
|
|
| 3229 | - ServiceReference<FileStorageManagementService> ref = bundleContext
|
|
| 3230 | - .getServiceReference(FileStorageManagementService.class);
|
|
| 3231 | - if (ref == null) {
|
|
| 3232 | - logger.warning("No file storage management service registered");
|
|
| 3233 | - return null;
|
|
| 3234 | - }
|
|
| 3235 | - return bundleContext.getService(ref);
|
|
| 3236 | - }
|
|
| 3237 | -
|
|
| 3238 | - public void addMasterDataClassLoader(ClassLoader classLoader) {
|
|
| 3239 | - masterDataClassLoaders.add(classLoader);
|
|
| 3240 | - }
|
|
| 3241 | -
|
|
| 3242 | - public void removeMasterDataClassLoader(ClassLoader classLoader) {
|
|
| 3243 | - masterDataClassLoaders.remove(classLoader);
|
|
| 3244 | - }
|
|
| 3245 | -
|
|
| 3246 | - @Override
|
|
| 3247 | - public ClassLoader getCombinedMasterDataClassLoader() {
|
|
| 3248 | - JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
|
|
| 3249 | - return joinedClassLoader;
|
|
| 3250 | - }
|
|
| 3251 | -
|
|
| 3252 | - public void setPolarDataService(PolarDataService service) {
|
|
| 3253 | - if (this.polarDataService == null && service != null) {
|
|
| 3254 | - polarDataService = service;
|
|
| 3255 | - polarDataService.registerDomainFactory(baseDomainFactory);
|
|
| 3256 | - setPolarDataServiceOnAllTrackedRaces(service);
|
|
| 3257 | - }
|
|
| 3258 | - }
|
|
| 3259 | -
|
|
| 3260 | - private void setPolarDataServiceOnAllTrackedRaces(PolarDataService service) {
|
|
| 3261 | - Iterable<Regatta> allRegattas = getAllRegattas();
|
|
| 3262 | - for (Regatta regatta : allRegattas) {
|
|
| 3263 | - DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta);
|
|
| 3264 | - if (trackedRegatta != null) {
|
|
| 3265 | - trackedRegatta.lockTrackedRacesForRead();
|
|
| 3266 | - try {
|
|
| 3267 | - Iterable<DynamicTrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
|
| 3268 | - for (TrackedRace trackedRace : trackedRaces) {
|
|
| 3269 | - trackedRace.setPolarDataService(service);
|
|
| 3270 | - service.insertExistingFixes(trackedRace);
|
|
| 3271 | - }
|
|
| 3272 | - } finally {
|
|
| 3273 | - trackedRegatta.unlockTrackedRacesAfterRead();
|
|
| 3274 | - }
|
|
| 3275 | - }
|
|
| 3276 | - }
|
|
| 3277 | - }
|
|
| 3278 | -
|
|
| 3279 | - public void unsetPolarDataService(PolarDataService service) {
|
|
| 3280 | - if (polarDataService == service) {
|
|
| 3281 | - polarDataService.unregisterDomainFactory(baseDomainFactory);
|
|
| 3282 | - polarDataService = null;
|
|
| 3283 | - setPolarDataService(null);
|
|
| 3284 | - }
|
|
| 3285 | - }
|
|
| 3286 | -
|
|
| 3287 | - @Override
|
|
| 3288 | - public Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) {
|
|
| 3289 | - final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint);
|
|
| 3290 | - final List<Competitor> result = new ArrayList<>();
|
|
| 3291 | - final Map<Competitor, Distance> windwardDistanceSailedPerCompetitor = new HashMap<>();
|
|
| 3292 | - for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
|
| 3293 | - result.add(competitor);
|
|
| 3294 | - final CompetitorRankingInfo competitorRankingInfo = rankingInfo.getCompetitorRankingInfo().apply(competitor);
|
|
| 3295 | - windwardDistanceSailedPerCompetitor.put(competitor, competitorRankingInfo == null ? null : competitorRankingInfo.getWindwardDistanceSailed());
|
|
| 3296 | - }
|
|
| 3297 | - final Comparator<Distance> durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder());
|
|
| 3298 | - result.sort((c1, c2) -> durationComparatorNullsLast.compare(windwardDistanceSailedPerCompetitor.get(c2),
|
|
| 3299 | - windwardDistanceSailedPerCompetitor.get(c1)));
|
|
| 3300 | - return result;
|
|
| 3301 | - }
|
|
| 3302 | -
|
|
| 3303 | - /**
|
|
| 3304 | - * A {@link SimpleRaceLogIdentifier} in particular has a {@link SimpleRaceLogIdentifier#getRegattaLikeParentName()}
|
|
| 3305 | - * which identifies either a regatta by name or a flexible leaderboard by name. Here is why this can luckily be
|
|
| 3306 | - * resolved unanimously: A regatta leaderboard always uses as its name the regatta name (see
|
|
| 3307 | - * {@link RegattaImpl#getName()}). Trying to {@link RegattaLeaderboardImpl#setName(String) set} the regatta leaderboard's
|
|
| 3308 | - * name can only update its {@link Leaderboard#getDisplayName() display name}. Therefore, regatta leaderboards are always
|
|
| 3309 | - * keyed in {@link #leaderboardsByName} by their regatta's name. Thus, no flexible leaderboard can have a regatta's name
|
|
| 3310 | - * as its name, and therefore leaderboard names <em>and</em> regatta names are unitedly unique.
|
|
| 3311 | - */
|
|
| 3312 | - @Override
|
|
| 3313 | - public RaceLog resolve(SimpleRaceLogIdentifier identifier) {
|
|
| 3314 | - final RaceLog result;
|
|
| 3315 | - final IsRegattaLike regattaLike;
|
|
| 3316 | - final Regatta regatta = regattasByName.get(identifier.getRegattaLikeParentName());
|
|
| 3317 | - if (regatta != null) {
|
|
| 3318 | - regattaLike = regatta;
|
|
| 3319 | - } else {
|
|
| 3320 | - final Leaderboard leaderboard = leaderboardsByName.get(identifier.getRegattaLikeParentName());
|
|
| 3321 | - if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) {
|
|
| 3322 | - regattaLike = (FlexibleLeaderboard) leaderboard;
|
|
| 3323 | - } else {
|
|
| 3324 | - regattaLike = null;
|
|
| 3325 | - }
|
|
| 3326 | - }
|
|
| 3327 | - if (regattaLike != null) {
|
|
| 3328 | - final RaceColumn raceColumn = regattaLike.getRaceColumnByName(identifier.getRaceColumnName());
|
|
| 3329 | - if (raceColumn != null) {
|
|
| 3330 | - final Fleet fleet = raceColumn.getFleetByName(identifier.getFleetName());
|
|
| 3331 | - if (fleet != null) {
|
|
| 3332 | - result = raceColumn.getRaceLog(fleet);
|
|
| 3333 | - } else {
|
|
| 3334 | - result = null;
|
|
| 3335 | - }
|
|
| 3336 | - } else {
|
|
| 3337 | - result = null;
|
|
| 3338 | - }
|
|
| 3339 | - } else {
|
|
| 3340 | - result = null;
|
|
| 3341 | - }
|
|
| 3342 | - return result;
|
|
| 3343 | - }
|
|
| 3344 | -}
|
|
| 1 | +package com.sap.sailing.server.impl; |
|
| 2 | + |
|
| 3 | +import java.io.BufferedReader; |
|
| 4 | +import java.io.IOException; |
|
| 5 | +import java.io.InputStream; |
|
| 6 | +import java.io.InputStreamReader; |
|
| 7 | +import java.io.ObjectInputStream; |
|
| 8 | +import java.io.ObjectOutputStream; |
|
| 9 | +import java.io.Serializable; |
|
| 10 | +import java.net.MalformedURLException; |
|
| 11 | +import java.net.SocketException; |
|
| 12 | +import java.net.URL; |
|
| 13 | +import java.net.URLConnection; |
|
| 14 | +import java.net.URLEncoder; |
|
| 15 | +import java.util.ArrayList; |
|
| 16 | +import java.util.Arrays; |
|
| 17 | +import java.util.Collection; |
|
| 18 | +import java.util.Collections; |
|
| 19 | +import java.util.Comparator; |
|
| 20 | +import java.util.HashMap; |
|
| 21 | +import java.util.HashSet; |
|
| 22 | +import java.util.Iterator; |
|
| 23 | +import java.util.LinkedHashMap; |
|
| 24 | +import java.util.List; |
|
| 25 | +import java.util.Map; |
|
| 26 | +import java.util.Map.Entry; |
|
| 27 | +import java.util.Set; |
|
| 28 | +import java.util.UUID; |
|
| 29 | +import java.util.concurrent.ConcurrentHashMap; |
|
| 30 | +import java.util.concurrent.Executor; |
|
| 31 | +import java.util.concurrent.Executors; |
|
| 32 | +import java.util.concurrent.LinkedBlockingQueue; |
|
| 33 | +import java.util.concurrent.ScheduledExecutorService; |
|
| 34 | +import java.util.concurrent.ScheduledFuture; |
|
| 35 | +import java.util.concurrent.ThreadPoolExecutor; |
|
| 36 | +import java.util.concurrent.TimeUnit; |
|
| 37 | +import java.util.function.Function; |
|
| 38 | +import java.util.logging.Level; |
|
| 39 | +import java.util.logging.Logger; |
|
| 40 | + |
|
| 41 | +import org.json.simple.JSONArray; |
|
| 42 | +import org.json.simple.JSONObject; |
|
| 43 | +import org.json.simple.parser.JSONParser; |
|
| 44 | +import org.json.simple.parser.ParseException; |
|
| 45 | +import org.osgi.framework.BundleContext; |
|
| 46 | +import org.osgi.framework.ServiceReference; |
|
| 47 | +import org.osgi.util.tracker.ServiceTracker; |
|
| 48 | + |
|
| 49 | +import com.sap.sailing.domain.abstractlog.AbstractLog; |
|
| 50 | +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; |
|
| 51 | +import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; |
|
| 52 | +import com.sap.sailing.domain.abstractlog.race.RaceLog; |
|
| 53 | +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; |
|
| 54 | +import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; |
|
| 55 | +import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; |
|
| 56 | +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; |
|
| 57 | +import com.sap.sailing.domain.abstractlog.race.state.RaceState; |
|
| 58 | +import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; |
|
| 59 | +import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl; |
|
| 60 | +import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; |
|
| 61 | +import com.sap.sailing.domain.base.Competitor; |
|
| 62 | +import com.sap.sailing.domain.base.CompetitorStore; |
|
| 63 | +import com.sap.sailing.domain.base.CompetitorStore.CompetitorUpdateListener; |
|
| 64 | +import com.sap.sailing.domain.base.ControlPoint; |
|
| 65 | +import com.sap.sailing.domain.base.CourseArea; |
|
| 66 | +import com.sap.sailing.domain.base.DomainFactory; |
|
| 67 | +import com.sap.sailing.domain.base.Event; |
|
| 68 | +import com.sap.sailing.domain.base.EventBase; |
|
| 69 | +import com.sap.sailing.domain.base.EventFetcher; |
|
| 70 | +import com.sap.sailing.domain.base.Fleet; |
|
| 71 | +import com.sap.sailing.domain.base.LeaderboardSearchResult; |
|
| 72 | +import com.sap.sailing.domain.base.LeaderboardSearchResultBase; |
|
| 73 | +import com.sap.sailing.domain.base.Mark; |
|
| 74 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 75 | +import com.sap.sailing.domain.base.RaceColumnInSeries; |
|
| 76 | +import com.sap.sailing.domain.base.RaceDefinition; |
|
| 77 | +import com.sap.sailing.domain.base.Regatta; |
|
| 78 | +import com.sap.sailing.domain.base.RegattaListener; |
|
| 79 | +import com.sap.sailing.domain.base.RemoteSailingServerReference; |
|
| 80 | +import com.sap.sailing.domain.base.SailingServerConfiguration; |
|
| 81 | +import com.sap.sailing.domain.base.Series; |
|
| 82 | +import com.sap.sailing.domain.base.Sideline; |
|
| 83 | +import com.sap.sailing.domain.base.Waypoint; |
|
| 84 | +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; |
|
| 85 | +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; |
|
| 86 | +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; |
|
| 87 | +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; |
|
| 88 | +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMapImpl; |
|
| 89 | +import com.sap.sailing.domain.base.impl.DynamicCompetitor; |
|
| 90 | +import com.sap.sailing.domain.base.impl.EventImpl; |
|
| 91 | +import com.sap.sailing.domain.base.impl.RegattaImpl; |
|
| 92 | +import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; |
|
| 93 | +import com.sap.sailing.domain.common.DataImportProgress; |
|
| 94 | +import com.sap.sailing.domain.common.Distance; |
|
| 95 | +import com.sap.sailing.domain.common.Position; |
|
| 96 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 97 | +import com.sap.sailing.domain.common.RegattaIdentifier; |
|
| 98 | +import com.sap.sailing.domain.common.RegattaName; |
|
| 99 | +import com.sap.sailing.domain.common.Renamable; |
|
| 100 | +import com.sap.sailing.domain.common.ScoringSchemeType; |
|
| 101 | +import com.sap.sailing.domain.common.TrackedRaceStatusEnum; |
|
| 102 | +import com.sap.sailing.domain.common.Wind; |
|
| 103 | +import com.sap.sailing.domain.common.WindSource; |
|
| 104 | +import com.sap.sailing.domain.common.dto.FleetDTO; |
|
| 105 | +import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; |
|
| 106 | +import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO; |
|
| 107 | +import com.sap.sailing.domain.common.impl.DataImportProgressImpl; |
|
| 108 | +import com.sap.sailing.domain.common.media.MediaTrack; |
|
| 109 | +import com.sap.sailing.domain.common.racelog.RacingProcedureType; |
|
| 110 | +import com.sap.sailing.domain.common.tracking.GPSFix; |
|
| 111 | +import com.sap.sailing.domain.common.tracking.GPSFixMoving; |
|
| 112 | +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; |
|
| 113 | +import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn; |
|
| 114 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 115 | +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; |
|
| 116 | +import com.sap.sailing.domain.leaderboard.LeaderboardRegistry; |
|
| 117 | +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; |
|
| 118 | +import com.sap.sailing.domain.leaderboard.ScoringScheme; |
|
| 119 | +import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; |
|
| 120 | +import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; |
|
| 121 | +import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; |
|
| 122 | +import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; |
|
| 123 | +import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; |
|
| 124 | +import com.sap.sailing.domain.persistence.DomainObjectFactory; |
|
| 125 | +import com.sap.sailing.domain.persistence.MongoObjectFactory; |
|
| 126 | +import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory; |
|
| 127 | +import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory; |
|
| 128 | +import com.sap.sailing.domain.persistence.MongoWindStore; |
|
| 129 | +import com.sap.sailing.domain.persistence.MongoWindStoreFactory; |
|
| 130 | +import com.sap.sailing.domain.persistence.PersistenceFactory; |
|
| 131 | +import com.sap.sailing.domain.persistence.media.MediaDB; |
|
| 132 | +import com.sap.sailing.domain.persistence.media.MediaDBFactory; |
|
| 133 | +import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory; |
|
| 134 | +import com.sap.sailing.domain.polars.PolarDataService; |
|
| 135 | +import com.sap.sailing.domain.racelog.RaceLogIdentifier; |
|
| 136 | +import com.sap.sailing.domain.racelog.RaceLogStore; |
|
| 137 | +import com.sap.sailing.domain.racelog.tracking.GPSFixStore; |
|
| 138 | +import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; |
|
| 139 | +import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo; |
|
| 140 | +import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; |
|
| 141 | +import com.sap.sailing.domain.ranking.RankingMetricConstructor; |
|
| 142 | +import com.sap.sailing.domain.regattalike.HasRegattaLike; |
|
| 143 | +import com.sap.sailing.domain.regattalike.IsRegattaLike; |
|
| 144 | +import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; |
|
| 145 | +import com.sap.sailing.domain.regattalog.RegattaLogStore; |
|
| 146 | +import com.sap.sailing.domain.tracking.DynamicTrackedRace; |
|
| 147 | +import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; |
|
| 148 | +import com.sap.sailing.domain.tracking.GPSFixTrack; |
|
| 149 | +import com.sap.sailing.domain.tracking.MarkPassing; |
|
| 150 | +import com.sap.sailing.domain.tracking.RaceChangeListener; |
|
| 151 | +import com.sap.sailing.domain.tracking.RaceHandle; |
|
| 152 | +import com.sap.sailing.domain.tracking.RaceListener; |
|
| 153 | +import com.sap.sailing.domain.tracking.RaceTracker; |
|
| 154 | +import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters; |
|
| 155 | +import com.sap.sailing.domain.tracking.TrackedRace; |
|
| 156 | +import com.sap.sailing.domain.tracking.TrackedRaceStatus; |
|
| 157 | +import com.sap.sailing.domain.tracking.TrackedRegatta; |
|
| 158 | +import com.sap.sailing.domain.tracking.WindStore; |
|
| 159 | +import com.sap.sailing.domain.tracking.WindTracker; |
|
| 160 | +import com.sap.sailing.domain.tracking.WindTrackerFactory; |
|
| 161 | +import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; |
|
| 162 | +import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl; |
|
| 163 | +import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; |
|
| 164 | +import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl; |
|
| 165 | +import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; |
|
| 166 | +import com.sap.sailing.server.RacingEventService; |
|
| 167 | +import com.sap.sailing.server.Replicator; |
|
| 168 | +import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer; |
|
| 169 | +import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer; |
|
| 170 | +import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer; |
|
| 171 | +import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardSearchResultBaseJsonDeserializer; |
|
| 172 | +import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer; |
|
| 173 | +import com.sap.sailing.server.masterdata.DataImportLockWithProgress; |
|
| 174 | +import com.sap.sailing.server.operationaltransformation.AddCourseAreas; |
|
| 175 | +import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta; |
|
| 176 | +import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation; |
|
| 177 | +import com.sap.sailing.server.operationaltransformation.AddRaceDefinition; |
|
| 178 | +import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta; |
|
| 179 | +import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn; |
|
| 180 | +import com.sap.sailing.server.operationaltransformation.CreateEvent; |
|
| 181 | +import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDataImportProgress; |
|
| 182 | +import com.sap.sailing.server.operationaltransformation.CreateOrUpdateDeviceConfiguration; |
|
| 183 | +import com.sap.sailing.server.operationaltransformation.CreateTrackedRace; |
|
| 184 | +import com.sap.sailing.server.operationaltransformation.DataImportFailed; |
|
| 185 | +import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix; |
|
| 186 | +import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix; |
|
| 187 | +import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFixForExistingTrack; |
|
| 188 | +import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFixForNewMarkTrack; |
|
| 189 | +import com.sap.sailing.server.operationaltransformation.RecordWindFix; |
|
| 190 | +import com.sap.sailing.server.operationaltransformation.RemoveDeviceConfiguration; |
|
| 191 | +import com.sap.sailing.server.operationaltransformation.RemoveEvent; |
|
| 192 | +import com.sap.sailing.server.operationaltransformation.RemoveMediaTrackOperation; |
|
| 193 | +import com.sap.sailing.server.operationaltransformation.RemoveWindFix; |
|
| 194 | +import com.sap.sailing.server.operationaltransformation.RenameEvent; |
|
| 195 | +import com.sap.sailing.server.operationaltransformation.SetDataImportDeleteProgressFromMapTimer; |
|
| 196 | +import com.sap.sailing.server.operationaltransformation.TrackRegatta; |
|
| 197 | +import com.sap.sailing.server.operationaltransformation.UpdateCompetitor; |
|
| 198 | +import com.sap.sailing.server.operationaltransformation.UpdateEndOfTracking; |
|
| 199 | +import com.sap.sailing.server.operationaltransformation.UpdateMarkPassings; |
|
| 200 | +import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackDurationOperation; |
|
| 201 | +import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackRacesOperation; |
|
| 202 | +import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackStartTimeOperation; |
|
| 203 | +import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackTitleOperation; |
|
| 204 | +import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackUrlOperation; |
|
| 205 | +import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive; |
|
| 206 | +import com.sap.sailing.server.operationaltransformation.UpdateStartOfTracking; |
|
| 207 | +import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived; |
|
| 208 | +import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus; |
|
| 209 | +import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime; |
|
| 210 | +import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude; |
|
| 211 | +import com.sap.sailing.server.simulation.SimulationService; |
|
| 212 | +import com.sap.sailing.server.simulation.SimulationServiceFactory; |
|
| 213 | +import com.sap.sse.ServerInfo; |
|
| 214 | +import com.sap.sse.common.TimePoint; |
|
| 215 | +import com.sap.sse.common.TypeBasedServiceFinderFactory; |
|
| 216 | +import com.sap.sse.common.Util; |
|
| 217 | +import com.sap.sse.common.Util.Pair; |
|
| 218 | +import com.sap.sse.common.Util.Triple; |
|
| 219 | +import com.sap.sse.common.impl.MillisecondsTimePoint; |
|
| 220 | +import com.sap.sse.common.search.KeywordQuery; |
|
| 221 | +import com.sap.sse.common.search.Result; |
|
| 222 | +import com.sap.sse.common.search.ResultImpl; |
|
| 223 | +import com.sap.sse.concurrent.LockUtil; |
|
| 224 | +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; |
|
| 225 | +import com.sap.sse.filestorage.FileStorageManagementService; |
|
| 226 | +import com.sap.sse.replication.OperationExecutionListener; |
|
| 227 | +import com.sap.sse.replication.OperationWithResult; |
|
| 228 | +import com.sap.sse.replication.ReplicationMasterDescriptor; |
|
| 229 | +import com.sap.sse.replication.impl.OperationWithResultWithIdWrapper; |
|
| 230 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 231 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 232 | +import com.sap.sse.util.ClearStateTestSupport; |
|
| 233 | +import com.sap.sse.util.JoinedClassLoader; |
|
| 234 | +import com.sap.sse.util.impl.ThreadFactoryWithPriority; |
|
| 235 | + |
|
| 236 | +public class RacingEventServiceImpl implements RacingEventService, ClearStateTestSupport, RegattaListener, |
|
| 237 | + LeaderboardRegistry, Replicator, EventFetcher { |
|
| 238 | + private static final Logger logger = Logger.getLogger(RacingEventServiceImpl.class.getName()); |
|
| 239 | + |
|
| 240 | + /** |
|
| 241 | + * A scheduler for the periodic checks of the paramURL documents for the advent of {@link ControlPoint}s with static |
|
| 242 | + * position information otherwise not available through <code>MarkPassingReceiver</code>'s events. |
|
| 243 | + */ |
|
| 244 | + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactoryWithPriority(Thread.NORM_PRIORITY, /* daemon */ true)); |
|
| 245 | + |
|
| 246 | + private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory; |
|
| 247 | + |
|
| 248 | + /** |
|
| 249 | + * Holds the {@link Event} objects for those event registered with this service. Note that there may be |
|
| 250 | + * {@link Event} objects that exist outside this service for events not (yet) registered here. |
|
| 251 | + */ |
|
| 252 | + private final ConcurrentHashMap<Serializable, Event> eventsById; |
|
| 253 | + |
|
| 254 | + private final RemoteSailingServerSet remoteSailingServerSet; |
|
| 255 | + |
|
| 256 | + /** |
|
| 257 | + * Holds the {@link Regatta} objects for those races registered with this service. Note that there may be |
|
| 258 | + * {@link Regatta} objects that exist outside this service for regattas not (yet) registered here. |
|
| 259 | + */ |
|
| 260 | + protected final ConcurrentHashMap<String, Regatta> regattasByName; |
|
| 261 | + |
|
| 262 | + private final NamedReentrantReadWriteLock regattasByNameLock; |
|
| 263 | + |
|
| 264 | + private final ConcurrentHashMap<RaceDefinition, CourseChangeReplicator> courseListeners; |
|
| 265 | + |
|
| 266 | + protected final ConcurrentHashMap<Regatta, Set<RaceTracker>> raceTrackersByRegatta; |
|
| 267 | + |
|
| 268 | + /** |
|
| 269 | + * Although {@link #raceTrackersByRegatta} is a concurrent hash map, entering sets as values needs to be |
|
| 270 | + * synchronized using this lock's write lock to avoid two value sets overwriting each other. |
|
| 271 | + */ |
|
| 272 | + private final NamedReentrantReadWriteLock raceTrackersByRegattaLock; |
|
| 273 | + |
|
| 274 | + /** |
|
| 275 | + * Remembers the trackers by paramURL/liveURI/storedURI to avoid duplication |
|
| 276 | + */ |
|
| 277 | + protected final ConcurrentHashMap<Object, RaceTracker> raceTrackersByID; |
|
| 278 | + |
|
| 279 | + /** |
|
| 280 | + * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} will check |
|
| 281 | + * {@link #raceTrackersByID} for the presence of a tracker and won't create a new tracker if one for the |
|
| 282 | + * connectivity parameters' ID already exists. This check and creation and addition to {@link #raceTrackersByID} |
|
| 283 | + * requires locking in the face of concurrent calls to |
|
| 284 | + * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)}. Using <code>synchronized</code> is |
|
| 285 | + * not ideal due to its coarse-grained locking style which allows for little concurrency. Instead, this map is used |
|
| 286 | + * to keep locks for any ID that any invocation of the |
|
| 287 | + * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method is currently working on. |
|
| 288 | + * Fetching or creating and putting a lock to this map happens in ({@link #getOrCreateRaceTrackersByIdLock}) which |
|
| 289 | + * takes care of managing concurrent access to this concurrent map. When done, the |
|
| 290 | + * {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long)} method cleans up by removing the |
|
| 291 | + * lock again from this map, again using a synchronized method ( |
|
| 292 | + * {@link #unlockRaceTrackersById(Object, NamedReentrantReadWriteLock)}). |
|
| 293 | + */ |
|
| 294 | + private final ConcurrentHashMap<Object, NamedReentrantReadWriteLock> raceTrackersByIDLocks; |
|
| 295 | + |
|
| 296 | + /** |
|
| 297 | + * Leaderboards managed by this racing event service |
|
| 298 | + */ |
|
| 299 | + private final ConcurrentHashMap<String, Leaderboard> leaderboardsByName; |
|
| 300 | + |
|
| 301 | + /** |
|
| 302 | + * {@link #leaderboardsByName} is already a concurrent hash map; however, when renaming a leaderboard, this shall |
|
| 303 | + * happen as an atomic transaction, not interruptible by other write accesses on the same map because otherwise |
|
| 304 | + * assumptions made during the rename process wouldn't hold. See, in particular, |
|
| 305 | + * {@link #renameLeaderboard(String, String)}. |
|
| 306 | + */ |
|
| 307 | + private final NamedReentrantReadWriteLock leaderboardsByNameLock; |
|
| 308 | + |
|
| 309 | + private final ConcurrentHashMap<String, LeaderboardGroup> leaderboardGroupsByName; |
|
| 310 | + |
|
| 311 | + private final ConcurrentHashMap<UUID, LeaderboardGroup> leaderboardGroupsByID; |
|
| 312 | + |
|
| 313 | + /** |
|
| 314 | + * See {@link #leaderboardsByNameLock} |
|
| 315 | + */ |
|
| 316 | + private final NamedReentrantReadWriteLock leaderboardGroupsByNameLock; |
|
| 317 | + |
|
| 318 | + private final CompetitorStore competitorStore; |
|
| 319 | + |
|
| 320 | + /** |
|
| 321 | + * A set based on a concurrent hash map, therefore being thread safe |
|
| 322 | + */ |
|
| 323 | + private Set<DynamicTrackedRegatta> regattasObservedForDefaultLeaderboard = Collections |
|
| 324 | + .newSetFromMap(new ConcurrentHashMap<DynamicTrackedRegatta, Boolean>()); |
|
| 325 | + |
|
| 326 | + private final MongoObjectFactory mongoObjectFactory; |
|
| 327 | + |
|
| 328 | + private final DomainObjectFactory domainObjectFactory; |
|
| 329 | + |
|
| 330 | + private final ConcurrentHashMap<Regatta, DynamicTrackedRegatta> regattaTrackingCache; |
|
| 331 | + |
|
| 332 | + /** |
|
| 333 | + * Protects write access transactions that do a previous read to {@link #regattaTrackingCache}; read-only access is |
|
| 334 | + * already synchronized by using a concurrent hash map for {@link #regattaTrackingCache}. |
|
| 335 | + */ |
|
| 336 | + private final NamedReentrantReadWriteLock regattaTrackingCacheLock; |
|
| 337 | + |
|
| 338 | + private final ConcurrentHashMap<OperationExecutionListener<RacingEventService>, OperationExecutionListener<RacingEventService>> operationExecutionListeners; |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * Keys are the toString() representation of the {@link RaceDefinition#getId() IDs} of races passed to |
|
| 342 | + * {@link #setRegattaForRace(Regatta, RaceDefinition)}. |
|
| 343 | + */ |
|
| 344 | + private final ConcurrentHashMap<String, Regatta> persistentRegattasForRaceIDs; |
|
| 345 | + |
|
| 346 | + private final RaceLogReplicator raceLogReplicator; |
|
| 347 | + private final RegattaLogReplicator regattaLogReplicator; |
|
| 348 | + |
|
| 349 | + private final RaceLogScoringReplicator raceLogScoringReplicator; |
|
| 350 | + |
|
| 351 | + private final MediaDB mediaDB; |
|
| 352 | + |
|
| 353 | + private final MediaLibrary mediaLibrary; |
|
| 354 | + |
|
| 355 | + /** |
|
| 356 | + * Currently valid pairs of {@link DeviceConfigurationMatcher}s and {@link DeviceConfiguration}s. The contents of |
|
| 357 | + * this map is persisted and replicated. See {@link DeviceConfigurationMapImpl}. |
|
| 358 | + */ |
|
| 359 | + protected final DeviceConfigurationMapImpl configurationMap; |
|
| 360 | + |
|
| 361 | + private final WindStore windStore; |
|
| 362 | + private final GPSFixStore gpsFixStore; |
|
| 363 | + |
|
| 364 | + /** |
|
| 365 | + * This author should be used for server generated race log events |
|
| 366 | + */ |
|
| 367 | + private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl( |
|
| 368 | + RacingEventService.class.getName(), 0); |
|
| 369 | + |
|
| 370 | + private PolarDataService polarDataService; |
|
| 371 | + |
|
| 372 | + private final SimulationService simulationService; |
|
| 373 | + |
|
| 374 | + /** |
|
| 375 | + * Allow only one master data import at a time to avoid situation where multiple Imports override each other in |
|
| 376 | + * unpredictable fashion |
|
| 377 | + */ |
|
| 378 | + private final DataImportLockWithProgress dataImportLock; |
|
| 379 | + |
|
| 380 | + /** |
|
| 381 | + * If this service runs in the context of an OSGi environment, the activator should {@link #setBundleContext set the |
|
| 382 | + * bundle context} on this object so that service lookups become possible. |
|
| 383 | + */ |
|
| 384 | + private BundleContext bundleContext; |
|
| 385 | + |
|
| 386 | + private TypeBasedServiceFinderFactory serviceFinderFactory; |
|
| 387 | + |
|
| 388 | + /** |
|
| 389 | + * The master from which this replicable is currently replicating, or <code>null</code> if this replicable is not |
|
| 390 | + * currently replicated from any master. |
|
| 391 | + */ |
|
| 392 | + private ReplicationMasterDescriptor replicatingFromMaster; |
|
| 393 | + |
|
| 394 | + private Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication; |
|
| 395 | + |
|
| 396 | + private ThreadLocal<Boolean> currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster = ThreadLocal |
|
| 397 | + .withInitial(() -> false); |
|
| 398 | + |
|
| 399 | + private final Set<ClassLoader> masterDataClassLoaders = new HashSet<ClassLoader>(); |
|
| 400 | + |
|
| 401 | + private final JoinedClassLoader joinedClassLoader; |
|
| 402 | + |
|
| 403 | + private SailingServerConfiguration sailingServerConfiguration; |
|
| 404 | + |
|
| 405 | + /** |
|
| 406 | + * Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky |
|
| 407 | + * in some cases because containment and initialization order of some types is fairly tightly coupled. |
|
| 408 | + * There is a dependency of many such objects on an instance of {@link RaceLogResolver} which is implemented |
|
| 409 | + * by {@link RacingEventServiceImpl}. However, therefore, this instance only becomes available in the |
|
| 410 | + * innermost constructor. |
|
| 411 | + * |
|
| 412 | + * @author Axel Uhl (d043530) |
|
| 413 | + * |
|
| 414 | + */ |
|
| 415 | + public static interface ConstructorParameters { |
|
| 416 | + DomainObjectFactory getDomainObjectFactory(); |
|
| 417 | + MongoObjectFactory getMongoObjectFactory(); |
|
| 418 | + com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory(); |
|
| 419 | + CompetitorStore getCompetitorStore(); |
|
| 420 | + } |
|
| 421 | + |
|
| 422 | + /** |
|
| 423 | + * Constructs a {@link DomainFactory base domain factory} that uses this object's {@link #competitorStore competitor |
|
| 424 | + * store} for competitor management. This base domain factory is then also used for the construction of the |
|
| 425 | + * {@link DomainObjectFactory}. This constructor variant initially clears the persistent competitor collection, |
|
| 426 | + * hence removes all previously persistent competitors. This is the default for testing and for backward |
|
| 427 | + * compatibility with prior releases that did not support a persistent competitor collection. |
|
| 428 | + */ |
|
| 429 | + public RacingEventServiceImpl() { |
|
| 430 | + this(true, null); |
|
| 431 | + } |
|
| 432 | + |
|
| 433 | + public RacingEventServiceImpl(WindStore windStore, GPSFixStore gpsFixStore, |
|
| 434 | + TypeBasedServiceFinderFactory serviceFinderFactory) { |
|
| 435 | + this(true, windStore, gpsFixStore, serviceFinderFactory); |
|
| 436 | + } |
|
| 437 | + |
|
| 438 | + void setBundleContext(BundleContext bundleContext) { |
|
| 439 | + this.bundleContext = bundleContext; |
|
| 440 | + } |
|
| 441 | + |
|
| 442 | + /** |
|
| 443 | + * Like {@link #RacingEventServiceImpl()}, but allows callers to specify that the persistent competitor collection |
|
| 444 | + * be cleared before the service starts. |
|
| 445 | + * |
|
| 446 | + * @param clearPersistentCompetitorStore |
|
| 447 | + * if <code>true</code>, the {@link PersistentCompetitorStore} is created empty, with the corresponding |
|
| 448 | + * database collection cleared as well. Use with caution! When used with <code>false</code>, competitors |
|
| 449 | + * created and stored during previous service executions will initially be loaded. |
|
| 450 | + */ |
|
| 451 | + public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory) { |
|
| 452 | + this((final RaceLogResolver raceLogResolver)-> { |
|
| 453 | + return new ConstructorParameters() { |
|
| 454 | + private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); |
|
| 455 | + private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore( |
|
| 456 | + PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory), |
|
| 457 | + clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver); |
|
| 458 | + |
|
| 459 | + @Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); } |
|
| 460 | + @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; } |
|
| 461 | + @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } |
|
| 462 | + @Override public CompetitorStore getCompetitorStore() { return competitorStore; } |
|
| 463 | + }; |
|
| 464 | + }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory); |
|
| 465 | + } |
|
| 466 | + |
|
| 467 | + private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore, |
|
| 468 | + GPSFixStore gpsFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory) { |
|
| 469 | + this((final RaceLogResolver raceLogResolver)-> { |
|
| 470 | + return new ConstructorParameters() { |
|
| 471 | + private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); |
|
| 472 | + private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore( |
|
| 473 | + mongoObjectFactory, |
|
| 474 | + clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver); |
|
| 475 | + |
|
| 476 | + @Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); } |
|
| 477 | + @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; } |
|
| 478 | + @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } |
|
| 479 | + @Override public CompetitorStore getCompetitorStore() { return competitorStore; } |
|
| 480 | + }; |
|
| 481 | + }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, gpsFixStore, serviceFinderFactory); |
|
| 482 | + } |
|
| 483 | + |
|
| 484 | + /** |
|
| 485 | + * Uses the default factories for the tracking adapters and the {@link DomainFactory base domain factory} of the |
|
| 486 | + * {@link PersistenceFactory#getDefaultDomainObjectFactory() default domain object factory}. This constructor should |
|
| 487 | + * be used for testing because it provides a transient {@link CompetitorStore} as required for competitor |
|
| 488 | + * persistence. |
|
| 489 | + */ |
|
| 490 | + public RacingEventServiceImpl(Function<RaceLogResolver, DomainObjectFactory> domainObjectFactoryProvider, |
|
| 491 | + final MongoObjectFactory mongoObjectFactory, MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) { |
|
| 492 | + this((final RaceLogResolver raceLogResolver)-> { |
|
| 493 | + return new ConstructorParameters() { |
|
| 494 | + private final DomainObjectFactory domainObjectFactory = domainObjectFactoryProvider.apply(raceLogResolver); |
|
| 495 | + |
|
| 496 | + @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; } |
|
| 497 | + @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; } |
|
| 498 | + @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); } |
|
| 499 | + @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } |
|
| 500 | + }; |
|
| 501 | + }, mediaDB, windStore, gpsFixStore, null); |
|
| 502 | + } |
|
| 503 | + |
|
| 504 | + public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory, |
|
| 505 | + MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) { |
|
| 506 | + this((final RaceLogResolver raceLogResolver)-> { |
|
| 507 | + return new ConstructorParameters() { |
|
| 508 | + @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; } |
|
| 509 | + @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; } |
|
| 510 | + @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); } |
|
| 511 | + @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } |
|
| 512 | + }; |
|
| 513 | + }, mediaDB, windStore, gpsFixStore, null); |
|
| 514 | + } |
|
| 515 | + |
|
| 516 | + /** |
|
| 517 | + * @param windStore |
|
| 518 | + * if <code>null</code>, a default {@link MongoWindStore} will be used, based on the persistence set-up |
|
| 519 | + * of this service |
|
| 520 | + * @param serviceFinderFactory |
|
| 521 | + * used to find the services handling specific types of tracking devices, such as the persistent storage |
|
| 522 | + * of {@link DeviceIdentifier}s of specific device types or the managing of the device-to-competitor |
|
| 523 | + * associations per race tracked. |
|
| 524 | + */ |
|
| 525 | + public RacingEventServiceImpl(Function<RaceLogResolver, ConstructorParameters> constructorParametersProvider, MediaDB mediaDb, |
|
| 526 | + WindStore windStore, GPSFixStore gpsFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) { |
|
| 527 | + logger.info("Created " + this); |
|
| 528 | + final ConstructorParameters constructorParameters = constructorParametersProvider.apply(this); |
|
| 529 | + this.domainObjectFactory = constructorParameters.getDomainObjectFactory(); |
|
| 530 | + this.masterDataClassLoaders.add(this.getClass().getClassLoader()); |
|
| 531 | + joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders); |
|
| 532 | + this.operationsSentToMasterForReplication = new HashSet<>(); |
|
| 533 | + this.baseDomainFactory = constructorParameters.getBaseDomainFactory(); |
|
| 534 | + this.mongoObjectFactory = constructorParameters.getMongoObjectFactory(); |
|
| 535 | + this.mediaDB = mediaDb; |
|
| 536 | + this.competitorStore = constructorParameters.getCompetitorStore(); |
|
| 537 | + if (windStore == null) { |
|
| 538 | + try { |
|
| 539 | + windStore = MongoWindStoreFactory.INSTANCE.getMongoWindStore(mongoObjectFactory, domainObjectFactory); |
|
| 540 | + } catch (Exception e) { |
|
| 541 | + throw new RuntimeException(e); |
|
| 542 | + } |
|
| 543 | + } |
|
| 544 | + this.competitorStore.addCompetitorUpdateListener(new CompetitorUpdateListener() { |
|
| 545 | + @Override |
|
| 546 | + public void competitorUpdated(Competitor competitor) { |
|
| 547 | + replicate(new UpdateCompetitor(competitor.getId().toString(), competitor.getName(), competitor |
|
| 548 | + .getColor(), competitor.getEmail(), competitor.getBoat().getSailID(), competitor.getTeam().getNationality(), |
|
| 549 | + competitor.getTeam().getImage(), competitor.getFlagImage(), |
|
| 550 | + competitor.getTimeOnTimeFactor(), competitor.getTimeOnDistanceAllowancePerNauticalMile())); |
|
| 551 | + } |
|
| 552 | + }); |
|
| 553 | + this.windStore = windStore; |
|
| 554 | + this.dataImportLock = new DataImportLockWithProgress(); |
|
| 555 | + |
|
| 556 | + remoteSailingServerSet = new RemoteSailingServerSet(scheduler); |
|
| 557 | + regattasByName = new ConcurrentHashMap<String, Regatta>(); |
|
| 558 | + regattasByNameLock = new NamedReentrantReadWriteLock("regattasByName for " + this, /* fair */false); |
|
| 559 | + eventsById = new ConcurrentHashMap<Serializable, Event>(); |
|
| 560 | + regattaTrackingCache = new ConcurrentHashMap<>(); |
|
| 561 | + regattaTrackingCacheLock = new NamedReentrantReadWriteLock("regattaTrackingCache for " + this, /* fair */false); |
|
| 562 | + raceTrackersByRegatta = new ConcurrentHashMap<>(); |
|
| 563 | + raceTrackersByRegattaLock = new NamedReentrantReadWriteLock("raceTrackersByRegatta for " + this, /* fair */ |
|
| 564 | + false); |
|
| 565 | + raceTrackersByID = new ConcurrentHashMap<>(); |
|
| 566 | + raceTrackersByIDLocks = new ConcurrentHashMap<>(); |
|
| 567 | + leaderboardGroupsByName = new ConcurrentHashMap<>(); |
|
| 568 | + leaderboardGroupsByID = new ConcurrentHashMap<>(); |
|
| 569 | + leaderboardGroupsByNameLock = new NamedReentrantReadWriteLock("leaderboardGroupsByName for " + this, /* fair */ |
|
| 570 | + false); |
|
| 571 | + leaderboardsByName = new ConcurrentHashMap<String, Leaderboard>(); |
|
| 572 | + leaderboardsByNameLock = new NamedReentrantReadWriteLock("leaderboardsByName for " + this, /* fair */false); |
|
| 573 | + operationExecutionListeners = new ConcurrentHashMap<>(); |
|
| 574 | + courseListeners = new ConcurrentHashMap<>(); |
|
| 575 | + persistentRegattasForRaceIDs = new ConcurrentHashMap<>(); |
|
| 576 | + final int SIMULATION_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/3, 1); |
|
| 577 | + Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */SIMULATION_THREAD_POOL_SIZE, |
|
| 578 | + /* maximumPoolSize */SIMULATION_THREAD_POOL_SIZE, |
|
| 579 | + /* keepAliveTime */60, TimeUnit.SECONDS, |
|
| 580 | + /* workQueue */new LinkedBlockingQueue<Runnable>()); |
|
| 581 | + // TODO: initialize smart-future-cache for simulation-results and add to simulation-service |
|
| 582 | + simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this); |
|
| 583 | + this.raceLogReplicator = new RaceLogReplicator(this); |
|
| 584 | + this.regattaLogReplicator = new RegattaLogReplicator(this); |
|
| 585 | + this.raceLogScoringReplicator = new RaceLogScoringReplicator(this); |
|
| 586 | + this.mediaLibrary = new MediaLibrary(); |
|
| 587 | + if (gpsFixStore == null) { |
|
| 588 | + try { |
|
| 589 | + gpsFixStore = MongoGPSFixStoreFactory.INSTANCE.getMongoGPSFixStore(mongoObjectFactory, |
|
| 590 | + domainObjectFactory, serviceFinderFactory); |
|
| 591 | + } catch (Exception e) { |
|
| 592 | + e.printStackTrace(); |
|
| 593 | + throw new RuntimeException(e); |
|
| 594 | + } |
|
| 595 | + } |
|
| 596 | + this.gpsFixStore = gpsFixStore; |
|
| 597 | + this.configurationMap = new DeviceConfigurationMapImpl(); |
|
| 598 | + this.serviceFinderFactory = serviceFinderFactory; |
|
| 599 | + |
|
| 600 | + sailingServerConfiguration = domainObjectFactory.loadServerConfiguration(); |
|
| 601 | + final Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = loadStoredEvents(); |
|
| 602 | + loadStoredRegattas(); |
|
| 603 | + loadRaceIDToRegattaAssociations(); |
|
| 604 | + loadStoredLeaderboardsAndGroups(); |
|
| 605 | + loadLinksFromEventsToLeaderboardGroups(); |
|
| 606 | + loadMediaLibary(); |
|
| 607 | + loadStoredDeviceConfigurations(); |
|
| 608 | + loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh(); |
|
| 609 | + |
|
| 610 | + // Stores all events which run through a data migration |
|
| 611 | + // Remark: must be called after loadLinksFromEventsToLeaderboardGroups(), otherwise would loose the Event -> LeaderboardGroup relation |
|
| 612 | + for (Pair<Event, Boolean> eventAndRequireStoreFlag : loadedEventsWithRequireStoreFlag) { |
|
| 613 | + if (eventAndRequireStoreFlag.getB()) { |
|
| 614 | + mongoObjectFactory.storeEvent(eventAndRequireStoreFlag.getA()); |
|
| 615 | + } |
|
| 616 | + } |
|
| 617 | + } |
|
| 618 | + |
|
| 619 | + @Override |
|
| 620 | + public boolean isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster() { |
|
| 621 | + return currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.get(); |
|
| 622 | + } |
|
| 623 | + |
|
| 624 | + @Override |
|
| 625 | + public void setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster( |
|
| 626 | + boolean currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster) { |
|
| 627 | + this.currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster |
|
| 628 | + .set(currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster); |
|
| 629 | + } |
|
| 630 | + |
|
| 631 | + @Override |
|
| 632 | + public PolarDataService getPolarDataService() { |
|
| 633 | + return polarDataService; |
|
| 634 | + } |
|
| 635 | + |
|
| 636 | + @Override |
|
| 637 | + public SimulationService getSimulationService() { |
|
| 638 | + return simulationService; |
|
| 639 | + } |
|
| 640 | + |
|
| 641 | + @Override |
|
| 642 | + public void clearState() throws Exception { |
|
| 643 | + for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) { |
|
| 644 | + removeLeaderboardGroup(leaderboardGroupName); |
|
| 645 | + } |
|
| 646 | + for (String leaderboardName : new ArrayList<>(this.leaderboardsByName.keySet())) { |
|
| 647 | + removeLeaderboard(leaderboardName); |
|
| 648 | + } |
|
| 649 | + for (Regatta regatta : new ArrayList<>(this.regattasByName.values())) { |
|
| 650 | + stopTracking(regatta); |
|
| 651 | + removeRegatta(regatta); |
|
| 652 | + } |
|
| 653 | + for (Event event : new ArrayList<>(this.eventsById.values())) { |
|
| 654 | + removeEvent(event.getId()); |
|
| 655 | + } |
|
| 656 | + for (MediaTrack mediaTrack : this.mediaLibrary.allTracks()) { |
|
| 657 | + mediaTrackDeleted(mediaTrack); |
|
| 658 | + } |
|
| 659 | + // TODO clear user store? See bug 2430. |
|
| 660 | + this.competitorStore.clear(); |
|
| 661 | + } |
|
| 662 | + |
|
| 663 | + @Override |
|
| 664 | + public com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory() { |
|
| 665 | + return baseDomainFactory; |
|
| 666 | + } |
|
| 667 | + |
|
| 668 | + @Override |
|
| 669 | + public MongoObjectFactory getMongoObjectFactory() { |
|
| 670 | + return mongoObjectFactory; |
|
| 671 | + } |
|
| 672 | + |
|
| 673 | + @Override |
|
| 674 | + public DomainObjectFactory getDomainObjectFactory() { |
|
| 675 | + return domainObjectFactory; |
|
| 676 | + } |
|
| 677 | + |
|
| 678 | + private void loadRaceIDToRegattaAssociations() { |
|
| 679 | + persistentRegattasForRaceIDs.putAll(domainObjectFactory.loadRaceIDToRegattaAssociations(this)); |
|
| 680 | + } |
|
| 681 | + |
|
| 682 | + private void loadStoredRegattas() { |
|
| 683 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 684 | + try { |
|
| 685 | + for (Regatta regatta : domainObjectFactory.loadAllRegattas(this)) { |
|
| 686 | + logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode() |
|
| 687 | + + ") into regattasByName"); |
|
| 688 | + regattasByName.put(regatta.getName(), regatta); |
|
| 689 | + regatta.addRegattaListener(this); |
|
| 690 | + onRegattaLikeAdded(regatta); |
|
| 691 | + regatta.addRaceColumnListener(raceLogReplicator); |
|
| 692 | + regatta.addRaceColumnListener(raceLogScoringReplicator); |
|
| 693 | + } |
|
| 694 | + } finally { |
|
| 695 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 696 | + } |
|
| 697 | + } |
|
| 698 | + |
|
| 699 | + private Iterable<Pair<Event, Boolean>> loadStoredEvents() { |
|
| 700 | + Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = domainObjectFactory.loadAllEvents(); |
|
| 701 | + for (Pair<Event, Boolean> eventAndFlag : loadedEventsWithRequireStoreFlag) { |
|
| 702 | + Event event = eventAndFlag.getA(); |
|
| 703 | + if (event.getId() != null) |
|
| 704 | + eventsById.put(event.getId(), event); |
|
| 705 | + } |
|
| 706 | + return loadedEventsWithRequireStoreFlag; |
|
| 707 | + } |
|
| 708 | + |
|
| 709 | + private void loadLinksFromEventsToLeaderboardGroups() { |
|
| 710 | + domainObjectFactory.loadLeaderboardGroupLinksForEvents(/* eventResolver */this, /* leaderboardGroupResolver */ |
|
| 711 | + this); |
|
| 712 | + } |
|
| 713 | + |
|
| 714 | + private void loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh() { |
|
| 715 | + for (RemoteSailingServerReference sailingServer : domainObjectFactory.loadAllRemoteSailingServerReferences()) { |
|
| 716 | + remoteSailingServerSet.add(sailingServer); |
|
| 717 | + } |
|
| 718 | + } |
|
| 719 | + |
|
| 720 | + /** |
|
| 721 | + * Collects media track references from the configured sources (mongo DB by default, ftp folder yet to be |
|
| 722 | + * implemented). The method is expected to be called initially blocking the API until finished. |
|
| 723 | + * |
|
| 724 | + * Subsequent calls (assumed to be triggered from the admin console or in scheduled intervals) don't need to block. |
|
| 725 | + * In that case, the API will simply serve the current state. |
|
| 726 | + * |
|
| 727 | + */ |
|
| 728 | + private void loadMediaLibary() { |
|
| 729 | + Collection<MediaTrack> allDbMediaTracks = mediaDB.loadAllMediaTracks(); |
|
| 730 | + mediaTracksAdded(allDbMediaTracks); |
|
| 731 | + } |
|
| 732 | + |
|
| 733 | + private void loadStoredDeviceConfigurations() { |
|
| 734 | + for (Entry<DeviceConfigurationMatcher, DeviceConfiguration> entry : domainObjectFactory |
|
| 735 | + .loadAllDeviceConfigurations()) { |
|
| 736 | + configurationMap.put(entry.getKey(), entry.getValue()); |
|
| 737 | + } |
|
| 738 | + } |
|
| 739 | + |
|
| 740 | + @Override |
|
| 741 | + public void addLeaderboard(Leaderboard leaderboard) { |
|
| 742 | + LockUtil.lockForWrite(leaderboardsByNameLock); |
|
| 743 | + try { |
|
| 744 | + leaderboardsByName.put(leaderboard.getName(), leaderboard); |
|
| 745 | + } finally { |
|
| 746 | + LockUtil.unlockAfterWrite(leaderboardsByNameLock); |
|
| 747 | + } |
|
| 748 | + // RaceColumns of RegattaLeaderboards are tracked via its Regatta! |
|
| 749 | + if (leaderboard instanceof FlexibleLeaderboard) { |
|
| 750 | + onRegattaLikeAdded(((FlexibleLeaderboard) leaderboard).getRegattaLike()); |
|
| 751 | + leaderboard.addRaceColumnListener(raceLogReplicator); |
|
| 752 | + leaderboard.addRaceColumnListener(raceLogScoringReplicator); |
|
| 753 | + } |
|
| 754 | + } |
|
| 755 | + |
|
| 756 | + private void loadStoredLeaderboardsAndGroups() { |
|
| 757 | + logger.info("loading stored leaderboards and groups"); |
|
| 758 | + // Loading all leaderboard groups and the contained leaderboards |
|
| 759 | + for (LeaderboardGroup leaderboardGroup : domainObjectFactory.getAllLeaderboardGroups(this, this)) { |
|
| 760 | + logger.info("loaded leaderboard group " + leaderboardGroup.getName() + " into " + this); |
|
| 761 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 762 | + try { |
|
| 763 | + leaderboardGroupsByName.put(leaderboardGroup.getName(), leaderboardGroup); |
|
| 764 | + leaderboardGroupsByID.put(leaderboardGroup.getId(), leaderboardGroup); |
|
| 765 | + } finally { |
|
| 766 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 767 | + } |
|
| 768 | + } |
|
| 769 | + // Loading the remaining leaderboards |
|
| 770 | + domainObjectFactory.getLeaderboardsNotInGroup(this, this); |
|
| 771 | + logger.info("done with loading stored leaderboards and groups"); |
|
| 772 | + } |
|
| 773 | + |
|
| 774 | + @Override |
|
| 775 | + public FlexibleLeaderboard addFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, |
|
| 776 | + int[] discardThresholds, ScoringScheme scoringScheme, Serializable courseAreaId) { |
|
| 777 | + logger.info("adding flexible leaderboard " + leaderboardName); |
|
| 778 | + CourseArea courseArea = getCourseArea(courseAreaId); |
|
| 779 | + FlexibleLeaderboard result = new FlexibleLeaderboardImpl(getRaceLogStore(), getRegattaLogStore(), |
|
| 780 | + leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardThresholds), scoringScheme, |
|
| 781 | + courseArea); |
|
| 782 | + result.setDisplayName(leaderboardDisplayName); |
|
| 783 | + if (getLeaderboardByName(leaderboardName) != null) { |
|
| 784 | + throw new IllegalArgumentException("Leaderboard with name " + leaderboardName + " already exists"); |
|
| 785 | + } |
|
| 786 | + addLeaderboard(result); |
|
| 787 | + mongoObjectFactory.storeLeaderboard(result); |
|
| 788 | + return result; |
|
| 789 | + } |
|
| 790 | + |
|
| 791 | + @Override |
|
| 792 | + public CourseArea getCourseArea(Serializable courseAreaId) { |
|
| 793 | + for (Event event : getAllEvents()) { |
|
| 794 | + for (CourseArea courseArea : event.getVenue().getCourseAreas()) { |
|
| 795 | + if (courseArea.getId().equals(courseAreaId)) { |
|
| 796 | + return courseArea; |
|
| 797 | + } |
|
| 798 | + } |
|
| 799 | + } |
|
| 800 | + return null; |
|
| 801 | + } |
|
| 802 | + |
|
| 803 | + @Override |
|
| 804 | + public RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, |
|
| 805 | + int[] discardThresholds) { |
|
| 806 | + Regatta regatta = getRegatta(regattaIdentifier); |
|
| 807 | + logger.info("adding regatta leaderboard for regatta " |
|
| 808 | + + (regatta == null ? "null" : (regatta.getName() + " (" + regatta.hashCode() + ")")) + " to " + this); |
|
| 809 | + RegattaLeaderboard result = null; |
|
| 810 | + if (regatta != null) { |
|
| 811 | + result = new RegattaLeaderboardImpl(regatta, new ThresholdBasedResultDiscardingRuleImpl(discardThresholds)); |
|
| 812 | + result.setDisplayName(leaderboardDisplayName); |
|
| 813 | + if (getLeaderboardByName(result.getName()) != null) { |
|
| 814 | + throw new IllegalArgumentException("Leaderboard with name " + result.getName() + " already exists in " |
|
| 815 | + + this); |
|
| 816 | + } |
|
| 817 | + addLeaderboard(result); |
|
| 818 | + mongoObjectFactory.storeLeaderboard(result); |
|
| 819 | + } else { |
|
| 820 | + logger.warning("Cannot find regatta " + regattaIdentifier |
|
| 821 | + + ". Hence, cannot create regatta leaderboard for it."); |
|
| 822 | + } |
|
| 823 | + return result; |
|
| 824 | + } |
|
| 825 | + |
|
| 826 | + @Override |
|
| 827 | + public RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace) { |
|
| 828 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 829 | + if (leaderboard != null) { |
|
| 830 | + if (leaderboard instanceof FlexibleLeaderboard) { |
|
| 831 | + // uses the default fleet as the single fleet for the new column |
|
| 832 | + RaceColumn result = ((FlexibleLeaderboard) leaderboard).addRaceColumn(columnName, medalRace); |
|
| 833 | + updateStoredLeaderboard((FlexibleLeaderboard) leaderboard); |
|
| 834 | + return result; |
|
| 835 | + } else { |
|
| 836 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName |
|
| 837 | + + " is not a FlexibleLeaderboard"); |
|
| 838 | + } |
|
| 839 | + } else { |
|
| 840 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 841 | + } |
|
| 842 | + } |
|
| 843 | + |
|
| 844 | + @Override |
|
| 845 | + public void moveLeaderboardColumnUp(String leaderboardName, String columnName) { |
|
| 846 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 847 | + if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) { |
|
| 848 | + ((FlexibleLeaderboard) leaderboard).moveRaceColumnUp(columnName); |
|
| 849 | + updateStoredLeaderboard((FlexibleLeaderboard) leaderboard); |
|
| 850 | + } else { |
|
| 851 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 852 | + } |
|
| 853 | + } |
|
| 854 | + |
|
| 855 | + @Override |
|
| 856 | + public void moveLeaderboardColumnDown(String leaderboardName, String columnName) { |
|
| 857 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 858 | + if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) { |
|
| 859 | + ((FlexibleLeaderboard) leaderboard).moveRaceColumnDown(columnName); |
|
| 860 | + updateStoredLeaderboard((FlexibleLeaderboard) leaderboard); |
|
| 861 | + } else { |
|
| 862 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 863 | + } |
|
| 864 | + } |
|
| 865 | + |
|
| 866 | + @Override |
|
| 867 | + public void removeLeaderboardColumn(String leaderboardName, String columnName) { |
|
| 868 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 869 | + if (leaderboard == null) { |
|
| 870 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 871 | + } else if (!(leaderboard instanceof FlexibleLeaderboard)) { |
|
| 872 | + throw new IllegalArgumentException("Columns cannot be removed from Leaderboard named " + leaderboardName); |
|
| 873 | + } else { |
|
| 874 | + ((FlexibleLeaderboard) leaderboard).removeRaceColumn(columnName); |
|
| 875 | + updateStoredLeaderboard((FlexibleLeaderboard) leaderboard); |
|
| 876 | + } |
|
| 877 | + } |
|
| 878 | + |
|
| 879 | + @Override |
|
| 880 | + public void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName) { |
|
| 881 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 882 | + if (leaderboard != null) { |
|
| 883 | + final RaceColumn raceColumn = leaderboard.getRaceColumnByName(oldColumnName); |
|
| 884 | + if (raceColumn instanceof FlexibleRaceColumn) { |
|
| 885 | + // remove race log under old identifier; the race log identifier changes |
|
| 886 | + for (Fleet fleet : raceColumn.getFleets()) { |
|
| 887 | + getMongoObjectFactory().removeRaceLog(raceColumn.getRaceLogIdentifier(fleet)); |
|
| 888 | + } |
|
| 889 | + ((FlexibleRaceColumn) raceColumn).setName(newColumnName); |
|
| 890 | + // store the race logs again under the new identifiers |
|
| 891 | + storeRaceLogs(raceColumn); |
|
| 892 | + updateStoredLeaderboard(leaderboard); |
|
| 893 | + } else { |
|
| 894 | + throw new IllegalArgumentException("Race column " + oldColumnName + " cannot be renamed"); |
|
| 895 | + } |
|
| 896 | + } else { |
|
| 897 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 898 | + } |
|
| 899 | + } |
|
| 900 | + |
|
| 901 | + /** |
|
| 902 | + * When a race column is renamed, its race log identifiers change. Therefore, the race logs need to be stored under |
|
| 903 | + * the new identifier again to be consistent with the in-memory image again. |
|
| 904 | + */ |
|
| 905 | + private void storeRaceLogs(RaceColumn raceColumn) { |
|
| 906 | + for (Fleet fleet : raceColumn.getFleets()) { |
|
| 907 | + RaceLogIdentifier identifier = raceColumn.getRaceLogIdentifier(fleet); |
|
| 908 | + RaceLogEventVisitor storeVisitor = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStoreVisitor( |
|
| 909 | + identifier, getMongoObjectFactory()); |
|
| 910 | + RaceLog raceLog = raceColumn.getRaceLog(fleet); |
|
| 911 | + raceLog.lockForRead(); |
|
| 912 | + try { |
|
| 913 | + for (RaceLogEvent e : raceLog.getRawFixes()) { |
|
| 914 | + e.accept(storeVisitor); |
|
| 915 | + } |
|
| 916 | + } finally { |
|
| 917 | + raceLog.unlockAfterRead(); |
|
| 918 | + } |
|
| 919 | + } |
|
| 920 | + } |
|
| 921 | + |
|
| 922 | + @Override |
|
| 923 | + public void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor) { |
|
| 924 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 925 | + if (leaderboard != null) { |
|
| 926 | + final RaceColumn raceColumn = leaderboard.getRaceColumnByName(columnName); |
|
| 927 | + if (raceColumn != null) { |
|
| 928 | + raceColumn.setFactor(factor); |
|
| 929 | + updateStoredLeaderboard(leaderboard); |
|
| 930 | + } else { |
|
| 931 | + throw new IllegalArgumentException("Race column " + columnName + " not found in leaderboard " |
|
| 932 | + + leaderboardName); |
|
| 933 | + } |
|
| 934 | + } else { |
|
| 935 | + throw new IllegalArgumentException("Leaderboard named " + leaderboardName + " not found"); |
|
| 936 | + } |
|
| 937 | + } |
|
| 938 | + |
|
| 939 | + @Override |
|
| 940 | + public void renameLeaderboard(String oldName, String newName) { |
|
| 941 | + final Leaderboard toRename = leaderboardsByName.get(oldName); |
|
| 942 | + LockUtil.lockForWrite(leaderboardsByNameLock); |
|
| 943 | + try { |
|
| 944 | + if (toRename == null) { |
|
| 945 | + throw new IllegalArgumentException("No leaderboard with name " + oldName + " found"); |
|
| 946 | + } |
|
| 947 | + if (leaderboardsByName.containsKey(newName)) { |
|
| 948 | + throw new IllegalArgumentException("Leaderboard with name " + newName + " already exists"); |
|
| 949 | + } |
|
| 950 | + if (toRename instanceof Renamable) { |
|
| 951 | + ((Renamable) toRename).setName(newName); |
|
| 952 | + leaderboardsByName.remove(oldName); |
|
| 953 | + leaderboardsByName.put(newName, toRename); |
|
| 954 | + } else { |
|
| 955 | + throw new IllegalArgumentException("Leaderboard with name " + newName + " is of type " |
|
| 956 | + + toRename.getClass().getSimpleName() + " and therefore cannot be renamed"); |
|
| 957 | + } |
|
| 958 | + } finally { |
|
| 959 | + LockUtil.unlockAfterWrite(leaderboardsByNameLock); |
|
| 960 | + } |
|
| 961 | + // don't need the lock anymore to update DB |
|
| 962 | + if (toRename instanceof Renamable) { |
|
| 963 | + mongoObjectFactory.renameLeaderboard(oldName, newName); |
|
| 964 | + syncGroupsAfterLeaderboardChange(toRename, true); |
|
| 965 | + } |
|
| 966 | + } |
|
| 967 | + |
|
| 968 | + @Override |
|
| 969 | + public void updateStoredLeaderboard(Leaderboard leaderboard) { |
|
| 970 | + getMongoObjectFactory().storeLeaderboard(leaderboard); |
|
| 971 | + syncGroupsAfterLeaderboardChange(leaderboard, true); |
|
| 972 | + } |
|
| 973 | + |
|
| 974 | + @Override |
|
| 975 | + public void updateStoredRegatta(Regatta regatta) { |
|
| 976 | + if (regatta.isPersistent()) { |
|
| 977 | + mongoObjectFactory.storeRegatta(regatta); |
|
| 978 | + } |
|
| 979 | + } |
|
| 980 | + |
|
| 981 | + /** |
|
| 982 | + * Checks all groups, if they contain a leaderboard with the name of the <code>updatedLeaderboard</code> and |
|
| 983 | + * replaces the one in the group with the updated one.<br /> |
|
| 984 | + * This synchronizes things like the RaceIdentifier in the leaderboard columns. |
|
| 985 | + */ |
|
| 986 | + private void syncGroupsAfterLeaderboardChange(Leaderboard updatedLeaderboard, boolean doDatabaseUpdate) { |
|
| 987 | + boolean groupNeedsUpdate = false; |
|
| 988 | + for (LeaderboardGroup leaderboardGroup : leaderboardGroupsByName.values()) { |
|
| 989 | + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { |
|
| 990 | + if (leaderboard == updatedLeaderboard) { |
|
| 991 | + int index = leaderboardGroup.getIndexOf(leaderboard); |
|
| 992 | + leaderboardGroup.removeLeaderboard(leaderboard); |
|
| 993 | + leaderboardGroup.addLeaderboardAt(updatedLeaderboard, index); |
|
| 994 | + groupNeedsUpdate = true; |
|
| 995 | + // TODO we assume that the leaderboard names are unique, so we can break the inner loop here |
|
| 996 | + break; |
|
| 997 | + } |
|
| 998 | + } |
|
| 999 | + |
|
| 1000 | + if (doDatabaseUpdate && groupNeedsUpdate) { |
|
| 1001 | + mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup); |
|
| 1002 | + } |
|
| 1003 | + groupNeedsUpdate = false; |
|
| 1004 | + } |
|
| 1005 | + } |
|
| 1006 | + |
|
| 1007 | + @Override |
|
| 1008 | + public void removeLeaderboard(String leaderboardName) { |
|
| 1009 | + Leaderboard leaderboard = removeLeaderboardFromLeaderboardsByName(leaderboardName); |
|
| 1010 | + if (leaderboard != null) { |
|
| 1011 | + leaderboard.removeRaceColumnListener(raceLogReplicator); |
|
| 1012 | + leaderboard.removeRaceColumnListener(raceLogScoringReplicator); |
|
| 1013 | + mongoObjectFactory.removeLeaderboard(leaderboardName); |
|
| 1014 | + syncGroupsAfterLeaderboardRemove(leaderboardName, true); |
|
| 1015 | + if (leaderboard instanceof FlexibleLeaderboard) { |
|
| 1016 | + onRegattaLikeRemoved(((FlexibleLeaderboard) leaderboard).getRegattaLike()); |
|
| 1017 | + } |
|
| 1018 | + leaderboard.destroy(); |
|
| 1019 | + } |
|
| 1020 | + } |
|
| 1021 | + |
|
| 1022 | + private Leaderboard removeLeaderboardFromLeaderboardsByName(String leaderboardName) { |
|
| 1023 | + LockUtil.lockForWrite(leaderboardsByNameLock); |
|
| 1024 | + try { |
|
| 1025 | + return leaderboardsByName.remove(leaderboardName); |
|
| 1026 | + } finally { |
|
| 1027 | + LockUtil.unlockAfterWrite(leaderboardsByNameLock); |
|
| 1028 | + } |
|
| 1029 | + } |
|
| 1030 | + |
|
| 1031 | + /** |
|
| 1032 | + * Checks all groups, if they contain a leaderboard with the <code>removedLeaderboardName</code> and removes it from |
|
| 1033 | + * the group. |
|
| 1034 | + * |
|
| 1035 | + * @param removedLeaderboardName |
|
| 1036 | + */ |
|
| 1037 | + private void syncGroupsAfterLeaderboardRemove(String removedLeaderboardName, boolean doDatabaseUpdate) { |
|
| 1038 | + boolean groupNeedsUpdate = false; |
|
| 1039 | + for (LeaderboardGroup leaderboardGroup : leaderboardGroupsByName.values()) { |
|
| 1040 | + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { |
|
| 1041 | + if (leaderboard.getName().equals(removedLeaderboardName)) { |
|
| 1042 | + leaderboardGroup.removeLeaderboard(leaderboard); |
|
| 1043 | + groupNeedsUpdate = true; |
|
| 1044 | + // TODO we assume that the leaderboard names are unique, so we can break the inner loop here |
|
| 1045 | + break; |
|
| 1046 | + } |
|
| 1047 | + } |
|
| 1048 | + |
|
| 1049 | + if (doDatabaseUpdate && groupNeedsUpdate) { |
|
| 1050 | + mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup); |
|
| 1051 | + } |
|
| 1052 | + groupNeedsUpdate = false; |
|
| 1053 | + } |
|
| 1054 | + } |
|
| 1055 | + |
|
| 1056 | + @Override |
|
| 1057 | + public Leaderboard getLeaderboardByName(String name) { |
|
| 1058 | + return leaderboardsByName.get(name); |
|
| 1059 | + } |
|
| 1060 | + |
|
| 1061 | + @Override |
|
| 1062 | + public Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog) { |
|
| 1063 | + GPSFixTrack<Mark, GPSFix> track = null; |
|
| 1064 | + // If no spanning track is found, the fix closest to the time point requested is used instead |
|
| 1065 | + GPSFix nonSpanningFallback = null; |
|
| 1066 | + for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) { |
|
| 1067 | + GPSFixTrack<Mark, GPSFix> trackCandidate = trackedRace.getTrack(mark); |
|
| 1068 | + if (trackCandidate != null) { |
|
| 1069 | + if (spansTimePoint(trackCandidate, timePoint)) { |
|
| 1070 | + track = trackCandidate; |
|
| 1071 | + break; |
|
| 1072 | + } else { |
|
| 1073 | + nonSpanningFallback = improveTimewiseClosestFix(nonSpanningFallback, trackCandidate, timePoint); |
|
| 1074 | + } |
|
| 1075 | + } |
|
| 1076 | + } |
|
| 1077 | + if (track == null) { // no spanning track found in any tracked race, or no tracked races found |
|
| 1078 | + // try to load from store |
|
| 1079 | + DynamicGPSFixTrackImpl<Mark> loadedTrack = new DynamicGPSFixTrackImpl<Mark>(mark, 0); |
|
| 1080 | + track = loadedTrack; |
|
| 1081 | + Set<AbstractLog<?, ?>> logs = new HashSet<>(); |
|
| 1082 | + logs.add(leaderboard.getRegattaLike().getRegattaLog()); |
|
| 1083 | + if (raceLog == null) { // no race log explicitly provided --> use all race logs |
|
| 1084 | + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { |
|
| 1085 | + for (Fleet fleet : raceColumn.getFleets()) { |
|
| 1086 | + logs.add(raceColumn.getRaceLog(fleet)); |
|
| 1087 | + } |
|
| 1088 | + } |
|
| 1089 | + } else { |
|
| 1090 | + logs.add(raceLog); |
|
| 1091 | + } |
|
| 1092 | + for (AbstractLog<?, ?> log : logs) { |
|
| 1093 | + try { |
|
| 1094 | + getGPSFixStore().loadMarkTrack(loadedTrack, log, mark); |
|
| 1095 | + } catch (Exception e) { |
|
| 1096 | + logger.log(Level.WARNING, "Couldn't load mark track for mark " + mark + " from log " + log, e); |
|
| 1097 | + } |
|
| 1098 | + } |
|
| 1099 | + } |
|
| 1100 | + Position result = track.getEstimatedPosition(timePoint, /* extrapolate */ false); |
|
| 1101 | + if (result == null) { |
|
| 1102 | + result = nonSpanningFallback == null ? null : nonSpanningFallback.getPosition(); |
|
| 1103 | + } |
|
| 1104 | + return result; |
|
| 1105 | + } |
|
| 1106 | + |
|
| 1107 | + private GPSFix improveTimewiseClosestFix(GPSFix nonSpanningFallback, GPSFixTrack<Mark, GPSFix> track, final TimePoint timePoint) { |
|
| 1108 | + GPSFix lastAtOrBefore = track.getLastFixAtOrBefore(timePoint); |
|
| 1109 | + GPSFix firstAtOrAfter = track.getFirstFixAtOrAfter(timePoint); |
|
| 1110 | + // find the fix closes to timePoint, sorting null values to the end and fixes near timePoint to the beginning |
|
| 1111 | + final List<GPSFix> list = Arrays.asList(nonSpanningFallback, lastAtOrBefore, firstAtOrAfter); |
|
| 1112 | + list.sort(new Comparator<GPSFix>() { |
|
| 1113 | + @Override |
|
| 1114 | + public int compare(GPSFix o1, GPSFix o2) { |
|
| 1115 | + final int result; |
|
| 1116 | + if (o1 == null) { |
|
| 1117 | + if (o2 == null) { |
|
| 1118 | + result = 0; |
|
| 1119 | + } else { |
|
| 1120 | + result = 1; |
|
| 1121 | + } |
|
| 1122 | + } else if (o2 == null) { |
|
| 1123 | + result = -1; |
|
| 1124 | + } else { |
|
| 1125 | + result = new Long(Math.abs(o1.getTimePoint().until(timePoint).asMillis())).compareTo( |
|
| 1126 | + Math.abs(o2.getTimePoint().until(timePoint).asMillis())); |
|
| 1127 | + } |
|
| 1128 | + return result; |
|
| 1129 | + } |
|
| 1130 | + }); |
|
| 1131 | + return list.get(0); |
|
| 1132 | + } |
|
| 1133 | + |
|
| 1134 | + private boolean spansTimePoint(GPSFixTrack<Mark, GPSFix> track, TimePoint timePoint) { |
|
| 1135 | + return track.getLastFixAtOrBefore(timePoint) != null && track.getFirstFixAtOrAfter(timePoint) != null; |
|
| 1136 | + } |
|
| 1137 | + |
|
| 1138 | + @Override |
|
| 1139 | + public Map<String, Leaderboard> getLeaderboards() { |
|
| 1140 | + return Collections.unmodifiableMap(new HashMap<String, Leaderboard>(leaderboardsByName)); |
|
| 1141 | + } |
|
| 1142 | + |
|
| 1143 | + @Override |
|
| 1144 | + public SailingServerConfiguration getSailingServerConfiguration() { |
|
| 1145 | + return sailingServerConfiguration; |
|
| 1146 | + } |
|
| 1147 | + |
|
| 1148 | + @Override |
|
| 1149 | + public void updateServerConfiguration(SailingServerConfiguration serverConfiguration) { |
|
| 1150 | + this.sailingServerConfiguration = serverConfiguration; |
|
| 1151 | + mongoObjectFactory.storeServerConfiguration(serverConfiguration); |
|
| 1152 | + } |
|
| 1153 | + |
|
| 1154 | + @Override |
|
| 1155 | + public Map<RemoteSailingServerReference, com.sap.sse.common.Util.Pair<Iterable<EventBase>, Exception>> getPublicEventsOfAllSailingServers() { |
|
| 1156 | + return remoteSailingServerSet.getCachedEventsForRemoteSailingServers(); // FIXME should probably add our own |
|
| 1157 | + // stuff here... Is it enough to pass on |
|
| 1158 | + // the remote reference URL to the |
|
| 1159 | + // client for leaderboard group URL |
|
| 1160 | + // construction? |
|
| 1161 | + } |
|
| 1162 | + |
|
| 1163 | + @Override |
|
| 1164 | + public RemoteSailingServerReference addRemoteSailingServerReference(String name, URL url) { |
|
| 1165 | + RemoteSailingServerReference result = new RemoteSailingServerReferenceImpl(name, url); |
|
| 1166 | + remoteSailingServerSet.add(result); |
|
| 1167 | + mongoObjectFactory.storeSailingServer(result); |
|
| 1168 | + return result; |
|
| 1169 | + } |
|
| 1170 | + |
|
| 1171 | + @Override |
|
| 1172 | + public Iterable<RemoteSailingServerReference> getLiveRemoteServerReferences() { |
|
| 1173 | + return remoteSailingServerSet.getLiveRemoteServerReferences(); |
|
| 1174 | + } |
|
| 1175 | + |
|
| 1176 | + @Override |
|
| 1177 | + public RemoteSailingServerReference getRemoteServerReferenceByName(String remoteServerReferenceName) { |
|
| 1178 | + return remoteSailingServerSet.getServerReferenceByName(remoteServerReferenceName); |
|
| 1179 | + } |
|
| 1180 | + |
|
| 1181 | + @Override |
|
| 1182 | + public com.sap.sse.common.Util.Pair<Iterable<EventBase>, Exception> updateRemoteServerEventCacheSynchronously( |
|
| 1183 | + RemoteSailingServerReference ref) { |
|
| 1184 | + return remoteSailingServerSet.getEventsOrException(ref); |
|
| 1185 | + } |
|
| 1186 | + |
|
| 1187 | + @Override |
|
| 1188 | + public void removeRemoteSailingServerReference(String name) { |
|
| 1189 | + remoteSailingServerSet.remove(name); |
|
| 1190 | + mongoObjectFactory.removeSailingServer(name); |
|
| 1191 | + } |
|
| 1192 | + |
|
| 1193 | + @Override |
|
| 1194 | + public Iterable<Event> getAllEvents() { |
|
| 1195 | + return Collections.unmodifiableCollection(new ArrayList<Event>(eventsById.values())); |
|
| 1196 | + } |
|
| 1197 | + |
|
| 1198 | + @Override |
|
| 1199 | + public Event getEvent(Serializable id) { |
|
| 1200 | + return id == null ? null : eventsById.get(id); |
|
| 1201 | + } |
|
| 1202 | + |
|
| 1203 | + @Override |
|
| 1204 | + public Iterable<Regatta> getAllRegattas() { |
|
| 1205 | + return Collections.unmodifiableCollection(new ArrayList<Regatta>(regattasByName.values())); |
|
| 1206 | + } |
|
| 1207 | + |
|
| 1208 | + @Override |
|
| 1209 | + public boolean isRaceBeingTracked(Regatta regattaContext, RaceDefinition r) { |
|
| 1210 | + Set<RaceTracker> trackers = raceTrackersByRegatta.get(regattaContext); |
|
| 1211 | + if (trackers != null) { |
|
| 1212 | + for (RaceTracker tracker : trackers) { |
|
| 1213 | + final Set<RaceDefinition> races = tracker.getRaces(); |
|
| 1214 | + if (races != null && races.contains(r)) { |
|
| 1215 | + return true; |
|
| 1216 | + } |
|
| 1217 | + } |
|
| 1218 | + } |
|
| 1219 | + return false; |
|
| 1220 | + } |
|
| 1221 | + |
|
| 1222 | + @Override |
|
| 1223 | + public Regatta getRegattaByName(String name) { |
|
| 1224 | + return name == null ? null : regattasByName.get(name); |
|
| 1225 | + } |
|
| 1226 | + |
|
| 1227 | + @Override |
|
| 1228 | + public Regatta getOrCreateDefaultRegatta(String name, String boatClassName, Serializable id) { |
|
| 1229 | + Regatta result = regattasByName.get(name); |
|
| 1230 | + if (result == null) { |
|
| 1231 | + result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, getBaseDomainFactory() |
|
| 1232 | + .getOrCreateBoatClass(boatClassName), /* startDate */null, /* endDate */null, this, |
|
| 1233 | + getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), id, null); |
|
| 1234 | + logger.info("Created default regatta " + result.getName() + " (" + hashCode() + ") on " + this); |
|
| 1235 | + onRegattaLikeAdded(result); |
|
| 1236 | + cacheAndReplicateDefaultRegatta(result); |
|
| 1237 | + } |
|
| 1238 | + return result; |
|
| 1239 | + } |
|
| 1240 | + |
|
| 1241 | + private void onRegattaLikeAdded(IsRegattaLike isRegattaLike) { |
|
| 1242 | + isRegattaLike.addListener(regattaLogReplicator); |
|
| 1243 | + } |
|
| 1244 | + |
|
| 1245 | + private void onRegattaLikeRemoved(IsRegattaLike isRegattaLike) { |
|
| 1246 | + isRegattaLike.removeListener(regattaLogReplicator); |
|
| 1247 | + getRegattaLogStore().removeRegattaLog(isRegattaLike.getRegattaLikeIdentifier()); |
|
| 1248 | + } |
|
| 1249 | + |
|
| 1250 | + @Override |
|
| 1251 | + public Regatta createRegatta(String fullRegattaName, String boatClassName, TimePoint startDate, TimePoint endDate, |
|
| 1252 | + Serializable id, Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme, |
|
| 1253 | + Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) { |
|
| 1254 | + com.sap.sse.common.Util.Pair<Regatta, Boolean> regattaWithCreatedFlag = getOrCreateRegattaWithoutReplication( |
|
| 1255 | + fullRegattaName, boatClassName, startDate, endDate, id, series, persistent, scoringScheme, |
|
| 1256 | + defaultCourseAreaId, useStartTimeInference, rankingMetricConstructor); |
|
| 1257 | + Regatta regatta = regattaWithCreatedFlag.getA(); |
|
| 1258 | + if (regattaWithCreatedFlag.getB()) { |
|
| 1259 | + onRegattaLikeAdded(regatta); |
|
| 1260 | + replicateSpecificRegattaWithoutRaceColumns(regatta); |
|
| 1261 | + } |
|
| 1262 | + return regatta; |
|
| 1263 | + } |
|
| 1264 | + |
|
| 1265 | + @Override |
|
| 1266 | + public void addRegattaWithoutReplication(Regatta regatta) { |
|
| 1267 | + UUID defaultCourseAreaId = null; |
|
| 1268 | + if (regatta.getDefaultCourseArea() != null) { |
|
| 1269 | + defaultCourseAreaId = regatta.getDefaultCourseArea().getId(); |
|
| 1270 | + } |
|
| 1271 | + boolean wasAdded = addAndConnectRegatta(regatta.isPersistent(), defaultCourseAreaId, regatta); |
|
| 1272 | + if (!wasAdded) { |
|
| 1273 | + logger.info("Regatta with name " + regatta.getName() + " already existed, so it hasn't been added."); |
|
| 1274 | + } |
|
| 1275 | + } |
|
| 1276 | + |
|
| 1277 | + private RaceLogStore getRaceLogStore() { |
|
| 1278 | + return MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory); |
|
| 1279 | + } |
|
| 1280 | + |
|
| 1281 | + private RegattaLogStore getRegattaLogStore() { |
|
| 1282 | + return MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory); |
|
| 1283 | + } |
|
| 1284 | + |
|
| 1285 | + @Override |
|
| 1286 | + public com.sap.sse.common.Util.Pair<Regatta, Boolean> getOrCreateRegattaWithoutReplication(String fullRegattaName, |
|
| 1287 | + String boatClassName, TimePoint startDate, TimePoint endDate, Serializable id, |
|
| 1288 | + Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme, |
|
| 1289 | + Serializable defaultCourseAreaId, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) { |
|
| 1290 | + CourseArea courseArea = getCourseArea(defaultCourseAreaId); |
|
| 1291 | + Regatta regatta = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), fullRegattaName, |
|
| 1292 | + getBaseDomainFactory().getOrCreateBoatClass(boatClassName), startDate, endDate, series, persistent, |
|
| 1293 | + scoringScheme, id, courseArea, useStartTimeInference, rankingMetricConstructor); |
|
| 1294 | + boolean wasCreated = addAndConnectRegatta(persistent, defaultCourseAreaId, regatta); |
|
| 1295 | + if (wasCreated) { |
|
| 1296 | + logger.info("Created regatta " + regatta.getName() + " (" + hashCode() + ") on " + this); |
|
| 1297 | + } |
|
| 1298 | + return new com.sap.sse.common.Util.Pair<Regatta, Boolean>(regatta, wasCreated); |
|
| 1299 | + } |
|
| 1300 | + |
|
| 1301 | + private boolean addAndConnectRegatta(boolean persistent, Serializable defaultCourseAreaId, Regatta regatta) { |
|
| 1302 | + boolean wasCreated = false; |
|
| 1303 | + // try a quick read protected by the concurrent hash map implementation |
|
| 1304 | + if (!regattasByName.containsKey(regatta.getName())) { |
|
| 1305 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 1306 | + try { |
|
| 1307 | + // check again, now that we hold the exclusive write lock |
|
| 1308 | + if (!regattasByName.containsKey(regatta.getName())) { |
|
| 1309 | + wasCreated = true; |
|
| 1310 | + logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode() |
|
| 1311 | + + ") into regattasByName of " + this); |
|
| 1312 | + regattasByName.put(regatta.getName(), regatta); |
|
| 1313 | + regatta.addRegattaListener(this); |
|
| 1314 | + regatta.addRaceColumnListener(raceLogReplicator); |
|
| 1315 | + regatta.addRaceColumnListener(raceLogScoringReplicator); |
|
| 1316 | + } |
|
| 1317 | + } finally { |
|
| 1318 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 1319 | + } |
|
| 1320 | + } |
|
| 1321 | + if (persistent) { |
|
| 1322 | + updateStoredRegatta(regatta); |
|
| 1323 | + } |
|
| 1324 | + for (Event event : getAllEvents()) { |
|
| 1325 | + for (CourseArea eventCourseArea : event.getVenue().getCourseAreas()) { |
|
| 1326 | + if (defaultCourseAreaId != null && eventCourseArea.getId().equals(defaultCourseAreaId)) { |
|
| 1327 | + event.addRegatta(regatta); |
|
| 1328 | + } |
|
| 1329 | + } |
|
| 1330 | + } |
|
| 1331 | + return wasCreated; |
|
| 1332 | + } |
|
| 1333 | + |
|
| 1334 | + @Override |
|
| 1335 | + public void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition) { |
|
| 1336 | + Regatta regatta = getRegatta(addToRegatta); |
|
| 1337 | + regatta.addRace(raceDefinition); // will trigger the raceAdded operation because this service is listening on |
|
| 1338 | + // all its regattas |
|
| 1339 | + } |
|
| 1340 | + |
|
| 1341 | + /** |
|
| 1342 | + * If the <code>regatta</code> {@link Regatta#isPersistent() is a persistent one}, the association of the race with |
|
| 1343 | + * the regatta is remembered persistently so that {@link #getRememberedRegattaForRace(Serializable)} will provide |
|
| 1344 | + * it. |
|
| 1345 | + */ |
|
| 1346 | + @Override |
|
| 1347 | + public void raceAdded(Regatta regatta, RaceDefinition raceDefinition) { |
|
| 1348 | + if (regatta.isPersistent()) { |
|
| 1349 | + setRegattaForRace(regatta, raceDefinition); |
|
| 1350 | + } |
|
| 1351 | + final CourseChangeReplicator listener = new CourseChangeReplicator(this, regatta, raceDefinition); |
|
| 1352 | + courseListeners.put(raceDefinition, listener); |
|
| 1353 | + raceDefinition.getCourse().addCourseListener(listener); |
|
| 1354 | + replicate(new AddRaceDefinition(regatta.getRegattaIdentifier(), raceDefinition)); |
|
| 1355 | + } |
|
| 1356 | + |
|
| 1357 | + @Override |
|
| 1358 | + public void raceRemoved(Regatta regatta, RaceDefinition raceDefinition) { |
|
| 1359 | + raceDefinition.getCourse().removeCourseListener(courseListeners.remove(raceDefinition)); |
|
| 1360 | + } |
|
| 1361 | + |
|
| 1362 | + private NamedReentrantReadWriteLock lockRaceTrackersById(Object trackerId) { |
|
| 1363 | + NamedReentrantReadWriteLock lock; |
|
| 1364 | + synchronized (raceTrackersByIDLocks) { |
|
| 1365 | + lock = raceTrackersByIDLocks.get(trackerId); |
|
| 1366 | + if (lock == null) { |
|
| 1367 | + lock = new NamedReentrantReadWriteLock("raceTrackersByIDLock for " + trackerId, /* fair */false); |
|
| 1368 | + raceTrackersByIDLocks.put(trackerId, lock); |
|
| 1369 | + } |
|
| 1370 | + } |
|
| 1371 | + LockUtil.lockForWrite(lock); |
|
| 1372 | + return lock; |
|
| 1373 | + } |
|
| 1374 | + |
|
| 1375 | + /** |
|
| 1376 | + * @param lock |
|
| 1377 | + * need to pass the lock obtained from {@link #lockRaceTrackersById(Object)} because a competing thread |
|
| 1378 | + * may already have removed the lock from the {@link #raceTrackersByIDLocks} map |
|
| 1379 | + */ |
|
| 1380 | + private void unlockRaceTrackersById(Object trackerId, NamedReentrantReadWriteLock lock) { |
|
| 1381 | + LockUtil.unlockAfterWrite(lock); |
|
| 1382 | + synchronized (raceTrackersByIDLocks) { |
|
| 1383 | + raceTrackersByIDLocks.remove(trackerId); |
|
| 1384 | + } |
|
| 1385 | + } |
|
| 1386 | + |
|
| 1387 | + @Override |
|
| 1388 | + public RaceHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params, |
|
| 1389 | + long timeoutInMilliseconds) throws Exception { |
|
| 1390 | + final Object trackerID = params.getTrackerID(); |
|
| 1391 | + NamedReentrantReadWriteLock raceTrackersByIdLock = lockRaceTrackersById(trackerID); |
|
| 1392 | + try { |
|
| 1393 | + RaceTracker tracker = raceTrackersByID.get(trackerID); |
|
| 1394 | + if (tracker == null) { |
|
| 1395 | + Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo); |
|
| 1396 | + if (regatta == null) { |
|
| 1397 | + // create tracker and use an existing or create a default regatta |
|
| 1398 | + tracker = params.createRaceTracker(this, windStore, gpsFixStore, /* raceLogResolver */ this); |
|
| 1399 | + } else { |
|
| 1400 | + // use the regatta selected by the RaceIdentifier regattaToAddTo |
|
| 1401 | + tracker = params.createRaceTracker(regatta, this, windStore, gpsFixStore, /* raceLogResolver */ this); |
|
| 1402 | + assert tracker.getRegatta() == regatta; |
|
| 1403 | + } |
|
| 1404 | + LockUtil.lockForWrite(raceTrackersByRegattaLock); |
|
| 1405 | + try { |
|
| 1406 | + raceTrackersByID.put(trackerID, tracker); |
|
| 1407 | + Set<RaceTracker> trackers = raceTrackersByRegatta.get(tracker.getRegatta()); |
|
| 1408 | + if (trackers == null) { |
|
| 1409 | + trackers = Collections.newSetFromMap(new ConcurrentHashMap<RaceTracker, Boolean>()); |
|
| 1410 | + raceTrackersByRegatta.put(tracker.getRegatta(), trackers); |
|
| 1411 | + } |
|
| 1412 | + trackers.add(tracker); |
|
| 1413 | + } finally { |
|
| 1414 | + LockUtil.unlockAfterWrite(raceTrackersByRegattaLock); |
|
| 1415 | + } |
|
| 1416 | + // TODO we assume here that the regatta name is unique which necessitates adding the boat class name to |
|
| 1417 | + // it in RegattaImpl constructor |
|
| 1418 | + String regattaName = tracker.getRegatta().getName(); |
|
| 1419 | + Regatta regattaWithName = regattasByName.get(regattaName); |
|
| 1420 | + // TODO we assume here that the regatta name is unique which necessitates adding the boat class name to |
|
| 1421 | + // it in RegattaImpl constructor |
|
| 1422 | + if (regattaWithName != null) { |
|
| 1423 | + if (regattaWithName != tracker.getRegatta()) { |
|
| 1424 | + if (Util.isEmpty(regattaWithName.getAllRaces())) { |
|
| 1425 | + // probably, tracker removed the last races from the old regatta and created a new one |
|
| 1426 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 1427 | + try { |
|
| 1428 | + regattasByName.remove(regattaName); |
|
| 1429 | + cacheAndReplicateDefaultRegatta(tracker.getRegatta()); |
|
| 1430 | + } finally { |
|
| 1431 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 1432 | + } |
|
| 1433 | + } else { |
|
| 1434 | + throw new RuntimeException("Internal error. Two regatta objects with equal name " |
|
| 1435 | + + regattaName); |
|
| 1436 | + } |
|
| 1437 | + } |
|
| 1438 | + } else { |
|
| 1439 | + cacheAndReplicateDefaultRegatta(tracker.getRegatta()); |
|
| 1440 | + } |
|
| 1441 | + } else { |
|
| 1442 | + logger.warning("Race tracker with ID "+trackerID+" already found; not tracking twice to avoid race duplication"); |
|
| 1443 | + WindStore existingTrackersWindStore = tracker.getWindStore(); |
|
| 1444 | + if (!existingTrackersWindStore.equals(windStore)) { |
|
| 1445 | + logger.warning("Wind store mismatch. Requested wind store: " + windStore |
|
| 1446 | + + ". Wind store in use by existing tracker: " + existingTrackersWindStore); |
|
| 1447 | + } |
|
| 1448 | + GPSFixStore existingTrackersGPSFixStore = tracker.getGPSFixStore(); |
|
| 1449 | + if (!existingTrackersGPSFixStore.equals(gpsFixStore)) { |
|
| 1450 | + logger.warning("GPSFix store mismatch. Requested GPSFix store: " + gpsFixStore |
|
| 1451 | + + ". GPSFix store in use by existing tracker: " + existingTrackersGPSFixStore); |
|
| 1452 | + } |
|
| 1453 | + } |
|
| 1454 | + if (timeoutInMilliseconds != -1) { |
|
| 1455 | + scheduleAbortTrackerAfterInitialTimeout(tracker, timeoutInMilliseconds); |
|
| 1456 | + } |
|
| 1457 | + return tracker.getRacesHandle(); |
|
| 1458 | + } finally { |
|
| 1459 | + unlockRaceTrackersById(trackerID, raceTrackersByIdLock); |
|
| 1460 | + } |
|
| 1461 | + } |
|
| 1462 | + |
|
| 1463 | + /** |
|
| 1464 | + * The regatta and all its contained {@link Regatta#getAllRaces() races} are replicated to all replicas. |
|
| 1465 | + * |
|
| 1466 | + * @param regatta |
|
| 1467 | + * the series of this regatta must not have any {@link Series#getRaceColumns() race columns associated |
|
| 1468 | + * (yet)}. |
|
| 1469 | + */ |
|
| 1470 | + private void replicateSpecificRegattaWithoutRaceColumns(Regatta regatta) { |
|
| 1471 | + Serializable courseAreaId = null; |
|
| 1472 | + if (regatta.getDefaultCourseArea() != null) { |
|
| 1473 | + courseAreaId = regatta.getDefaultCourseArea().getId(); |
|
| 1474 | + } |
|
| 1475 | + replicate(new AddSpecificRegatta(regatta.getName(), regatta.getBoatClass() == null ? null : regatta |
|
| 1476 | + .getBoatClass().getName(), regatta.getStartDate(), regatta.getEndDate(), regatta.getId(), |
|
| 1477 | + getSeriesWithoutRaceColumnsConstructionParametersAsMap(regatta), regatta.isPersistent(), |
|
| 1478 | + regatta.getScoringScheme(), courseAreaId, regatta.useStartTimeInference(), regatta.getRankingMetricType())); |
|
| 1479 | + RegattaIdentifier regattaIdentifier = regatta.getRegattaIdentifier(); |
|
| 1480 | + for (RaceDefinition race : regatta.getAllRaces()) { |
|
| 1481 | + replicate(new AddRaceDefinition(regattaIdentifier, race)); |
|
| 1482 | + } |
|
| 1483 | + } |
|
| 1484 | + |
|
| 1485 | + private RegattaCreationParametersDTO getSeriesWithoutRaceColumnsConstructionParametersAsMap(Regatta regatta) { |
|
| 1486 | + LinkedHashMap<String, SeriesCreationParametersDTO> result = new LinkedHashMap<String, SeriesCreationParametersDTO>(); |
|
| 1487 | + for (Series s : regatta.getSeries()) { |
|
| 1488 | + assert Util.isEmpty(s.getRaceColumns()); |
|
| 1489 | + List<FleetDTO> fleetNamesAndOrdering = new ArrayList<FleetDTO>(); |
|
| 1490 | + for (Fleet f : s.getFleets()) { |
|
| 1491 | + fleetNamesAndOrdering.add(getBaseDomainFactory().convertToFleetDTO(f)); |
|
| 1492 | + } |
|
| 1493 | + result.put( |
|
| 1494 | + s.getName(), |
|
| 1495 | + new SeriesCreationParametersDTO(fleetNamesAndOrdering, s.isMedal(), s.isStartsWithZeroScore(), s |
|
| 1496 | + .isFirstColumnIsNonDiscardableCarryForward(), s.getResultDiscardingRule() == null ? null |
|
| 1497 | + : s.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces(), s |
|
| 1498 | + .hasSplitFleetContiguousScoring())); |
|
| 1499 | + } |
|
| 1500 | + return new RegattaCreationParametersDTO(result); |
|
| 1501 | + } |
|
| 1502 | + |
|
| 1503 | + /** |
|
| 1504 | + * If <code>regatta</code> is not yet in {@link #regattasByName}, it is added, this service is |
|
| 1505 | + * {@link Regatta#addRegattaListener(RegattaListener) added} as regatta listener, and the regatta and all its |
|
| 1506 | + * contained {@link Regatta#getAllRaces() races} are replicated to all replica. |
|
| 1507 | + */ |
|
| 1508 | + private void cacheAndReplicateDefaultRegatta(Regatta regatta) { |
|
| 1509 | + // try a quick read first, protected by regattasByName being a concurrent hash set |
|
| 1510 | + if (!regattasByName.containsKey(regatta.getName())) { |
|
| 1511 | + // now we need to obtain exclusive write access; in between, some other thread may have added a regatta by |
|
| 1512 | + // that |
|
| 1513 | + // name, so we need to check again: |
|
| 1514 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 1515 | + try { |
|
| 1516 | + if (!regattasByName.containsKey(regatta.getName())) { |
|
| 1517 | + logger.info("putting regatta " + regatta.getName() + " (" + regatta.hashCode() |
|
| 1518 | + + ") into regattasByName of " + this); |
|
| 1519 | + regattasByName.put(regatta.getName(), regatta); |
|
| 1520 | + regatta.addRegattaListener(this); |
|
| 1521 | + regatta.addRaceColumnListener(raceLogReplicator); |
|
| 1522 | + regatta.addRaceColumnListener(raceLogScoringReplicator); |
|
| 1523 | + |
|
| 1524 | + replicate(new AddDefaultRegatta(regatta.getName(), regatta.getBoatClass() == null ? null : regatta |
|
| 1525 | + .getBoatClass().getName(), regatta.getStartDate(), regatta.getEndDate(), regatta.getId())); |
|
| 1526 | + RegattaIdentifier regattaIdentifier = regatta.getRegattaIdentifier(); |
|
| 1527 | + for (RaceDefinition race : regatta.getAllRaces()) { |
|
| 1528 | + replicate(new AddRaceDefinition(regattaIdentifier, race)); |
|
| 1529 | + } |
|
| 1530 | + } |
|
| 1531 | + } finally { |
|
| 1532 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 1533 | + } |
|
| 1534 | + } |
|
| 1535 | + } |
|
| 1536 | + |
|
| 1537 | + @Override |
|
| 1538 | + public DynamicTrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore, |
|
| 1539 | + GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, |
|
| 1540 | + long millisecondsOverWhichToAverageSpeed, boolean useMarkPassingCalculator) { |
|
| 1541 | + DynamicTrackedRegatta trackedRegatta = getOrCreateTrackedRegatta(getRegatta(raceIdentifier)); |
|
| 1542 | + RaceDefinition race = getRace(raceIdentifier); |
|
| 1543 | + return trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), windStore, gpsFixStore, |
|
| 1544 | + delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, |
|
| 1545 | + /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this); |
|
| 1546 | + } |
|
| 1547 | + |
|
| 1548 | + private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking( |
|
| 1549 | + DynamicTrackedRegatta trackedRegatta) { |
|
| 1550 | + if (regattasObservedForDefaultLeaderboard.add(trackedRegatta)) { |
|
| 1551 | + trackedRegatta.addRaceListener(new RaceAdditionListener()); |
|
| 1552 | + } |
|
| 1553 | + } |
|
| 1554 | + |
|
| 1555 | + private void stopObservingRegattaForRedaultLeaderboardAndAutoLeaderboardLinking(DynamicTrackedRegatta trackedRegatta) { |
|
| 1556 | + regattasObservedForDefaultLeaderboard.remove(trackedRegatta); |
|
| 1557 | + } |
|
| 1558 | + |
|
| 1559 | + /** |
|
| 1560 | + * A listener class used to ensure that when a tracked race is added to any {@link TrackedRegatta} managed by this |
|
| 1561 | + * service, the service adds the tracked race to the default leaderboard and links it to the leaderboard columns |
|
| 1562 | + * that were previously connected to it. Additionally, a {@link RaceChangeListener} is added to the |
|
| 1563 | + * {@link TrackedRace} which is responsible for triggering the replication of all relevant changes to the tracked |
|
| 1564 | + * race. When a tracked race is removed, the {@link TrackedRaceReplicator} that was added as listener to that |
|
| 1565 | + * tracked race is removed again. |
|
| 1566 | + * |
|
| 1567 | + * A {@link PolarFixCacheUpdater} is added to every race so that polar fixes are aggregated when new GPS fixes |
|
| 1568 | + * arrive. |
|
| 1569 | + * |
|
| 1570 | + * @author Axel Uhl (d043530) |
|
| 1571 | + * |
|
| 1572 | + */ |
|
| 1573 | + private class RaceAdditionListener implements RaceListener, Serializable { |
|
| 1574 | + private static final long serialVersionUID = 1036955460477000265L; |
|
| 1575 | + |
|
| 1576 | + private final Map<TrackedRace, TrackedRaceReplicator> trackedRaceReplicators; |
|
| 1577 | + |
|
| 1578 | + private final Map<TrackedRace, PolarFixCacheUpdater> polarFixCacheUpdaters; |
|
| 1579 | + |
|
| 1580 | + public RaceAdditionListener() { |
|
| 1581 | + this.trackedRaceReplicators = new HashMap<TrackedRace, TrackedRaceReplicator>(); |
|
| 1582 | + this.polarFixCacheUpdaters = new HashMap<TrackedRace, PolarFixCacheUpdater>(); |
|
| 1583 | + } |
|
| 1584 | + |
|
| 1585 | + @Override |
|
| 1586 | + public void raceRemoved(TrackedRace trackedRace) { |
|
| 1587 | + TrackedRaceReplicator trackedRaceReplicator = trackedRaceReplicators.remove(trackedRace); |
|
| 1588 | + if (trackedRaceReplicator != null) { |
|
| 1589 | + trackedRace.removeListener(trackedRaceReplicator); |
|
| 1590 | + } |
|
| 1591 | + PolarFixCacheUpdater polarFixCacheUpdater = polarFixCacheUpdaters.remove(trackedRace); |
|
| 1592 | + if (polarFixCacheUpdater != null) { |
|
| 1593 | + trackedRace.removeListener(polarFixCacheUpdater); |
|
| 1594 | + } |
|
| 1595 | + } |
|
| 1596 | + |
|
| 1597 | + @Override |
|
| 1598 | + public void raceAdded(TrackedRace trackedRace) { |
|
| 1599 | + // replicate the addition of the tracked race: |
|
| 1600 | + CreateTrackedRace op = new CreateTrackedRace(trackedRace.getRaceIdentifier(), trackedRace.getWindStore(), |
|
| 1601 | + trackedRace.getGPSFixStore(), trackedRace.getDelayToLiveInMillis(), |
|
| 1602 | + trackedRace.getMillisecondsOverWhichToAverageWind(), |
|
| 1603 | + trackedRace.getMillisecondsOverWhichToAverageSpeed()); |
|
| 1604 | + replicate(op); |
|
| 1605 | + linkRaceToConfiguredLeaderboardColumns(trackedRace); |
|
| 1606 | + TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace); |
|
| 1607 | + trackedRaceReplicators.put(trackedRace, trackedRaceReplicator); |
|
| 1608 | + trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */true, true); |
|
| 1609 | + |
|
| 1610 | + PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace); |
|
| 1611 | + polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater); |
|
| 1612 | + trackedRace.addListener(polarFixCacheUpdater); |
|
| 1613 | + |
|
| 1614 | + if (polarDataService != null) { |
|
| 1615 | + trackedRace.setPolarDataService(polarDataService); |
|
| 1616 | + } |
|
| 1617 | + } |
|
| 1618 | + } |
|
| 1619 | + |
|
| 1620 | + private class PolarFixCacheUpdater extends AbstractRaceChangeListener { |
|
| 1621 | + |
|
| 1622 | + private final TrackedRace race; |
|
| 1623 | + |
|
| 1624 | + public PolarFixCacheUpdater(TrackedRace race) { |
|
| 1625 | + this.race = race; |
|
| 1626 | + } |
|
| 1627 | + |
|
| 1628 | + @Override |
|
| 1629 | + public void competitorPositionChanged(GPSFixMoving fix, Competitor item) { |
|
| 1630 | + if (polarDataService != null) { |
|
| 1631 | + polarDataService.competitorPositionChanged(fix, item, race); |
|
| 1632 | + } |
|
| 1633 | + } |
|
| 1634 | + |
|
| 1635 | + @Override |
|
| 1636 | + public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) { |
|
| 1637 | + if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING |
|
| 1638 | + && newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) { |
|
| 1639 | + if (polarDataService != null) { |
|
| 1640 | + polarDataService.raceFinishedLoading(race); |
|
| 1641 | + } |
|
| 1642 | + } |
|
| 1643 | + } |
|
| 1644 | + |
|
| 1645 | + } |
|
| 1646 | + |
|
| 1647 | + private class TrackedRaceReplicator implements RaceChangeListener { |
|
| 1648 | + private final TrackedRace trackedRace; |
|
| 1649 | + |
|
| 1650 | + public TrackedRaceReplicator(TrackedRace trackedRace) { |
|
| 1651 | + this.trackedRace = trackedRace; |
|
| 1652 | + } |
|
| 1653 | + |
|
| 1654 | + @Override |
|
| 1655 | + public void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude) { |
|
| 1656 | + replicate(new UpdateWindSourcesToExclude(getRaceIdentifier(), windSourcesToExclude)); |
|
| 1657 | + } |
|
| 1658 | + |
|
| 1659 | + @Override |
|
| 1660 | + public void startOfTrackingChanged(TimePoint startOfTracking) { |
|
| 1661 | + replicate(new UpdateStartOfTracking(getRaceIdentifier(), startOfTracking)); |
|
| 1662 | + } |
|
| 1663 | + |
|
| 1664 | + @Override |
|
| 1665 | + public void endOfTrackingChanged(TimePoint endOfTracking) { |
|
| 1666 | + replicate(new UpdateEndOfTracking(getRaceIdentifier(), endOfTracking)); |
|
| 1667 | + } |
|
| 1668 | + |
|
| 1669 | + @Override |
|
| 1670 | + public void startTimeReceivedChanged(TimePoint startTimeReceived) { |
|
| 1671 | + replicate(new UpdateStartTimeReceived(getRaceIdentifier(), startTimeReceived)); |
|
| 1672 | + } |
|
| 1673 | + |
|
| 1674 | + @Override |
|
| 1675 | + public void startOfRaceChanged(TimePoint oldStartOfRace, TimePoint newStartOfRace) { |
|
| 1676 | + // no action required; the update signaled by this call is implicit; for explicit updates |
|
| 1677 | + // see raceTimesChanged(TimePoint, TimePoint, TimePoint). |
|
| 1678 | + } |
|
| 1679 | + |
|
| 1680 | + @Override |
|
| 1681 | + public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) { |
|
| 1682 | + // no-op; the course change is replicated by the separate CourseChangeReplicator |
|
| 1683 | + } |
|
| 1684 | + |
|
| 1685 | + @Override |
|
| 1686 | + public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) { |
|
| 1687 | + // no-op; the course change is replicated by the separate CourseChangeReplicator |
|
| 1688 | + } |
|
| 1689 | + |
|
| 1690 | + @Override |
|
| 1691 | + public void delayToLiveChanged(long delayToLiveInMillis) { |
|
| 1692 | + replicate(new UpdateRaceDelayToLive(getRaceIdentifier(), delayToLiveInMillis)); |
|
| 1693 | + } |
|
| 1694 | + |
|
| 1695 | + @Override |
|
| 1696 | + public void windDataReceived(Wind wind, WindSource windSource) { |
|
| 1697 | + replicate(new RecordWindFix(getRaceIdentifier(), windSource, wind)); |
|
| 1698 | + } |
|
| 1699 | + |
|
| 1700 | + @Override |
|
| 1701 | + public void windDataRemoved(Wind wind, WindSource windSource) { |
|
| 1702 | + replicate(new RemoveWindFix(getRaceIdentifier(), windSource, wind)); |
|
| 1703 | + } |
|
| 1704 | + |
|
| 1705 | + @Override |
|
| 1706 | + public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) { |
|
| 1707 | + replicate(new UpdateWindAveragingTime(getRaceIdentifier(), newMillisecondsOverWhichToAverage)); |
|
| 1708 | + } |
|
| 1709 | + |
|
| 1710 | + @Override |
|
| 1711 | + public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) { |
|
| 1712 | + replicate(new RecordCompetitorGPSFix(getRaceIdentifier(), competitor, fix)); |
|
| 1713 | + } |
|
| 1714 | + |
|
| 1715 | + @Override |
|
| 1716 | + public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) { |
|
| 1717 | + replicate(new UpdateTrackedRaceStatus(getRaceIdentifier(), newStatus)); |
|
| 1718 | + } |
|
| 1719 | + |
|
| 1720 | + @Override |
|
| 1721 | + public void markPositionChanged(GPSFix fix, Mark mark, boolean firstInTrack) { |
|
| 1722 | + final RecordMarkGPSFix operation; |
|
| 1723 | + if (firstInTrack) { |
|
| 1724 | + operation = new RecordMarkGPSFixForNewMarkTrack(getRaceIdentifier(), mark, fix); |
|
| 1725 | + } else { |
|
| 1726 | + operation = new RecordMarkGPSFixForExistingTrack(getRaceIdentifier(), mark, fix); |
|
| 1727 | + } |
|
| 1728 | + replicate(operation); |
|
| 1729 | + } |
|
| 1730 | + |
|
| 1731 | + @Override |
|
| 1732 | + public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings, |
|
| 1733 | + Iterable<MarkPassing> markPassings) { |
|
| 1734 | + replicate(new UpdateMarkPassings(getRaceIdentifier(), competitor, markPassings)); |
|
| 1735 | + } |
|
| 1736 | + |
|
| 1737 | + @Override |
|
| 1738 | + public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) { |
|
| 1739 | + replicate(new UpdateWindAveragingTime(getRaceIdentifier(), newMillisecondsOverWhichToAverage)); |
|
| 1740 | + } |
|
| 1741 | + |
|
| 1742 | + private RegattaAndRaceIdentifier getRaceIdentifier() { |
|
| 1743 | + return trackedRace.getRaceIdentifier(); |
|
| 1744 | + } |
|
| 1745 | + |
|
| 1746 | + } |
|
| 1747 | + |
|
| 1748 | + /** |
|
| 1749 | + * Based on the <code>trackedRace</code>'s {@link TrackedRace#getRaceIdentifier() race identifier}, the tracked race |
|
| 1750 | + * is (re-)associated to all {@link RaceColumn race columns} that currently have no |
|
| 1751 | + * {@link RaceColumn#getTrackedRace(Fleet) tracked race assigned} and whose |
|
| 1752 | + * {@link RaceColumn#getRaceIdentifier(Fleet) race identifier} equals that of <code>trackedRace</code>. |
|
| 1753 | + */ |
|
| 1754 | + private void linkRaceToConfiguredLeaderboardColumns(TrackedRace trackedRace) { |
|
| 1755 | + boolean leaderboardHasChanged = false; |
|
| 1756 | + RegattaAndRaceIdentifier trackedRaceIdentifier = trackedRace.getRaceIdentifier(); |
|
| 1757 | + for (Leaderboard leaderboard : getLeaderboards().values()) { |
|
| 1758 | + for (RaceColumn column : leaderboard.getRaceColumns()) { |
|
| 1759 | + for (Fleet fleet : column.getFleets()) { |
|
| 1760 | + if (trackedRaceIdentifier.equals(column.getRaceIdentifier(fleet)) |
|
| 1761 | + && column.getTrackedRace(fleet) == null) { |
|
| 1762 | + column.setTrackedRace(fleet, trackedRace); |
|
| 1763 | + leaderboardHasChanged = true; |
|
| 1764 | + replicate(new ConnectTrackedRaceToLeaderboardColumn(leaderboard.getName(), column.getName(), |
|
| 1765 | + fleet.getName(), trackedRaceIdentifier)); |
|
| 1766 | + } |
|
| 1767 | + } |
|
| 1768 | + } |
|
| 1769 | + if (leaderboardHasChanged) { |
|
| 1770 | + // Update the corresponding groups, to keep them in sync |
|
| 1771 | + syncGroupsAfterLeaderboardChange(leaderboard, /* doDatabaseUpdate */false); |
|
| 1772 | + } |
|
| 1773 | + } |
|
| 1774 | + } |
|
| 1775 | + |
|
| 1776 | + @Override |
|
| 1777 | + public void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException { |
|
| 1778 | + final Set<RaceTracker> trackersForRegatta = raceTrackersByRegatta.get(regatta); |
|
| 1779 | + if (trackersForRegatta != null) { |
|
| 1780 | + for (RaceTracker raceTracker : trackersForRegatta) { |
|
| 1781 | + final Set<RaceDefinition> races = raceTracker.getRaces(); |
|
| 1782 | + if (races != null) { |
|
| 1783 | + for (RaceDefinition race : races) { |
|
| 1784 | + stopTrackingWind(regatta, race); |
|
| 1785 | + } |
|
| 1786 | + } |
|
| 1787 | + raceTracker.stop(/* preemptive */false); |
|
| 1788 | + final Object trackerId = raceTracker.getID(); |
|
| 1789 | + final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId); |
|
| 1790 | + try { |
|
| 1791 | + raceTrackersByID.remove(trackerId); |
|
| 1792 | + } finally { |
|
| 1793 | + unlockRaceTrackersById(trackerId, lock); |
|
| 1794 | + } |
|
| 1795 | + raceTrackersByID.remove(trackerId); |
|
| 1796 | + } |
|
| 1797 | + LockUtil.lockForWrite(raceTrackersByRegattaLock); |
|
| 1798 | + try { |
|
| 1799 | + raceTrackersByRegatta.remove(regatta); |
|
| 1800 | + } finally { |
|
| 1801 | + LockUtil.unlockAfterWrite(raceTrackersByRegattaLock); |
|
| 1802 | + } |
|
| 1803 | + } |
|
| 1804 | + } |
|
| 1805 | + |
|
| 1806 | + @Override |
|
| 1807 | + public void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException { |
|
| 1808 | + stopTracking(regatta); |
|
| 1809 | + if (regatta != null) { |
|
| 1810 | + if (regatta.getName() != null) { |
|
| 1811 | + logger.info("Removing regatta " + regatta.getName() + " (" + regatta.hashCode() + ") from " + this); |
|
| 1812 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 1813 | + try { |
|
| 1814 | + regattasByName.remove(regatta.getName()); |
|
| 1815 | + } finally { |
|
| 1816 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 1817 | + } |
|
| 1818 | + LockUtil.lockForWrite(regattaTrackingCacheLock); |
|
| 1819 | + try { |
|
| 1820 | + regattaTrackingCache.remove(regatta); |
|
| 1821 | + } finally { |
|
| 1822 | + LockUtil.unlockAfterWrite(regattaTrackingCacheLock); |
|
| 1823 | + } |
|
| 1824 | + regatta.removeRegattaListener(this); |
|
| 1825 | + regatta.removeRaceColumnListener(raceLogReplicator); |
|
| 1826 | + regatta.removeRaceColumnListener(raceLogScoringReplicator); |
|
| 1827 | + } |
|
| 1828 | + for (RaceDefinition race : regatta.getAllRaces()) { |
|
| 1829 | + stopTrackingWind(regatta, race); |
|
| 1830 | + } |
|
| 1831 | + } |
|
| 1832 | + } |
|
| 1833 | + |
|
| 1834 | + /** |
|
| 1835 | + * The tracker will initially try to connect to the tracking infrastructure to obtain basic race master data. If |
|
| 1836 | + * this fails after some timeout, to avoid garbage and lingering threads, the task scheduled by this method will |
|
| 1837 | + * check after the timeout expires if race master data was successfully received. If so, the tracker continues |
|
| 1838 | + * normally. Otherwise, the tracker is shut down orderly by calling {@link RaceTracker#stop(boolean) stopping}. |
|
| 1839 | + * |
|
| 1840 | + * @return the scheduled task, in case the caller wants to {@link ScheduledFuture#cancel(boolean) cancel} it, e.g., |
|
| 1841 | + * when the tracker is stopped or has successfully received the race |
|
| 1842 | + */ |
|
| 1843 | + private ScheduledFuture<?> scheduleAbortTrackerAfterInitialTimeout(final RaceTracker tracker, |
|
| 1844 | + final long timeoutInMilliseconds) { |
|
| 1845 | + ScheduledFuture<?> task = getScheduler().schedule(new Runnable() { |
|
| 1846 | + @Override |
|
| 1847 | + public void run() { |
|
| 1848 | + if (tracker.getRaces() == null || tracker.getRaces().isEmpty()) { |
|
| 1849 | + try { |
|
| 1850 | + Regatta regatta = tracker.getRegatta(); |
|
| 1851 | + logger.log(Level.SEVERE, "RaceDefinition for a race in regatta " + regatta.getName() |
|
| 1852 | + + " not obtained within " + timeoutInMilliseconds |
|
| 1853 | + + "ms. Aborting tracker for this race."); |
|
| 1854 | + Set<RaceTracker> trackersForRegatta = raceTrackersByRegatta.get(regatta); |
|
| 1855 | + if (trackersForRegatta != null) { |
|
| 1856 | + trackersForRegatta.remove(tracker); |
|
| 1857 | + } |
|
| 1858 | + tracker.stop(/* preemptive */true); |
|
| 1859 | + final Object trackerId = tracker.getID(); |
|
| 1860 | + final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId); |
|
| 1861 | + try { |
|
| 1862 | + raceTrackersByID.remove(trackerId); |
|
| 1863 | + } finally { |
|
| 1864 | + unlockRaceTrackersById(trackerId, lock); |
|
| 1865 | + } |
|
| 1866 | + if (trackersForRegatta == null || trackersForRegatta.isEmpty()) { |
|
| 1867 | + stopTracking(regatta); |
|
| 1868 | + } |
|
| 1869 | + } catch (Exception e) { |
|
| 1870 | + logger.log(Level.SEVERE, "scheduleAbortTrackerAfterInitialTimeout", e); |
|
| 1871 | + e.printStackTrace(); |
|
| 1872 | + } |
|
| 1873 | + } |
|
| 1874 | + } |
|
| 1875 | + }, /* delay */timeoutInMilliseconds, /* unit */TimeUnit.MILLISECONDS); |
|
| 1876 | + return task; |
|
| 1877 | + } |
|
| 1878 | + |
|
| 1879 | + @Override |
|
| 1880 | + public void stopTracking(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException, |
|
| 1881 | + InterruptedException { |
|
| 1882 | + logger.info("Stopping tracking for " + race + "..."); |
|
| 1883 | + final Set<RaceTracker> trackerSet = raceTrackersByRegatta.get(regatta); |
|
| 1884 | + if (trackerSet != null) { |
|
| 1885 | + Iterator<RaceTracker> trackerIter = trackerSet.iterator(); |
|
| 1886 | + while (trackerIter.hasNext()) { |
|
| 1887 | + RaceTracker raceTracker = trackerIter.next(); |
|
| 1888 | + if (raceTracker.getRaces() != null && raceTracker.getRaces().contains(race)) { |
|
| 1889 | + logger.info("Found tracker to stop for races " + raceTracker.getRaces()); |
|
| 1890 | + raceTracker.stop(/* preemptive */false); |
|
| 1891 | + trackerIter.remove(); |
|
| 1892 | + final Object trackerId = raceTracker.getID(); |
|
| 1893 | + final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId); |
|
| 1894 | + try { |
|
| 1895 | + raceTrackersByID.remove(trackerId); |
|
| 1896 | + } finally { |
|
| 1897 | + unlockRaceTrackersById(trackerId, lock); |
|
| 1898 | + } |
|
| 1899 | + } |
|
| 1900 | + } |
|
| 1901 | + } else { |
|
| 1902 | + logger.warning("Didn't find any trackers for regatta " + regatta); |
|
| 1903 | + } |
|
| 1904 | + stopTrackingWind(regatta, race); |
|
| 1905 | + // if the last tracked race was removed, confirm that tracking for the entire regatta has stopped |
|
| 1906 | + if (trackerSet == null || trackerSet.isEmpty()) { |
|
| 1907 | + stopTracking(regatta); |
|
| 1908 | + } |
|
| 1909 | + } |
|
| 1910 | + |
|
| 1911 | + @Override |
|
| 1912 | + public void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException { |
|
| 1913 | + Set<RegattaLeaderboard> leaderboardsToRemove = new HashSet<>(); |
|
| 1914 | + for (Leaderboard leaderboard : getLeaderboards().values()) { |
|
| 1915 | + if (leaderboard instanceof RegattaLeaderboard) { |
|
| 1916 | + RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; |
|
| 1917 | + if (regattaLeaderboard.getRegatta() == regatta) { |
|
| 1918 | + leaderboardsToRemove.add(regattaLeaderboard); |
|
| 1919 | + } |
|
| 1920 | + } |
|
| 1921 | + } |
|
| 1922 | + for (RegattaLeaderboard regattaLeaderboardToRemove : leaderboardsToRemove) { |
|
| 1923 | + removeLeaderboard(regattaLeaderboardToRemove.getName()); |
|
| 1924 | + } |
|
| 1925 | + // avoid ConcurrentModificationException by copying the races to remove: |
|
| 1926 | + Set<RaceDefinition> racesToRemove = new HashSet<>(); |
|
| 1927 | + Util.addAll(regatta.getAllRaces(), racesToRemove); |
|
| 1928 | + for (RaceDefinition race : racesToRemove) { |
|
| 1929 | + removeRace(regatta, race); |
|
| 1930 | + mongoObjectFactory.removeRegattaForRaceID(race.getName(), regatta); |
|
| 1931 | + persistentRegattasForRaceIDs.remove(race.getId().toString()); |
|
| 1932 | + } |
|
| 1933 | + if (regatta.isPersistent()) { |
|
| 1934 | + mongoObjectFactory.removeRegatta(regatta); |
|
| 1935 | + } |
|
| 1936 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 1937 | + try { |
|
| 1938 | + regattasByName.remove(regatta.getName()); |
|
| 1939 | + } finally { |
|
| 1940 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 1941 | + } |
|
| 1942 | + regatta.removeRegattaListener(this); |
|
| 1943 | + regatta.removeRaceColumnListener(raceLogReplicator); |
|
| 1944 | + regatta.removeRaceColumnListener(raceLogScoringReplicator); |
|
| 1945 | + onRegattaLikeRemoved(regatta); |
|
| 1946 | + } |
|
| 1947 | + |
|
| 1948 | + @Override |
|
| 1949 | + public void removeSeries(Series series) throws MalformedURLException, IOException, InterruptedException { |
|
| 1950 | + Regatta regatta = series.getRegatta(); |
|
| 1951 | + regatta.removeSeries(series); |
|
| 1952 | + if (regatta.isPersistent()) { |
|
| 1953 | + mongoObjectFactory.storeRegatta(regatta); |
|
| 1954 | + } |
|
| 1955 | + } |
|
| 1956 | + |
|
| 1957 | + @Override |
|
| 1958 | + public Regatta updateRegatta(RegattaIdentifier regattaIdentifier, TimePoint startDate, TimePoint endDate, |
|
| 1959 | + Serializable newDefaultCourseAreaId, RegattaConfiguration newRegattaConfiguration, |
|
| 1960 | + Iterable<? extends Series> series, boolean useStartTimeInference) { |
|
| 1961 | + // We're not doing any renaming of the regatta itself, therefore we don't have to sync on the maps. |
|
| 1962 | + Regatta regatta = getRegatta(regattaIdentifier); |
|
| 1963 | + CourseArea newCourseArea = getCourseArea(newDefaultCourseAreaId); |
|
| 1964 | + if (newCourseArea != regatta.getDefaultCourseArea()) { |
|
| 1965 | + regatta.setDefaultCourseArea(newCourseArea); |
|
| 1966 | + } |
|
| 1967 | + regatta.setStartDate(startDate); |
|
| 1968 | + regatta.setEndDate(endDate); |
|
| 1969 | + if (regatta.useStartTimeInference() != useStartTimeInference) { |
|
| 1970 | + regatta.setUseStartTimeInference(useStartTimeInference); |
|
| 1971 | + final DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta); |
|
| 1972 | + if (trackedRegatta != null) { |
|
| 1973 | + trackedRegatta.lockTrackedRacesForRead(); |
|
| 1974 | + try { |
|
| 1975 | + for (DynamicTrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { |
|
| 1976 | + // the start times of the regatta's tracked races now have to be re-evaluated the next time they |
|
| 1977 | + // are queried |
|
| 1978 | + trackedRace.invalidateStartTime(); |
|
| 1979 | + } |
|
| 1980 | + } finally { |
|
| 1981 | + trackedRegatta.unlockTrackedRacesAfterRead(); |
|
| 1982 | + } |
|
| 1983 | + } |
|
| 1984 | + } |
|
| 1985 | + regatta.setRegattaConfiguration(newRegattaConfiguration); |
|
| 1986 | + if (series != null) { |
|
| 1987 | + for (Series seriesObj : series) { |
|
| 1988 | + regatta.addSeries(seriesObj); |
|
| 1989 | + } |
|
| 1990 | + } |
|
| 1991 | + regatta.adjustEventToRegattaAssociation(this); |
|
| 1992 | + if (regatta.isPersistent()) { |
|
| 1993 | + mongoObjectFactory.storeRegatta(regatta); |
|
| 1994 | + } |
|
| 1995 | + return regatta; |
|
| 1996 | + } |
|
| 1997 | + |
|
| 1998 | + @Override |
|
| 1999 | + public void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException, |
|
| 2000 | + InterruptedException { |
|
| 2001 | + logger.info("Removing the race " + race + "..."); |
|
| 2002 | + stopAllTrackersForWhichRaceIsLastReachable(regatta, race); |
|
| 2003 | + stopTrackingWind(regatta, race); |
|
| 2004 | + TrackedRace trackedRace = getExistingTrackedRace(regatta, race); |
|
| 2005 | + if (trackedRace != null) { |
|
| 2006 | + TrackedRegatta trackedRegatta = getTrackedRegatta(regatta); |
|
| 2007 | + final boolean isTrackedRacesEmpty; |
|
| 2008 | + if (trackedRegatta != null) { |
|
| 2009 | + trackedRegatta.lockTrackedRacesForWrite(); |
|
| 2010 | + try { |
|
| 2011 | + trackedRegatta.removeTrackedRace(trackedRace); |
|
| 2012 | + isTrackedRacesEmpty = Util.isEmpty(trackedRegatta.getTrackedRaces()); |
|
| 2013 | + } finally { |
|
| 2014 | + trackedRegatta.unlockTrackedRacesAfterWrite(); |
|
| 2015 | + } |
|
| 2016 | + } else { |
|
| 2017 | + isTrackedRacesEmpty = false; |
|
| 2018 | + } |
|
| 2019 | + if (isTrackedRacesEmpty) { |
|
| 2020 | + removeTrackedRegatta(regatta); |
|
| 2021 | + } |
|
| 2022 | + // remove tracked race from RaceColumns of regatta |
|
| 2023 | + for (Series series : regatta.getSeries()) { |
|
| 2024 | + for (RaceColumnInSeries raceColumn : series.getRaceColumns()) { |
|
| 2025 | + for (Fleet fleet : series.getFleets()) { |
|
| 2026 | + if (raceColumn.getTrackedRace(fleet) == trackedRace) { |
|
| 2027 | + raceColumn.releaseTrackedRace(fleet); |
|
| 2028 | + } |
|
| 2029 | + } |
|
| 2030 | + } |
|
| 2031 | + } |
|
| 2032 | + for (Leaderboard leaderboard : getLeaderboards().values()) { |
|
| 2033 | + if (leaderboard instanceof FlexibleLeaderboard) { // RegattaLeaderboards have implicitly been updated by |
|
| 2034 | + // the code above |
|
| 2035 | + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { |
|
| 2036 | + for (Fleet fleet : raceColumn.getFleets()) { |
|
| 2037 | + if (raceColumn.getTrackedRace(fleet) == trackedRace) { |
|
| 2038 | + raceColumn.releaseTrackedRace(fleet); // but leave the RaceIdentifier on the race column |
|
| 2039 | + // untouched, e.g., for later re-load |
|
| 2040 | + } |
|
| 2041 | + } |
|
| 2042 | + } |
|
| 2043 | + } |
|
| 2044 | + } |
|
| 2045 | + } |
|
| 2046 | + // remove the race from the (default) regatta if the regatta is not persistently stored |
|
| 2047 | + regatta.removeRace(race); |
|
| 2048 | + if (!regatta.isPersistent() && Util.isEmpty(regatta.getAllRaces())) { |
|
| 2049 | + logger.info("Removing regatta " + regatta.getName() + " (" + regatta.hashCode() + ") from service " + this); |
|
| 2050 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 2051 | + try { |
|
| 2052 | + regattasByName.remove(regatta.getName()); |
|
| 2053 | + } finally { |
|
| 2054 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 2055 | + } |
|
| 2056 | + regatta.removeRegattaListener(this); |
|
| 2057 | + regatta.removeRaceColumnListener(raceLogReplicator); |
|
| 2058 | + regatta.removeRaceColumnListener(raceLogScoringReplicator); |
|
| 2059 | + } |
|
| 2060 | + } |
|
| 2061 | + |
|
| 2062 | + /** |
|
| 2063 | + * Doesn't stop any wind trackers |
|
| 2064 | + */ |
|
| 2065 | + private void stopAllTrackersForWhichRaceIsLastReachable(Regatta regatta, RaceDefinition race) |
|
| 2066 | + throws MalformedURLException, IOException, InterruptedException { |
|
| 2067 | + if (raceTrackersByRegatta.containsKey(regatta)) { |
|
| 2068 | + Iterator<RaceTracker> trackerIter = raceTrackersByRegatta.get(regatta).iterator(); |
|
| 2069 | + while (trackerIter.hasNext()) { |
|
| 2070 | + RaceTracker raceTracker = trackerIter.next(); |
|
| 2071 | + if (raceTracker.getRaces() != null && raceTracker.getRaces().contains(race)) { |
|
| 2072 | + boolean foundReachableRace = false; |
|
| 2073 | + for (RaceDefinition raceTrackedByTracker : raceTracker.getRaces()) { |
|
| 2074 | + if (raceTrackedByTracker != race && isReachable(regatta, raceTrackedByTracker)) { |
|
| 2075 | + foundReachableRace = true; |
|
| 2076 | + break; |
|
| 2077 | + } |
|
| 2078 | + } |
|
| 2079 | + if (!foundReachableRace) { |
|
| 2080 | + // firstly stop the tracker |
|
| 2081 | + raceTracker.stop(/* preemptive */true); |
|
| 2082 | + // remove it from the raceTrackers by Regatta |
|
| 2083 | + trackerIter.remove(); |
|
| 2084 | + final Object trackerId = raceTracker.getID(); |
|
| 2085 | + final NamedReentrantReadWriteLock lock = lockRaceTrackersById(trackerId); |
|
| 2086 | + try { |
|
| 2087 | + raceTrackersByID.remove(trackerId); |
|
| 2088 | + } finally { |
|
| 2089 | + unlockRaceTrackersById(trackerId, lock); |
|
| 2090 | + } |
|
| 2091 | + // if the last tracked race was removed, remove the entire regatta |
|
| 2092 | + if (raceTrackersByRegatta.get(regatta).isEmpty()) { |
|
| 2093 | + stopTracking(regatta); |
|
| 2094 | + } |
|
| 2095 | + } |
|
| 2096 | + } |
|
| 2097 | + } |
|
| 2098 | + } |
|
| 2099 | + } |
|
| 2100 | + |
|
| 2101 | + private boolean isReachable(Regatta regatta, RaceDefinition race) { |
|
| 2102 | + return Util.contains(regatta.getAllRaces(), race); |
|
| 2103 | + } |
|
| 2104 | + |
|
| 2105 | + @Override |
|
| 2106 | + public void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws Exception { |
|
| 2107 | + for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) { |
|
| 2108 | + windTrackerFactory.createWindTracker(getOrCreateTrackedRegatta(regatta), race, correctByDeclination); |
|
| 2109 | + } |
|
| 2110 | + } |
|
| 2111 | + |
|
| 2112 | + @Override |
|
| 2113 | + public void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException { |
|
| 2114 | + for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) { |
|
| 2115 | + WindTracker windTracker = windTrackerFactory.getExistingWindTracker(race); |
|
| 2116 | + if (windTracker != null) { |
|
| 2117 | + windTracker.stop(); |
|
| 2118 | + } |
|
| 2119 | + } |
|
| 2120 | + } |
|
| 2121 | + |
|
| 2122 | + @Override |
|
| 2123 | + public Iterable<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces() { |
|
| 2124 | + List<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>> result = new ArrayList<com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>>(); |
|
| 2125 | + for (Regatta regatta : getAllRegattas()) { |
|
| 2126 | + for (RaceDefinition race : regatta.getAllRaces()) { |
|
| 2127 | + for (WindTrackerFactory windTrackerFactory : getWindTrackerFactories()) { |
|
| 2128 | + WindTracker windTracker = windTrackerFactory.getExistingWindTracker(race); |
|
| 2129 | + if (windTracker != null) { |
|
| 2130 | + result.add(new com.sap.sse.common.Util.Triple<Regatta, RaceDefinition, String>(regatta, race, |
|
| 2131 | + windTracker.toString())); |
|
| 2132 | + } |
|
| 2133 | + } |
|
| 2134 | + } |
|
| 2135 | + } |
|
| 2136 | + return result; |
|
| 2137 | + } |
|
| 2138 | + |
|
| 2139 | + @Override |
|
| 2140 | + public DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race) { |
|
| 2141 | + return getOrCreateTrackedRegatta(regatta).getTrackedRace(race); |
|
| 2142 | + } |
|
| 2143 | + |
|
| 2144 | + private DynamicTrackedRace getExistingTrackedRace(Regatta regatta, RaceDefinition race) { |
|
| 2145 | + return getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race); |
|
| 2146 | + } |
|
| 2147 | + |
|
| 2148 | + @Override |
|
| 2149 | + public DynamicTrackedRegatta getOrCreateTrackedRegatta(Regatta regatta) { |
|
| 2150 | + cacheAndReplicateDefaultRegatta(regatta); |
|
| 2151 | + LockUtil.lockForWrite(regattaTrackingCacheLock); |
|
| 2152 | + try { |
|
| 2153 | + DynamicTrackedRegatta result = regattaTrackingCache.get(regatta); |
|
| 2154 | + if (result == null) { |
|
| 2155 | + logger.info("Creating DynamicTrackedRegattaImpl for regatta " + regatta.getName() + " with hashCode " |
|
| 2156 | + + regatta.hashCode()); |
|
| 2157 | + result = new DynamicTrackedRegattaImpl(regatta); |
|
| 2158 | + replicate(new TrackRegatta(regatta.getRegattaIdentifier())); |
|
| 2159 | + regattaTrackingCache.put(regatta, result); |
|
| 2160 | + ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(result); |
|
| 2161 | + } |
|
| 2162 | + return result; |
|
| 2163 | + } finally { |
|
| 2164 | + LockUtil.unlockAfterWrite(regattaTrackingCacheLock); |
|
| 2165 | + } |
|
| 2166 | + } |
|
| 2167 | + |
|
| 2168 | + @Override |
|
| 2169 | + public DynamicTrackedRegatta getTrackedRegatta(com.sap.sailing.domain.base.Regatta regatta) { |
|
| 2170 | + return regattaTrackingCache.get(regatta); |
|
| 2171 | + } |
|
| 2172 | + |
|
| 2173 | + @Override |
|
| 2174 | + public void removeTrackedRegatta(Regatta regatta) { |
|
| 2175 | + logger.info("Removing regatta " + regatta.getName() + " from regattaTrackingCache"); |
|
| 2176 | + final DynamicTrackedRegatta trackedRegatta; |
|
| 2177 | + LockUtil.lockForWrite(regattaTrackingCacheLock); |
|
| 2178 | + try { |
|
| 2179 | + trackedRegatta = regattaTrackingCache.remove(regatta); |
|
| 2180 | + } finally { |
|
| 2181 | + LockUtil.unlockAfterWrite(regattaTrackingCacheLock); |
|
| 2182 | + } |
|
| 2183 | + stopObservingRegattaForRedaultLeaderboardAndAutoLeaderboardLinking(trackedRegatta); |
|
| 2184 | + } |
|
| 2185 | + |
|
| 2186 | + @Override |
|
| 2187 | + public Regatta getRegatta(RegattaName regattaName) { |
|
| 2188 | + return (Regatta) regattasByName.get(regattaName.getRegattaName()); |
|
| 2189 | + } |
|
| 2190 | + |
|
| 2191 | + @Override |
|
| 2192 | + public Regatta getRegatta(RegattaIdentifier regattaIdentifier) { |
|
| 2193 | + return (Regatta) regattaIdentifier.getRegatta(this); |
|
| 2194 | + } |
|
| 2195 | + |
|
| 2196 | + @Override |
|
| 2197 | + public DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier) { |
|
| 2198 | + DynamicTrackedRace result = null; |
|
| 2199 | + Regatta regatta = regattasByName.get(raceIdentifier.getRegattaName()); |
|
| 2200 | + if (regatta != null) { |
|
| 2201 | + DynamicTrackedRegatta trackedRegatta = regattaTrackingCache.get(regatta); |
|
| 2202 | + if (trackedRegatta != null) { |
|
| 2203 | + RaceDefinition race = getRace(raceIdentifier); |
|
| 2204 | + if (race != null) { |
|
| 2205 | + result = trackedRegatta.getTrackedRace(race); |
|
| 2206 | + } |
|
| 2207 | + } |
|
| 2208 | + } |
|
| 2209 | + return result; |
|
| 2210 | + } |
|
| 2211 | + |
|
| 2212 | + @Override |
|
| 2213 | + public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) { |
|
| 2214 | + Regatta regatta = getRegattaByName(raceIdentifier.getRegattaName()); |
|
| 2215 | + DynamicTrackedRace trackedRace = null; |
|
| 2216 | + if (regatta != null) { |
|
| 2217 | + RaceDefinition race = regatta.getRaceByName(raceIdentifier.getRaceName()); |
|
| 2218 | + trackedRace = getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race); |
|
| 2219 | + } |
|
| 2220 | + return trackedRace; |
|
| 2221 | + } |
|
| 2222 | + |
|
| 2223 | + @Override |
|
| 2224 | + public RaceDefinition getRace(RegattaAndRaceIdentifier regattaNameAndRaceName) { |
|
| 2225 | + RaceDefinition result = null; |
|
| 2226 | + Regatta regatta = getRegatta(regattaNameAndRaceName); |
|
| 2227 | + if (regatta != null) { |
|
| 2228 | + result = regatta.getRaceByName(regattaNameAndRaceName.getRaceName()); |
|
| 2229 | + } |
|
| 2230 | + return result; |
|
| 2231 | + } |
|
| 2232 | + |
|
| 2233 | + @Override |
|
| 2234 | + public Map<String, LeaderboardGroup> getLeaderboardGroups() { |
|
| 2235 | + return Collections.unmodifiableMap(new HashMap<String, LeaderboardGroup>(leaderboardGroupsByName)); |
|
| 2236 | + } |
|
| 2237 | + |
|
| 2238 | + @Override |
|
| 2239 | + public LeaderboardGroup getLeaderboardGroupByName(String groupName) { |
|
| 2240 | + return leaderboardGroupsByName.get(groupName); |
|
| 2241 | + } |
|
| 2242 | + |
|
| 2243 | + @Override |
|
| 2244 | + public LeaderboardGroup getLeaderboardGroupByID(UUID leaderboardGroupID) { |
|
| 2245 | + return leaderboardGroupsByID.get(leaderboardGroupID); |
|
| 2246 | + } |
|
| 2247 | + |
|
| 2248 | + @Override |
|
| 2249 | + public LeaderboardGroup addLeaderboardGroup(UUID id, String groupName, String description, String displayName, |
|
| 2250 | + boolean displayGroupsInReverseOrder, List<String> leaderboardNames, |
|
| 2251 | + int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType) { |
|
| 2252 | + ArrayList<Leaderboard> leaderboards = new ArrayList<>(); |
|
| 2253 | + for (String leaderboardName : leaderboardNames) { |
|
| 2254 | + Leaderboard leaderboard = leaderboardsByName.get(leaderboardName); |
|
| 2255 | + if (leaderboard == null) { |
|
| 2256 | + throw new IllegalArgumentException("No leaderboard with name " + leaderboardName + " found"); |
|
| 2257 | + } else { |
|
| 2258 | + leaderboards.add(leaderboard); |
|
| 2259 | + } |
|
| 2260 | + } |
|
| 2261 | + LeaderboardGroup result = new LeaderboardGroupImpl(id, groupName, description, displayName, |
|
| 2262 | + displayGroupsInReverseOrder, leaderboards); |
|
| 2263 | + if (overallLeaderboardScoringSchemeType != null) { |
|
| 2264 | + // create overall leaderboard and its discards settings |
|
| 2265 | + addOverallLeaderboardToLeaderboardGroup(result, |
|
| 2266 | + getBaseDomainFactory().createScoringScheme(overallLeaderboardScoringSchemeType), |
|
| 2267 | + overallLeaderboardDiscardThresholds); |
|
| 2268 | + } |
|
| 2269 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 2270 | + try { |
|
| 2271 | + if (leaderboardGroupsByName.containsKey(groupName)) { |
|
| 2272 | + throw new IllegalArgumentException("Leaderboard group with name " + groupName + " already exists"); |
|
| 2273 | + } |
|
| 2274 | + leaderboardGroupsByName.put(groupName, result); |
|
| 2275 | + leaderboardGroupsByID.put(result.getId(), result); |
|
| 2276 | + } finally { |
|
| 2277 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 2278 | + } |
|
| 2279 | + mongoObjectFactory.storeLeaderboardGroup(result); |
|
| 2280 | + return result; |
|
| 2281 | + } |
|
| 2282 | + |
|
| 2283 | + @Override |
|
| 2284 | + public void addLeaderboardGroupWithoutReplication(LeaderboardGroup leaderboardGroup) { |
|
| 2285 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 2286 | + try { |
|
| 2287 | + String groupName = leaderboardGroup.getName(); |
|
| 2288 | + if (leaderboardGroupsByName.containsKey(groupName)) { |
|
| 2289 | + throw new IllegalArgumentException("Leaderboard group with name " + groupName + " already exists"); |
|
| 2290 | + } |
|
| 2291 | + leaderboardGroupsByName.put(groupName, leaderboardGroup); |
|
| 2292 | + leaderboardGroupsByID.put(leaderboardGroup.getId(), leaderboardGroup); |
|
| 2293 | + } finally { |
|
| 2294 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 2295 | + } |
|
| 2296 | + if (leaderboardGroup.hasOverallLeaderboard()) { |
|
| 2297 | + addLeaderboard(leaderboardGroup.getOverallLeaderboard()); |
|
| 2298 | + } |
|
| 2299 | + mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup); |
|
| 2300 | + } |
|
| 2301 | + |
|
| 2302 | + @Override |
|
| 2303 | + public void removeLeaderboardGroup(String groupName) { |
|
| 2304 | + final LeaderboardGroup leaderboardGroup; |
|
| 2305 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 2306 | + try { |
|
| 2307 | + leaderboardGroup = leaderboardGroupsByName.remove(groupName); |
|
| 2308 | + if (leaderboardGroup != null) { |
|
| 2309 | + leaderboardGroupsByID.remove(leaderboardGroup.getId()); |
|
| 2310 | + } |
|
| 2311 | + } finally { |
|
| 2312 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 2313 | + } |
|
| 2314 | + mongoObjectFactory.removeLeaderboardGroup(groupName); |
|
| 2315 | + if (leaderboardGroup != null && leaderboardGroup.getOverallLeaderboard() != null) { |
|
| 2316 | + removeLeaderboard(leaderboardGroup.getOverallLeaderboard().getName()); |
|
| 2317 | + } |
|
| 2318 | + } |
|
| 2319 | + |
|
| 2320 | + @Override |
|
| 2321 | + public void renameLeaderboardGroup(String oldName, String newName) { |
|
| 2322 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 2323 | + try { |
|
| 2324 | + final LeaderboardGroup toRename = leaderboardGroupsByName.get(oldName); |
|
| 2325 | + if (toRename == null) { |
|
| 2326 | + throw new IllegalArgumentException("No leaderboard group with name " + oldName + " found"); |
|
| 2327 | + } |
|
| 2328 | + if (leaderboardGroupsByName.containsKey(newName)) { |
|
| 2329 | + throw new IllegalArgumentException("Leaderboard group with name " + newName + " already exists"); |
|
| 2330 | + } |
|
| 2331 | + leaderboardGroupsByName.remove(oldName); |
|
| 2332 | + toRename.setName(newName); |
|
| 2333 | + leaderboardGroupsByName.put(newName, toRename); |
|
| 2334 | + } finally { |
|
| 2335 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 2336 | + } |
|
| 2337 | + mongoObjectFactory.renameLeaderboardGroup(oldName, newName); |
|
| 2338 | + } |
|
| 2339 | + |
|
| 2340 | + @Override |
|
| 2341 | + public void updateLeaderboardGroup(String oldName, String newName, String description, String displayName, |
|
| 2342 | + List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, |
|
| 2343 | + ScoringSchemeType overallLeaderboardScoringSchemeType) { |
|
| 2344 | + if (!oldName.equals(newName)) { |
|
| 2345 | + renameLeaderboardGroup(oldName, newName); |
|
| 2346 | + } |
|
| 2347 | + LeaderboardGroup group = getLeaderboardGroupByName(newName); |
|
| 2348 | + if (!description.equals(group.getDescription())) { |
|
| 2349 | + group.setDescriptiom(description); |
|
| 2350 | + } |
|
| 2351 | + if (!Util.equalsWithNull(displayName, group.getDisplayName())) { |
|
| 2352 | + group.setDisplayName(displayName); |
|
| 2353 | + } |
|
| 2354 | + group.clearLeaderboards(); |
|
| 2355 | + for (String leaderboardName : leaderboardNames) { |
|
| 2356 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 2357 | + if (leaderboard != null) { |
|
| 2358 | + group.addLeaderboard(leaderboard); |
|
| 2359 | + } |
|
| 2360 | + } |
|
| 2361 | + Leaderboard overallLeaderboard = group.getOverallLeaderboard(); |
|
| 2362 | + if (overallLeaderboard != null) { |
|
| 2363 | + if (overallLeaderboardScoringSchemeType == null) { |
|
| 2364 | + group.setOverallLeaderboard(null); |
|
| 2365 | + removeLeaderboard(overallLeaderboard.getName()); |
|
| 2366 | + } else { |
|
| 2367 | + // update existing overall leaderboard's discards settings; scoring scheme cannot be updated in-place |
|
| 2368 | + overallLeaderboard.setCrossLeaderboardResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl( |
|
| 2369 | + overallLeaderboardDiscardThresholds)); |
|
| 2370 | + updateStoredLeaderboard(overallLeaderboard); |
|
| 2371 | + } |
|
| 2372 | + } else if (overallLeaderboard == null && overallLeaderboardScoringSchemeType != null) { |
|
| 2373 | + addOverallLeaderboardToLeaderboardGroup(group, |
|
| 2374 | + getBaseDomainFactory().createScoringScheme(overallLeaderboardScoringSchemeType), |
|
| 2375 | + overallLeaderboardDiscardThresholds); |
|
| 2376 | + } |
|
| 2377 | + updateStoredLeaderboardGroup(group); |
|
| 2378 | + } |
|
| 2379 | + |
|
| 2380 | + private void addOverallLeaderboardToLeaderboardGroup(LeaderboardGroup leaderboardGroup, |
|
| 2381 | + ScoringScheme scoringScheme, int[] discardThresholds) { |
|
| 2382 | + Leaderboard overallLeaderboard = new LeaderboardGroupMetaLeaderboard(leaderboardGroup, scoringScheme, |
|
| 2383 | + new ThresholdBasedResultDiscardingRuleImpl(discardThresholds)); |
|
| 2384 | + leaderboardGroup.setOverallLeaderboard(overallLeaderboard); |
|
| 2385 | + addLeaderboard(overallLeaderboard); |
|
| 2386 | + updateStoredLeaderboard(overallLeaderboard); |
|
| 2387 | + } |
|
| 2388 | + |
|
| 2389 | + @Override |
|
| 2390 | + public void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup) { |
|
| 2391 | + mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup); |
|
| 2392 | + } |
|
| 2393 | + |
|
| 2394 | + private ScheduledExecutorService getScheduler() { |
|
| 2395 | + return scheduler; |
|
| 2396 | + } |
|
| 2397 | + |
|
| 2398 | + @Override |
|
| 2399 | + public ObjectInputStream createObjectInputStreamResolvingAgainstCache(InputStream is) throws IOException { |
|
| 2400 | + return getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory(is); |
|
| 2401 | + } |
|
| 2402 | + |
|
| 2403 | + @Override |
|
| 2404 | + public ClassLoader getDeserializationClassLoader() { |
|
| 2405 | + return joinedClassLoader; |
|
| 2406 | + } |
|
| 2407 | + |
|
| 2408 | + @Override |
|
| 2409 | + public Serializable getId() { |
|
| 2410 | + return getClass().getName(); |
|
| 2411 | + } |
|
| 2412 | + |
|
| 2413 | + @Override |
|
| 2414 | + public Iterable<OperationExecutionListener<RacingEventService>> getOperationExecutionListeners() { |
|
| 2415 | + return operationExecutionListeners.keySet(); |
|
| 2416 | + } |
|
| 2417 | + |
|
| 2418 | + @Override |
|
| 2419 | + public void addOperationExecutionListener(OperationExecutionListener<RacingEventService> listener) { |
|
| 2420 | + operationExecutionListeners.put(listener, listener); |
|
| 2421 | + } |
|
| 2422 | + |
|
| 2423 | + @Override |
|
| 2424 | + public void removeOperationExecutionListener(OperationExecutionListener<RacingEventService> listener) { |
|
| 2425 | + operationExecutionListeners.remove(listener); |
|
| 2426 | + } |
|
| 2427 | + |
|
| 2428 | + @Override |
|
| 2429 | + public void serializeForInitialReplicationInternal(ObjectOutputStream oos) throws IOException { |
|
| 2430 | + StringBuffer logoutput = new StringBuffer(); |
|
| 2431 | + |
|
| 2432 | + logger.info("Serializing regattas..."); |
|
| 2433 | + oos.writeObject(regattasByName); |
|
| 2434 | + logoutput.append("Serialized " + regattasByName.size() + " regattas\n"); |
|
| 2435 | + for (Regatta regatta : regattasByName.values()) { |
|
| 2436 | + logoutput.append(String.format("%3s\n", regatta.toString())); |
|
| 2437 | + } |
|
| 2438 | + |
|
| 2439 | + logger.info("Serializing events..."); |
|
| 2440 | + oos.writeObject(eventsById); |
|
| 2441 | + logoutput.append("\nSerialized " + eventsById.size() + " events\n"); |
|
| 2442 | + for (Event event : eventsById.values()) { |
|
| 2443 | + logoutput.append(String.format("%3s\n", event.toString())); |
|
| 2444 | + } |
|
| 2445 | + |
|
| 2446 | + logger.info("Serializing regattas observed..."); |
|
| 2447 | + oos.writeObject(regattasObservedForDefaultLeaderboard); |
|
| 2448 | + logger.info("Serializing regatta tracking cache..."); |
|
| 2449 | + oos.writeObject(regattaTrackingCache); |
|
| 2450 | + logger.info("Serializing leaderboard groups..."); |
|
| 2451 | + oos.writeObject(leaderboardGroupsByName); |
|
| 2452 | + logoutput.append("Serialized " + leaderboardGroupsByName.size() + " leaderboard groups\n"); |
|
| 2453 | + for (LeaderboardGroup lg : leaderboardGroupsByName.values()) { |
|
| 2454 | + logoutput.append(String.format("%3s\n", lg.toString())); |
|
| 2455 | + } |
|
| 2456 | + logger.info("Serializing leaderboards..."); |
|
| 2457 | + oos.writeObject(leaderboardsByName); |
|
| 2458 | + logoutput.append("Serialized " + leaderboardsByName.size() + " leaderboards\n"); |
|
| 2459 | + for (Leaderboard lg : leaderboardsByName.values()) { |
|
| 2460 | + logoutput.append(String.format("%3s\n", lg.toString())); |
|
| 2461 | + } |
|
| 2462 | + logger.info("Serializing media library..."); |
|
| 2463 | + mediaLibrary.serialize(oos); |
|
| 2464 | + logoutput.append("Serialized " + mediaLibrary.allTracks().size() + " media tracks\n"); |
|
| 2465 | + for (MediaTrack lg : mediaLibrary.allTracks()) { |
|
| 2466 | + logoutput.append(String.format("%3s\n", lg.toString())); |
|
| 2467 | + } |
|
| 2468 | + logger.info("Serializing persisted competitors..."); |
|
| 2469 | + oos.writeObject(competitorStore); |
|
| 2470 | + logoutput.append("Serialized " + competitorStore.size() + " persisted competitors\n"); |
|
| 2471 | + |
|
| 2472 | + logger.info("Serializing configuration map..."); |
|
| 2473 | + oos.writeObject(configurationMap); |
|
| 2474 | + logoutput.append("Serialized " + configurationMap.size() + " configuration entries\n"); |
|
| 2475 | + for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) { |
|
| 2476 | + logoutput.append(String.format("%3s\n", matcher.toString())); |
|
| 2477 | + } |
|
| 2478 | + |
|
| 2479 | + logger.info("Serializing remote sailing server references..."); |
|
| 2480 | + final ArrayList<RemoteSailingServerReference> remoteServerReferences = new ArrayList<>(remoteSailingServerSet |
|
| 2481 | + .getCachedEventsForRemoteSailingServers().keySet()); |
|
| 2482 | + oos.writeObject(remoteServerReferences); |
|
| 2483 | + logoutput.append("Serialized " + remoteServerReferences.size() + " remote sailing server references\n"); |
|
| 2484 | + |
|
| 2485 | + logger.info(logoutput.toString()); |
|
| 2486 | + } |
|
| 2487 | + |
|
| 2488 | + @SuppressWarnings("unchecked") |
|
| 2489 | + // all the casts of ois.readObject()'s return value to Map<..., ...> |
|
| 2490 | + // the type-parameters in the casts of the de-serialized collection objects can't be checked |
|
| 2491 | + @Override |
|
| 2492 | + public void initiallyFillFromInternal(ObjectInputStream ois) throws IOException, ClassNotFoundException, |
|
| 2493 | + InterruptedException { |
|
| 2494 | + logger.info("Performing initial replication load on " + this); |
|
| 2495 | + // Use this object's class's class loader as the context class loader which will then be used for |
|
| 2496 | + // de-serialization; this will cause all classes to be visible that this bundle |
|
| 2497 | + // (com.sap.sailing.server) can see |
|
| 2498 | + StringBuffer logoutput = new StringBuffer(); |
|
| 2499 | + logger.info("Reading all regattas..."); |
|
| 2500 | + regattasByName.putAll((Map<String, Regatta>) ois.readObject()); |
|
| 2501 | + logoutput.append("Received " + regattasByName.size() + " NEW regattas\n"); |
|
| 2502 | + for (Regatta regatta : regattasByName.values()) { |
|
| 2503 | + logoutput.append(String.format("%3s\n", regatta.toString())); |
|
| 2504 | + } |
|
| 2505 | + |
|
| 2506 | + logger.info("Reading all events..."); |
|
| 2507 | + eventsById.putAll((Map<Serializable, Event>) ois.readObject()); |
|
| 2508 | + logoutput.append("\nReceived " + eventsById.size() + " NEW events\n"); |
|
| 2509 | + for (Event event : eventsById.values()) { |
|
| 2510 | + logoutput.append(String.format("%3s\n", event.toString())); |
|
| 2511 | + } |
|
| 2512 | + |
|
| 2513 | + // it is important that the leaderboards and tracked regattas are cleared before auto-linking to |
|
| 2514 | + // old leaderboards takes place which then don't match the new ones |
|
| 2515 | + logger.info("Reading all dynamic tracked regattas..."); |
|
| 2516 | + for (DynamicTrackedRegatta trackedRegattaToObserve : (Set<DynamicTrackedRegatta>) ois.readObject()) { |
|
| 2517 | + ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(trackedRegattaToObserve); |
|
| 2518 | + } |
|
| 2519 | + |
|
| 2520 | + logger.info("Reading all of the regatta tracking cache..."); |
|
| 2521 | + regattaTrackingCache.putAll((Map<Regatta, DynamicTrackedRegatta>) ois.readObject()); |
|
| 2522 | + logoutput.append("Received " + regattaTrackingCache.size() + " NEW regatta tracking cache entries\n"); |
|
| 2523 | + |
|
| 2524 | + logger.info("Reading leaderboard groups..."); |
|
| 2525 | + leaderboardGroupsByName.putAll((Map<String, LeaderboardGroup>) ois.readObject()); |
|
| 2526 | + logoutput.append("Received " + leaderboardGroupsByName.size() + " NEW leaderboard groups\n"); |
|
| 2527 | + for (LeaderboardGroup lg : leaderboardGroupsByName.values()) { |
|
| 2528 | + leaderboardGroupsByID.put(lg.getId(), lg); |
|
| 2529 | + logoutput.append(String.format("%3s\n", lg.toString())); |
|
| 2530 | + } |
|
| 2531 | + |
|
| 2532 | + logger.info("Reading leaderboards by name..."); |
|
| 2533 | + leaderboardsByName.putAll((Map<String, Leaderboard>) ois.readObject()); |
|
| 2534 | + logoutput.append("Received " + leaderboardsByName.size() + " NEW leaderboards\n"); |
|
| 2535 | + for (Leaderboard leaderboard : leaderboardsByName.values()) { |
|
| 2536 | + logoutput.append(String.format("%3s\n", leaderboard.toString())); |
|
| 2537 | + } |
|
| 2538 | + |
|
| 2539 | + // now fix ScoreCorrectionListener setup for LeaderboardGroupMetaLeaderboard instances: |
|
| 2540 | + for (Leaderboard leaderboard : leaderboardsByName.values()) { |
|
| 2541 | + if (leaderboard instanceof LeaderboardGroupMetaLeaderboard) { |
|
| 2542 | + ((LeaderboardGroupMetaLeaderboard) leaderboard) |
|
| 2543 | + .registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards(); |
|
| 2544 | + } else if (leaderboard instanceof FlexibleLeaderboard) { |
|
| 2545 | + // and re-establish the RaceLogReplicator as listener on FlexibleLeaderboard objects |
|
| 2546 | + leaderboard.addRaceColumnListener(raceLogReplicator); |
|
| 2547 | + } |
|
| 2548 | + } |
|
| 2549 | + |
|
| 2550 | + logger.info("Reading media library..."); |
|
| 2551 | + mediaLibrary.deserialize(ois); |
|
| 2552 | + logoutput.append("Received " + mediaLibrary.allTracks().size() + " NEW media tracks\n"); |
|
| 2553 | + for (MediaTrack mediatrack : mediaLibrary.allTracks()) { |
|
| 2554 | + logoutput.append(String.format("%3s\n", mediatrack.toString())); |
|
| 2555 | + } |
|
| 2556 | + |
|
| 2557 | + // only copy the competitors from the deserialized competitor store; don't use it because it will have set |
|
| 2558 | + // a default Mongo object factory |
|
| 2559 | + logger.info("Reading competitors..."); |
|
| 2560 | + for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) { |
|
| 2561 | + DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor; |
|
| 2562 | + // the following should actually be redundant because during de-serialization the Competitor objects, |
|
| 2563 | + // whose classes implement IsManagedByCache, should already have been got/created from/in the |
|
| 2564 | + // competitor store |
|
| 2565 | + competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(), |
|
| 2566 | + dynamicCompetitor.getColor(), dynamicCompetitor.getEmail(), dynamicCompetitor.getFlagImage(), |
|
| 2567 | + dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat(), dynamicCompetitor.getTimeOnTimeFactor(), |
|
| 2568 | + dynamicCompetitor.getTimeOnDistanceAllowancePerNauticalMile()); |
|
| 2569 | + } |
|
| 2570 | + logoutput.append("Received " + competitorStore.size() + " NEW competitors\n"); |
|
| 2571 | + |
|
| 2572 | + logger.info("Reading device configurations..."); |
|
| 2573 | + configurationMap.putAll((DeviceConfigurationMapImpl) ois.readObject()); |
|
| 2574 | + logoutput.append("Received " + configurationMap.size() + " NEW configuration entries\n"); |
|
| 2575 | + for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) { |
|
| 2576 | + logoutput.append(String.format("%3s\n", matcher.toString())); |
|
| 2577 | + } |
|
| 2578 | + |
|
| 2579 | + logger.info("Reading remote sailing server references..."); |
|
| 2580 | + for (RemoteSailingServerReference remoteSailingServerReference : (Iterable<RemoteSailingServerReference>) ois |
|
| 2581 | + .readObject()) { |
|
| 2582 | + remoteSailingServerSet.add(remoteSailingServerReference); |
|
| 2583 | + logoutput.append("Received remote sailing server reference " + remoteSailingServerReference); |
|
| 2584 | + } |
|
| 2585 | + |
|
| 2586 | + // make sure to initialize listeners correctly |
|
| 2587 | + for (Regatta regatta : regattasByName.values()) { |
|
| 2588 | + RegattaImpl regattaImpl = (RegattaImpl) regatta; |
|
| 2589 | + regattaImpl.initializeSeriesAfterDeserialize(); |
|
| 2590 | + regattaImpl.addRaceColumnListener(raceLogReplicator); |
|
| 2591 | + } |
|
| 2592 | + // re-establish RaceLogResolver references to this RacingEventService in all TrackedRace instances |
|
| 2593 | + for (DynamicTrackedRegatta trackedRegatta : regattaTrackingCache.values()) { |
|
| 2594 | + trackedRegatta.lockTrackedRacesForRead(); |
|
| 2595 | + try { |
|
| 2596 | + for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { |
|
| 2597 | + ((TrackedRaceImpl) trackedRace).setRaceLogResolver(this); |
|
| 2598 | + } |
|
| 2599 | + } finally { |
|
| 2600 | + trackedRegatta.unlockTrackedRacesAfterRead(); |
|
| 2601 | + } |
|
| 2602 | + } |
|
| 2603 | + logger.info(logoutput.toString()); |
|
| 2604 | + } |
|
| 2605 | + |
|
| 2606 | + @Override |
|
| 2607 | + public void clearReplicaState() throws MalformedURLException, IOException, InterruptedException { |
|
| 2608 | + logger.info("Clearing all data structures..."); |
|
| 2609 | + LockUtil.lockForWrite(regattasByNameLock); |
|
| 2610 | + try { |
|
| 2611 | + regattasByName.clear(); |
|
| 2612 | + } finally { |
|
| 2613 | + LockUtil.unlockAfterWrite(regattasByNameLock); |
|
| 2614 | + } |
|
| 2615 | + regattasObservedForDefaultLeaderboard.clear(); |
|
| 2616 | + |
|
| 2617 | + if (raceTrackersByRegatta != null && !raceTrackersByRegatta.isEmpty()) { |
|
| 2618 | + for (DynamicTrackedRegatta regatta : regattaTrackingCache.values()) { |
|
| 2619 | + final Set<RaceTracker> trackers = raceTrackersByRegatta.get(regatta.getRegatta()); |
|
| 2620 | + if (trackers != null) { |
|
| 2621 | + for (RaceTracker tracker : trackers) { |
|
| 2622 | + tracker.stop(/* preemptive */true); |
|
| 2623 | + } |
|
| 2624 | + } |
|
| 2625 | + } |
|
| 2626 | + } |
|
| 2627 | + LockUtil.lockForWrite(regattaTrackingCacheLock); |
|
| 2628 | + try { |
|
| 2629 | + regattaTrackingCache.clear(); |
|
| 2630 | + } finally { |
|
| 2631 | + LockUtil.unlockAfterWrite(regattaTrackingCacheLock); |
|
| 2632 | + } |
|
| 2633 | + LockUtil.lockForWrite(raceTrackersByRegattaLock); |
|
| 2634 | + try { |
|
| 2635 | + raceTrackersByRegatta.clear(); |
|
| 2636 | + } finally { |
|
| 2637 | + LockUtil.unlockAfterWrite(raceTrackersByRegattaLock); |
|
| 2638 | + } |
|
| 2639 | + LockUtil.lockForWrite(leaderboardGroupsByNameLock); |
|
| 2640 | + try { |
|
| 2641 | + leaderboardGroupsByName.clear(); |
|
| 2642 | + leaderboardGroupsByID.clear(); |
|
| 2643 | + } finally { |
|
| 2644 | + LockUtil.unlockAfterWrite(leaderboardGroupsByNameLock); |
|
| 2645 | + } |
|
| 2646 | + LockUtil.lockForWrite(leaderboardsByNameLock); |
|
| 2647 | + try { |
|
| 2648 | + leaderboardsByName.clear(); |
|
| 2649 | + } finally { |
|
| 2650 | + LockUtil.unlockAfterWrite(leaderboardsByNameLock); |
|
| 2651 | + } |
|
| 2652 | + eventsById.clear(); |
|
| 2653 | + mediaLibrary.clear(); |
|
| 2654 | + competitorStore.clear(); |
|
| 2655 | + remoteSailingServerSet.clear(); |
|
| 2656 | + } |
|
| 2657 | + |
|
| 2658 | + // Used for TESTING only |
|
| 2659 | + @Override |
|
| 2660 | + public Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, |
|
| 2661 | + String venue, boolean isPublic, UUID id) { |
|
| 2662 | + Event result = createEventWithoutReplication(eventName, eventDescription, startDate, endDate, venue, isPublic, |
|
| 2663 | + id, /* officialWebsiteURL */null, /* sailorsInfoWebsiteURLAsString */null, |
|
| 2664 | + /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList()); |
|
| 2665 | + replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id, |
|
| 2666 | + /* officialWebsiteURLAsString */null, /* sailorsInfoWebsiteURLAsString */null, |
|
| 2667 | + /* images */Collections.<ImageDescriptor> emptyList(), /* videos */Collections.<VideoDescriptor> emptyList())); |
|
| 2668 | + return result; |
|
| 2669 | + } |
|
| 2670 | + |
|
| 2671 | + @Override |
|
| 2672 | + public void addEventWithoutReplication(Event event) { |
|
| 2673 | + addEvent(event); |
|
| 2674 | + } |
|
| 2675 | + |
|
| 2676 | + @Override |
|
| 2677 | + public Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, |
|
| 2678 | + TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, |
|
| 2679 | + Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) { |
|
| 2680 | + Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id); |
|
| 2681 | + addEvent(result); |
|
| 2682 | + result.setDescription(eventDescription); |
|
| 2683 | + result.setOfficialWebsiteURL(officialWebsiteURL); |
|
| 2684 | + result.setImages(images); |
|
| 2685 | + result.setVideos(videos); |
|
| 2686 | + return result; |
|
| 2687 | + } |
|
| 2688 | + |
|
| 2689 | + private void addEvent(Event result) { |
|
| 2690 | + if (eventsById.containsKey(result.getId())) { |
|
| 2691 | + throw new IllegalArgumentException("Event with ID " + result.getId() |
|
| 2692 | + + " already exists which is pretty surprising..."); |
|
| 2693 | + } |
|
| 2694 | + eventsById.put(result.getId(), result); |
|
| 2695 | + mongoObjectFactory.storeEvent(result); |
|
| 2696 | + } |
|
| 2697 | + |
|
| 2698 | + @Override |
|
| 2699 | + public void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, |
|
| 2700 | + String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, |
|
| 2701 | + Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) { |
|
| 2702 | + final Event event = eventsById.get(id); |
|
| 2703 | + if (event == null) { |
|
| 2704 | + throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist."); |
|
| 2705 | + } |
|
| 2706 | + event.setName(eventName); |
|
| 2707 | + event.setDescription(eventDescription); |
|
| 2708 | + event.setStartDate(startDate); |
|
| 2709 | + event.setEndDate(endDate); |
|
| 2710 | + event.setPublic(isPublic); |
|
| 2711 | + event.getVenue().setName(venueName); |
|
| 2712 | + List<LeaderboardGroup> leaderboardGroups = new ArrayList<>(); |
|
| 2713 | + for (UUID lgid : leaderboardGroupIds) { |
|
| 2714 | + LeaderboardGroup lg = getLeaderboardGroupByID(lgid); |
|
| 2715 | + if (lg != null) { |
|
| 2716 | + leaderboardGroups.add(lg); |
|
| 2717 | + } else { |
|
| 2718 | + logger.info("Couldn't find leaderboard group with ID " + lgid + " while updating event " |
|
| 2719 | + + event.getName()); |
|
| 2720 | + } |
|
| 2721 | + } |
|
| 2722 | + event.setLeaderboardGroups(leaderboardGroups); |
|
| 2723 | + event.setOfficialWebsiteURL(officialWebsiteURL); |
|
| 2724 | + event.setSailorsInfoWebsiteURL(sailorsInfoWebsiteURL); |
|
| 2725 | + event.setImages(images); |
|
| 2726 | + event.setVideos(videos); |
|
| 2727 | + // TODO consider use diffutils to compute diff between old and new leaderboard groups list and apply the patch |
|
| 2728 | + // to keep changes minimial |
|
| 2729 | + mongoObjectFactory.storeEvent(event); |
|
| 2730 | + } |
|
| 2731 | + |
|
| 2732 | + @Override |
|
| 2733 | + public void renameEvent(UUID id, String newName) { |
|
| 2734 | + final Event toRename = eventsById.get(id); |
|
| 2735 | + if (toRename == null) { |
|
| 2736 | + throw new IllegalArgumentException("No sailing event with ID " + id + " found."); |
|
| 2737 | + } |
|
| 2738 | + toRename.setName(newName); |
|
| 2739 | + mongoObjectFactory.renameEvent(id, newName); |
|
| 2740 | + replicate(new RenameEvent(id, newName)); |
|
| 2741 | + } |
|
| 2742 | + |
|
| 2743 | + @Override |
|
| 2744 | + public void removeEvent(UUID id) { |
|
| 2745 | + removeEventFromEventsById(id); |
|
| 2746 | + mongoObjectFactory.removeEvent(id); |
|
| 2747 | + replicate(new RemoveEvent(id)); |
|
| 2748 | + } |
|
| 2749 | + |
|
| 2750 | + protected void removeEventFromEventsById(Serializable id) { |
|
| 2751 | + eventsById.remove(id); |
|
| 2752 | + } |
|
| 2753 | + |
|
| 2754 | + @Override |
|
| 2755 | + public Regatta getRememberedRegattaForRace(Serializable raceID) { |
|
| 2756 | + return persistentRegattasForRaceIDs.get(raceID.toString()); |
|
| 2757 | + } |
|
| 2758 | + |
|
| 2759 | + /** |
|
| 2760 | + * Persistently remembers the association of the race with its {@link RaceDefinition#getId()} to the |
|
| 2761 | + * <code>regatta</code> with its {@link Regatta#getRegattaIdentifier() identifier} so that the next time |
|
| 2762 | + * {@link #getRememberedRegattaForRace(RaceDefinition)} is called with <code>race</code> as argument, |
|
| 2763 | + * <code>regatta</code> will be returned. |
|
| 2764 | + */ |
|
| 2765 | + private void setRegattaForRace(Regatta regatta, RaceDefinition race) { |
|
| 2766 | + setRegattaForRace(regatta, race.getId().toString()); |
|
| 2767 | + } |
|
| 2768 | + |
|
| 2769 | + @Override |
|
| 2770 | + public void setRegattaForRace(Regatta regatta, String raceIdAsString) { |
|
| 2771 | + persistentRegattasForRaceIDs.put(raceIdAsString, regatta); |
|
| 2772 | + mongoObjectFactory.storeRegattaForRaceID(raceIdAsString, regatta); |
|
| 2773 | + } |
|
| 2774 | + |
|
| 2775 | + @Override |
|
| 2776 | + public CourseArea[] addCourseAreas(UUID eventId, String[] courseAreaNames, UUID[] courseAreaIds) { |
|
| 2777 | + final CourseArea[] courseAreas = addCourseAreasWithoutReplication(eventId, courseAreaIds, courseAreaNames); |
|
| 2778 | + replicate(new AddCourseAreas(eventId, courseAreaNames, courseAreaIds)); |
|
| 2779 | + return courseAreas; |
|
| 2780 | + } |
|
| 2781 | + |
|
| 2782 | + @Override |
|
| 2783 | + public CourseArea[] addCourseAreasWithoutReplication(UUID eventId, UUID[] courseAreaIds, String[] courseAreaNames) { |
|
| 2784 | + final CourseArea[] result = new CourseArea[courseAreaNames.length]; |
|
| 2785 | + for (int i=0; i<courseAreaIds.length; i++) { |
|
| 2786 | + final CourseArea courseArea = getBaseDomainFactory().getOrCreateCourseArea(courseAreaIds[i], courseAreaNames[i]); |
|
| 2787 | + final Event event = eventsById.get(eventId); |
|
| 2788 | + if (event == null) { |
|
| 2789 | + throw new IllegalArgumentException("No sailing event with ID " + eventId + " found."); |
|
| 2790 | + } |
|
| 2791 | + event.getVenue().addCourseArea(courseArea); |
|
| 2792 | + mongoObjectFactory.storeEvent(event); |
|
| 2793 | + result[i] = courseArea; |
|
| 2794 | + } |
|
| 2795 | + return result; |
|
| 2796 | + } |
|
| 2797 | + |
|
| 2798 | + @Override |
|
| 2799 | + public CourseArea[] removeCourseAreaWithoutReplication(UUID eventId, UUID[] courseAreaIds) { |
|
| 2800 | + final Event event = eventsById.get(eventId); |
|
| 2801 | + if (event == null) { |
|
| 2802 | + throw new IllegalArgumentException("No sailing event with ID " + eventId + " found."); |
|
| 2803 | + } |
|
| 2804 | + final CourseArea[] courseAreasRemoved = new CourseArea[courseAreaIds.length]; |
|
| 2805 | + int i=0; |
|
| 2806 | + for (final UUID courseAreaId : courseAreaIds) { |
|
| 2807 | + final CourseArea courseArea = getBaseDomainFactory().getExistingCourseAreaById(courseAreaId); |
|
| 2808 | + if (courseArea == null) { |
|
| 2809 | + throw new IllegalArgumentException("No course area with ID " + courseAreaId + " found."); |
|
| 2810 | + } |
|
| 2811 | + courseAreasRemoved[i++] = courseArea; |
|
| 2812 | + event.getVenue().removeCourseArea(courseArea); |
|
| 2813 | + mongoObjectFactory.storeEvent(event); |
|
| 2814 | + } |
|
| 2815 | + return courseAreasRemoved; |
|
| 2816 | + } |
|
| 2817 | + |
|
| 2818 | + @Override |
|
| 2819 | + public void mediaTrackAdded(MediaTrack mediaTrack) { |
|
| 2820 | + if (mediaTrack.dbId == null) { |
|
| 2821 | + mediaTrack.dbId = mediaDB.insertMediaTrack(mediaTrack.title, mediaTrack.url, mediaTrack.startTime, |
|
| 2822 | + mediaTrack.duration, mediaTrack.mimeType, mediaTrack.assignedRaces); |
|
| 2823 | + } |
|
| 2824 | + mediaLibrary.addMediaTrack(mediaTrack); |
|
| 2825 | + replicate(new AddMediaTrackOperation(mediaTrack)); |
|
| 2826 | + } |
|
| 2827 | + |
|
| 2828 | + @Override |
|
| 2829 | + public void mediaTracksAdded(Collection<MediaTrack> mediaTracks) { |
|
| 2830 | + mediaLibrary.addMediaTracks(mediaTracks); |
|
| 2831 | + } |
|
| 2832 | + |
|
| 2833 | + @Override |
|
| 2834 | + public void mediaTrackTitleChanged(MediaTrack mediaTrack) { |
|
| 2835 | + mediaDB.updateTitle(mediaTrack.dbId, mediaTrack.title); |
|
| 2836 | + mediaLibrary.titleChanged(mediaTrack); |
|
| 2837 | + replicate(new UpdateMediaTrackTitleOperation(mediaTrack)); |
|
| 2838 | + } |
|
| 2839 | + |
|
| 2840 | + @Override |
|
| 2841 | + public void mediaTrackUrlChanged(MediaTrack mediaTrack) { |
|
| 2842 | + mediaDB.updateUrl(mediaTrack.dbId, mediaTrack.url); |
|
| 2843 | + mediaLibrary.urlChanged(mediaTrack); |
|
| 2844 | + replicate(new UpdateMediaTrackUrlOperation(mediaTrack)); |
|
| 2845 | + } |
|
| 2846 | + |
|
| 2847 | + @Override |
|
| 2848 | + public void mediaTrackStartTimeChanged(MediaTrack mediaTrack) { |
|
| 2849 | + mediaDB.updateStartTime(mediaTrack.dbId, mediaTrack.startTime); |
|
| 2850 | + mediaLibrary.startTimeChanged(mediaTrack); |
|
| 2851 | + replicate(new UpdateMediaTrackStartTimeOperation(mediaTrack)); |
|
| 2852 | + } |
|
| 2853 | + |
|
| 2854 | + @Override |
|
| 2855 | + public void mediaTrackDurationChanged(MediaTrack mediaTrack) { |
|
| 2856 | + mediaDB.updateDuration(mediaTrack.dbId, mediaTrack.duration); |
|
| 2857 | + mediaLibrary.durationChanged(mediaTrack); |
|
| 2858 | + replicate(new UpdateMediaTrackDurationOperation(mediaTrack)); |
|
| 2859 | + } |
|
| 2860 | + |
|
| 2861 | + @Override |
|
| 2862 | + public void mediaTrackAssignedRacesChanged(MediaTrack mediaTrack) { |
|
| 2863 | + mediaDB.updateRace(mediaTrack.dbId, mediaTrack.assignedRaces); |
|
| 2864 | + mediaLibrary.assignedRacesChanged(mediaTrack); |
|
| 2865 | + replicate(new UpdateMediaTrackRacesOperation(mediaTrack)); |
|
| 2866 | + |
|
| 2867 | + } |
|
| 2868 | + |
|
| 2869 | + @Override |
|
| 2870 | + public void mediaTrackDeleted(MediaTrack mediaTrack) { |
|
| 2871 | + mediaDB.deleteMediaTrack(mediaTrack.dbId); |
|
| 2872 | + mediaLibrary.deleteMediaTrack(mediaTrack); |
|
| 2873 | + replicate(new RemoveMediaTrackOperation(mediaTrack)); |
|
| 2874 | + } |
|
| 2875 | + |
|
| 2876 | + @Override |
|
| 2877 | + public void mediaTracksImported(Collection<MediaTrack> mediaTracksToImport, boolean override) { |
|
| 2878 | + for (MediaTrack trackToImport : mediaTracksToImport) { |
|
| 2879 | + MediaTrack existingTrack = mediaLibrary.lookupMediaTrack(trackToImport); |
|
| 2880 | + if (existingTrack == null) { |
|
| 2881 | + mediaDB.insertMediaTrackWithId(trackToImport.dbId, trackToImport.title, trackToImport.url, |
|
| 2882 | + trackToImport.startTime, trackToImport.duration, trackToImport.mimeType, |
|
| 2883 | + trackToImport.assignedRaces); |
|
| 2884 | + mediaTrackAdded(trackToImport); |
|
| 2885 | + } else if (override) { |
|
| 2886 | + |
|
| 2887 | + // Using fine-grained update methods. |
|
| 2888 | + // Rationale: Changes on more than one track property are rare |
|
| 2889 | + // and don't justify the introduction of a new set |
|
| 2890 | + // of methods (including replication). |
|
| 2891 | + if (!Util.equalsWithNull(existingTrack.title, trackToImport.title)) { |
|
| 2892 | + mediaTrackTitleChanged(trackToImport); |
|
| 2893 | + } |
|
| 2894 | + if (!Util.equalsWithNull(existingTrack.url, trackToImport.url)) { |
|
| 2895 | + mediaTrackUrlChanged(trackToImport); |
|
| 2896 | + } |
|
| 2897 | + if (!Util.equalsWithNull(existingTrack.startTime, trackToImport.startTime)) { |
|
| 2898 | + mediaTrackStartTimeChanged(trackToImport); |
|
| 2899 | + } |
|
| 2900 | + if (!Util.equalsWithNull(existingTrack.duration, trackToImport.duration)) { |
|
| 2901 | + mediaTrackDurationChanged(trackToImport); |
|
| 2902 | + } |
|
| 2903 | + if (!Util.equalsWithNull(existingTrack.assignedRaces, trackToImport.assignedRaces)) { |
|
| 2904 | + mediaTrackAssignedRacesChanged(trackToImport); |
|
| 2905 | + } |
|
| 2906 | + } |
|
| 2907 | + } |
|
| 2908 | + } |
|
| 2909 | + |
|
| 2910 | + @Override |
|
| 2911 | + public Collection<MediaTrack> getMediaTracksForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier) { |
|
| 2912 | + return mediaLibrary.findMediaTracksForRace(regattaAndRaceIdentifier); |
|
| 2913 | + } |
|
| 2914 | + |
|
| 2915 | + @Override |
|
| 2916 | + public Collection<MediaTrack> getMediaTracksInTimeRange(RegattaAndRaceIdentifier regattaAndRaceIdentifier) { |
|
| 2917 | + TrackedRace trackedRace = getExistingTrackedRace(regattaAndRaceIdentifier); |
|
| 2918 | + if (trackedRace != null) { |
|
| 2919 | + if (trackedRace.isLive(MillisecondsTimePoint.now())) { |
|
| 2920 | + return mediaLibrary.findLiveMediaTracks(); |
|
| 2921 | + } else { |
|
| 2922 | + TimePoint raceStart = trackedRace.getStartOfRace() == null ? trackedRace.getStartOfTracking() |
|
| 2923 | + : trackedRace.getStartOfRace(); |
|
| 2924 | + TimePoint raceEnd = trackedRace.getEndOfRace() == null ? trackedRace.getEndOfTracking() : trackedRace |
|
| 2925 | + .getEndOfRace(); |
|
| 2926 | + return mediaLibrary.findMediaTracksInTimeRange(raceStart, raceEnd); |
|
| 2927 | + } |
|
| 2928 | + } else { |
|
| 2929 | + return Collections.emptyList(); |
|
| 2930 | + } |
|
| 2931 | + } |
|
| 2932 | + |
|
| 2933 | + @Override |
|
| 2934 | + public Collection<MediaTrack> getAllMediaTracks() { |
|
| 2935 | + return mediaLibrary.allTracks(); |
|
| 2936 | + } |
|
| 2937 | + |
|
| 2938 | + public String toString() { |
|
| 2939 | + return "RacingEventService: " + this.hashCode() + " Build: " + ServerInfo.getBuildVersion(); |
|
| 2940 | + } |
|
| 2941 | + |
|
| 2942 | + @Override |
|
| 2943 | + public void reloadRaceLog(String leaderboardName, String raceColumnName, String fleetName) { |
|
| 2944 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 2945 | + if (leaderboard != null) { |
|
| 2946 | + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); |
|
| 2947 | + if (raceColumn != null) { |
|
| 2948 | + Fleet fleetImpl = raceColumn.getFleetByName(fleetName); |
|
| 2949 | + RaceLog racelog = raceColumn.getRaceLog(fleetImpl); |
|
| 2950 | + if (racelog != null) { |
|
| 2951 | + raceColumn.reloadRaceLog(fleetImpl); |
|
| 2952 | + logger.info("Reloaded race log for fleet " + fleetImpl + " for race column " + raceColumn.getName() |
|
| 2953 | + + " for leaderboard " + leaderboard.getName()); |
|
| 2954 | + } |
|
| 2955 | + } |
|
| 2956 | + } |
|
| 2957 | + } |
|
| 2958 | + |
|
| 2959 | + @Override |
|
| 2960 | + public ConcurrentHashMap<String, Regatta> getPersistentRegattasForRaceIDs() { |
|
| 2961 | + return persistentRegattasForRaceIDs; |
|
| 2962 | + } |
|
| 2963 | + |
|
| 2964 | + @Override |
|
| 2965 | + public WindStore getWindStore() { |
|
| 2966 | + return windStore; |
|
| 2967 | + } |
|
| 2968 | + |
|
| 2969 | + @Override |
|
| 2970 | + public DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier) { |
|
| 2971 | + return configurationMap.getByMatch(identifier); |
|
| 2972 | + } |
|
| 2973 | + |
|
| 2974 | + @Override |
|
| 2975 | + public void createOrUpdateDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) { |
|
| 2976 | + configurationMap.put(matcher, configuration); |
|
| 2977 | + mongoObjectFactory.storeDeviceConfiguration(matcher, configuration); |
|
| 2978 | + replicate(new CreateOrUpdateDeviceConfiguration(matcher, configuration)); |
|
| 2979 | + } |
|
| 2980 | + |
|
| 2981 | + @Override |
|
| 2982 | + public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) { |
|
| 2983 | + configurationMap.remove(matcher); |
|
| 2984 | + mongoObjectFactory.removeDeviceConfiguration(matcher); |
|
| 2985 | + replicate(new RemoveDeviceConfiguration(matcher)); |
|
| 2986 | + } |
|
| 2987 | + |
|
| 2988 | + @Override |
|
| 2989 | + public Map<DeviceConfigurationMatcher, DeviceConfiguration> getAllDeviceConfigurations() { |
|
| 2990 | + return new HashMap<DeviceConfigurationMatcher, DeviceConfiguration>(configurationMap); |
|
| 2991 | + } |
|
| 2992 | + |
|
| 2993 | + @Override |
|
| 2994 | + public TimePoint setStartTimeAndProcedure(String leaderboardName, String raceColumnName, String fleetName, |
|
| 2995 | + String authorName, int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime, |
|
| 2996 | + RacingProcedureType racingProcedure) { |
|
| 2997 | + RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); |
|
| 2998 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 2999 | + final TimePoint result; |
|
| 3000 | + if (leaderboard instanceof HasRegattaLike && raceLog != null) { |
|
| 3001 | + RaceState state = RaceStateImpl.create(/* race log resolver */ this, raceLog, new LogEventAuthorImpl(authorName, authorPriority)); |
|
| 3002 | + if (passId > raceLog.getCurrentPassId()) { |
|
| 3003 | + state.setAdvancePass(logicalTimePoint); |
|
| 3004 | + } |
|
| 3005 | + state.setRacingProcedure(logicalTimePoint, racingProcedure); |
|
| 3006 | + state.forceNewStartTime(logicalTimePoint, startTime); |
|
| 3007 | + result = state.getStartTime(); |
|
| 3008 | + } else { |
|
| 3009 | + result = null; |
|
| 3010 | + } |
|
| 3011 | + return result; |
|
| 3012 | + } |
|
| 3013 | + |
|
| 3014 | + public RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName) { |
|
| 3015 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 3016 | + if (leaderboard != null) { |
|
| 3017 | + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); |
|
| 3018 | + if (raceColumn != null) { |
|
| 3019 | + Fleet fleetImpl = raceColumn.getFleetByName(fleetName); |
|
| 3020 | + return raceColumn.getRaceLog(fleetImpl); |
|
| 3021 | + } |
|
| 3022 | + } |
|
| 3023 | + return null; |
|
| 3024 | + } |
|
| 3025 | + |
|
| 3026 | + @Override |
|
| 3027 | + public com.sap.sse.common.Util.Triple<TimePoint, Integer, RacingProcedureType> getStartTimeAndProcedure( |
|
| 3028 | + String leaderboardName, String raceColumnName, String fleetName) { |
|
| 3029 | + RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); |
|
| 3030 | + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); |
|
| 3031 | + final Triple<TimePoint, Integer, RacingProcedureType> result; |
|
| 3032 | + if (leaderboard instanceof HasRegattaLike && raceLog != null) { |
|
| 3033 | + ReadonlyRaceState state = ReadonlyRaceStateImpl.create(/* race log resolver */ this, raceLog); |
|
| 3034 | + result = new com.sap.sse.common.Util.Triple<TimePoint, Integer, RacingProcedureType>(state.getStartTime(), |
|
| 3035 | + raceLog.getCurrentPassId(), state.getRacingProcedure().getType()); |
|
| 3036 | + } else { |
|
| 3037 | + result = null; |
|
| 3038 | + } |
|
| 3039 | + return result; |
|
| 3040 | + } |
|
| 3041 | + |
|
| 3042 | + private Iterable<WindTrackerFactory> getWindTrackerFactories() { |
|
| 3043 | + final Set<WindTrackerFactory> result; |
|
| 3044 | + if (bundleContext == null) { |
|
| 3045 | + result = Collections.singleton((WindTrackerFactory) ExpeditionWindTrackerFactory.getInstance()); |
|
| 3046 | + } else { |
|
| 3047 | + ServiceTracker<WindTrackerFactory, WindTrackerFactory> tracker = new ServiceTracker<WindTrackerFactory, WindTrackerFactory>( |
|
| 3048 | + bundleContext, WindTrackerFactory.class.getName(), null); |
|
| 3049 | + tracker.open(); |
|
| 3050 | + result = new HashSet<>(); |
|
| 3051 | + for (WindTrackerFactory factory : tracker.getServices(new WindTrackerFactory[0])) { |
|
| 3052 | + result.add(factory); |
|
| 3053 | + } |
|
| 3054 | + } |
|
| 3055 | + return result; |
|
| 3056 | + } |
|
| 3057 | + |
|
| 3058 | + @Override |
|
| 3059 | + public GPSFixStore getGPSFixStore() { |
|
| 3060 | + return gpsFixStore; |
|
| 3061 | + } |
|
| 3062 | + |
|
| 3063 | + @Override |
|
| 3064 | + public RaceTracker getRaceTrackerById(Object id) { |
|
| 3065 | + return raceTrackersByID.get(id); |
|
| 3066 | + } |
|
| 3067 | + |
|
| 3068 | + @Override |
|
| 3069 | + public AbstractLogEventAuthor getServerAuthor() { |
|
| 3070 | + return raceLogEventAuthorForServer; |
|
| 3071 | + } |
|
| 3072 | + |
|
| 3073 | + @Override |
|
| 3074 | + public CompetitorStore getCompetitorStore() { |
|
| 3075 | + return competitorStore; |
|
| 3076 | + } |
|
| 3077 | + |
|
| 3078 | + @Override |
|
| 3079 | + public TypeBasedServiceFinderFactory getTypeBasedServiceFinderFactory() { |
|
| 3080 | + return serviceFinderFactory; |
|
| 3081 | + } |
|
| 3082 | + |
|
| 3083 | + @Override |
|
| 3084 | + public DataImportLockWithProgress getDataImportLock() { |
|
| 3085 | + return dataImportLock; |
|
| 3086 | + } |
|
| 3087 | + |
|
| 3088 | + @Override |
|
| 3089 | + public DataImportProgress createOrUpdateDataImportProgressWithReplication(UUID importOperationId, |
|
| 3090 | + double overallProgressPct, String subProgressName, double subProgressPct) { |
|
| 3091 | + // Create/Update locally |
|
| 3092 | + DataImportProgress progress = createOrUpdateDataImportProgressWithoutReplication(importOperationId, |
|
| 3093 | + overallProgressPct, subProgressName, subProgressPct); |
|
| 3094 | + // Create/Update on replicas |
|
| 3095 | + replicate(new CreateOrUpdateDataImportProgress(importOperationId, overallProgressPct, subProgressName, |
|
| 3096 | + subProgressPct)); |
|
| 3097 | + return progress; |
|
| 3098 | + } |
|
| 3099 | + |
|
| 3100 | + @Override |
|
| 3101 | + public DataImportProgress createOrUpdateDataImportProgressWithoutReplication(UUID importOperationId, |
|
| 3102 | + double overallProgressPct, String subProgressName, double subProgressPct) { |
|
| 3103 | + DataImportProgress progress = dataImportLock.getProgress(importOperationId); |
|
| 3104 | + boolean newObject = false; |
|
| 3105 | + if (progress == null) { |
|
| 3106 | + progress = new DataImportProgressImpl(importOperationId); |
|
| 3107 | + newObject = true; |
|
| 3108 | + } |
|
| 3109 | + progress.setOverAllProgressPct(overallProgressPct); |
|
| 3110 | + progress.setNameOfCurrentSubProgress(subProgressName); |
|
| 3111 | + progress.setCurrentSubProgressPct(subProgressPct); |
|
| 3112 | + if (newObject) { |
|
| 3113 | + dataImportLock.addProgress(importOperationId, progress); |
|
| 3114 | + } |
|
| 3115 | + return progress; |
|
| 3116 | + } |
|
| 3117 | + |
|
| 3118 | + @Override |
|
| 3119 | + public void setDataImportFailedWithoutReplication(UUID importOperationId, String errorMessage) { |
|
| 3120 | + DataImportProgress progress = dataImportLock.getProgress(importOperationId); |
|
| 3121 | + if (progress != null) { |
|
| 3122 | + progress.setFailed(); |
|
| 3123 | + progress.setErrorMessage(errorMessage); |
|
| 3124 | + } |
|
| 3125 | + } |
|
| 3126 | + |
|
| 3127 | + @Override |
|
| 3128 | + public void setDataImportFailedWithReplication(UUID importOperationId, String errorMessage) { |
|
| 3129 | + setDataImportFailedWithoutReplication(importOperationId, errorMessage); |
|
| 3130 | + replicate(new DataImportFailed(importOperationId, errorMessage)); |
|
| 3131 | + } |
|
| 3132 | + |
|
| 3133 | + @Override |
|
| 3134 | + public void setDataImportDeleteProgressFromMapTimerWithReplication(UUID importOperationId) { |
|
| 3135 | + setDataImportDeleteProgressFromMapTimerWithoutReplication(importOperationId); |
|
| 3136 | + replicate(new SetDataImportDeleteProgressFromMapTimer(importOperationId)); |
|
| 3137 | + } |
|
| 3138 | + |
|
| 3139 | + @Override |
|
| 3140 | + public void setDataImportDeleteProgressFromMapTimerWithoutReplication(UUID importOperationId) { |
|
| 3141 | + dataImportLock.setDeleteFromMapTimer(importOperationId); |
|
| 3142 | + } |
|
| 3143 | + |
|
| 3144 | + @Override |
|
| 3145 | + public Result<LeaderboardSearchResult> search(KeywordQuery query) { |
|
| 3146 | + long start = System.currentTimeMillis(); |
|
| 3147 | + logger.info("Searching local server for " + query); |
|
| 3148 | + Result<LeaderboardSearchResult> result = new RegattaByKeywordSearchService().search(this, query); |
|
| 3149 | + logger.fine("Search for " + query + " took " + (System.currentTimeMillis() - start) + "ms"); |
|
| 3150 | + return result; |
|
| 3151 | + } |
|
| 3152 | + |
|
| 3153 | + @Override |
|
| 3154 | + public Result<LeaderboardSearchResultBase> searchRemotely(String remoteServerReferenceName, KeywordQuery query) { |
|
| 3155 | + long start = System.currentTimeMillis(); |
|
| 3156 | + ResultImpl<LeaderboardSearchResultBase> result = null; |
|
| 3157 | + RemoteSailingServerReference remoteRef = remoteSailingServerSet |
|
| 3158 | + .getServerReferenceByName(remoteServerReferenceName); |
|
| 3159 | + if (remoteRef == null) { |
|
| 3160 | + result = null; |
|
| 3161 | + } else { |
|
| 3162 | + BufferedReader bufferedReader = null; |
|
| 3163 | + try { |
|
| 3164 | + try { |
|
| 3165 | + final URL eventsURL = new URL(remoteRef.getURL(), "sailingserver/api/v1/search?q=" |
|
| 3166 | + + URLEncoder.encode(query.toString(), "UTF-8")); |
|
| 3167 | + logger.info("Searching remote server " + remoteRef + " for " + query); |
|
| 3168 | + URLConnection urlConnection = eventsURL.openConnection(); |
|
| 3169 | + urlConnection.connect(); |
|
| 3170 | + bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); |
|
| 3171 | + JSONParser parser = new JSONParser(); |
|
| 3172 | + Object eventsAsObject = parser.parse(bufferedReader); |
|
| 3173 | + final LeaderboardGroupBaseJsonDeserializer leaderboardGroupBaseJsonDeserializer = new LeaderboardGroupBaseJsonDeserializer(); |
|
| 3174 | + LeaderboardSearchResultBaseJsonDeserializer deserializer = new LeaderboardSearchResultBaseJsonDeserializer( |
|
| 3175 | + new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer( |
|
| 3176 | + DomainFactory.INSTANCE)), leaderboardGroupBaseJsonDeserializer), |
|
| 3177 | + leaderboardGroupBaseJsonDeserializer); |
|
| 3178 | + result = new ResultImpl<LeaderboardSearchResultBase>(query, |
|
| 3179 | + new LeaderboardSearchResultBaseRanker<LeaderboardSearchResultBase>()); |
|
| 3180 | + JSONArray hitsAsJsonArray = (JSONArray) eventsAsObject; |
|
| 3181 | + for (Object hitAsObject : hitsAsJsonArray) { |
|
| 3182 | + JSONObject hitAsJson = (JSONObject) hitAsObject; |
|
| 3183 | + LeaderboardSearchResultBase hit = deserializer.deserialize(hitAsJson); |
|
| 3184 | + result.addHit(hit); |
|
| 3185 | + } |
|
| 3186 | + } finally { |
|
| 3187 | + if (bufferedReader != null) { |
|
| 3188 | + bufferedReader.close(); |
|
| 3189 | + } |
|
| 3190 | + } |
|
| 3191 | + } catch (IOException | ParseException e) { |
|
| 3192 | + logger.log(Level.INFO, |
|
| 3193 | + "Exception trying to fetch events from remote server " + remoteRef + ": " + e.getMessage(), e); |
|
| 3194 | + } |
|
| 3195 | + } |
|
| 3196 | + logger.fine("Remote search on " + remoteRef + " for " + query + " took " + (System.currentTimeMillis() - start) |
|
| 3197 | + + "ms"); |
|
| 3198 | + return result; |
|
| 3199 | + } |
|
| 3200 | + |
|
| 3201 | + @Override |
|
| 3202 | + public ReplicationMasterDescriptor getMasterDescriptor() { |
|
| 3203 | + return replicatingFromMaster; |
|
| 3204 | + } |
|
| 3205 | + |
|
| 3206 | + @Override |
|
| 3207 | + public void startedReplicatingFrom(ReplicationMasterDescriptor master) { |
|
| 3208 | + this.replicatingFromMaster = master; |
|
| 3209 | + } |
|
| 3210 | + |
|
| 3211 | + @Override |
|
| 3212 | + public void stoppedReplicatingFrom(ReplicationMasterDescriptor master) { |
|
| 3213 | + this.replicatingFromMaster = null; |
|
| 3214 | + } |
|
| 3215 | + |
|
| 3216 | + @Override |
|
| 3217 | + public void addOperationSentToMasterForReplication( |
|
| 3218 | + OperationWithResultWithIdWrapper<RacingEventService, ?> operationWithResultWithIdWrapper) { |
|
| 3219 | + this.operationsSentToMasterForReplication.add(operationWithResultWithIdWrapper); |
|
| 3220 | + } |
|
| 3221 | + |
|
| 3222 | + @Override |
|
| 3223 | + public boolean hasSentOperationToMaster(OperationWithResult<RacingEventService, ?> operation) { |
|
| 3224 | + return this.operationsSentToMasterForReplication.remove(operation); |
|
| 3225 | + } |
|
| 3226 | + |
|
| 3227 | + @Override |
|
| 3228 | + public FileStorageManagementService getFileStorageManagementService() { |
|
| 3229 | + ServiceReference<FileStorageManagementService> ref = bundleContext |
|
| 3230 | + .getServiceReference(FileStorageManagementService.class); |
|
| 3231 | + if (ref == null) { |
|
| 3232 | + logger.warning("No file storage management service registered"); |
|
| 3233 | + return null; |
|
| 3234 | + } |
|
| 3235 | + return bundleContext.getService(ref); |
|
| 3236 | + } |
|
| 3237 | + |
|
| 3238 | + public void addMasterDataClassLoader(ClassLoader classLoader) { |
|
| 3239 | + masterDataClassLoaders.add(classLoader); |
|
| 3240 | + } |
|
| 3241 | + |
|
| 3242 | + public void removeMasterDataClassLoader(ClassLoader classLoader) { |
|
| 3243 | + masterDataClassLoaders.remove(classLoader); |
|
| 3244 | + } |
|
| 3245 | + |
|
| 3246 | + @Override |
|
| 3247 | + public ClassLoader getCombinedMasterDataClassLoader() { |
|
| 3248 | + JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders); |
|
| 3249 | + return joinedClassLoader; |
|
| 3250 | + } |
|
| 3251 | + |
|
| 3252 | + public void setPolarDataService(PolarDataService service) { |
|
| 3253 | + if (this.polarDataService == null && service != null) { |
|
| 3254 | + polarDataService = service; |
|
| 3255 | + polarDataService.registerDomainFactory(baseDomainFactory); |
|
| 3256 | + setPolarDataServiceOnAllTrackedRaces(service); |
|
| 3257 | + } |
|
| 3258 | + } |
|
| 3259 | + |
|
| 3260 | + private void setPolarDataServiceOnAllTrackedRaces(PolarDataService service) { |
|
| 3261 | + Iterable<Regatta> allRegattas = getAllRegattas(); |
|
| 3262 | + for (Regatta regatta : allRegattas) { |
|
| 3263 | + DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta); |
|
| 3264 | + if (trackedRegatta != null) { |
|
| 3265 | + trackedRegatta.lockTrackedRacesForRead(); |
|
| 3266 | + try { |
|
| 3267 | + Iterable<DynamicTrackedRace> trackedRaces = trackedRegatta.getTrackedRaces(); |
|
| 3268 | + for (TrackedRace trackedRace : trackedRaces) { |
|
| 3269 | + trackedRace.setPolarDataService(service); |
|
| 3270 | + service.insertExistingFixes(trackedRace); |
|
| 3271 | + } |
|
| 3272 | + } finally { |
|
| 3273 | + trackedRegatta.unlockTrackedRacesAfterRead(); |
|
| 3274 | + } |
|
| 3275 | + } |
|
| 3276 | + } |
|
| 3277 | + } |
|
| 3278 | + |
|
| 3279 | + public void unsetPolarDataService(PolarDataService service) { |
|
| 3280 | + if (polarDataService == service) { |
|
| 3281 | + polarDataService.unregisterDomainFactory(baseDomainFactory); |
|
| 3282 | + polarDataService = null; |
|
| 3283 | + setPolarDataService(null); |
|
| 3284 | + } |
|
| 3285 | + } |
|
| 3286 | + |
|
| 3287 | + @Override |
|
| 3288 | + public Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) { |
|
| 3289 | + final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); |
|
| 3290 | + final List<Competitor> result = new ArrayList<>(); |
|
| 3291 | + final Map<Competitor, Distance> windwardDistanceSailedPerCompetitor = new HashMap<>(); |
|
| 3292 | + for (final Competitor competitor : trackedRace.getRace().getCompetitors()) { |
|
| 3293 | + result.add(competitor); |
|
| 3294 | + final CompetitorRankingInfo competitorRankingInfo = rankingInfo.getCompetitorRankingInfo().apply(competitor); |
|
| 3295 | + windwardDistanceSailedPerCompetitor.put(competitor, competitorRankingInfo == null ? null : competitorRankingInfo.getWindwardDistanceSailed()); |
|
| 3296 | + } |
|
| 3297 | + final Comparator<Distance> durationComparatorNullsLast = Comparator.nullsLast(Comparator.naturalOrder()); |
|
| 3298 | + result.sort((c1, c2) -> durationComparatorNullsLast.compare(windwardDistanceSailedPerCompetitor.get(c2), |
|
| 3299 | + windwardDistanceSailedPerCompetitor.get(c1))); |
|
| 3300 | + return result; |
|
| 3301 | + } |
|
| 3302 | + |
|
| 3303 | + /** |
|
| 3304 | + * A {@link SimpleRaceLogIdentifier} in particular has a {@link SimpleRaceLogIdentifier#getRegattaLikeParentName()} |
|
| 3305 | + * which identifies either a regatta by name or a flexible leaderboard by name. Here is why this can luckily be |
|
| 3306 | + * resolved unanimously: A regatta leaderboard always uses as its name the regatta name (see |
|
| 3307 | + * {@link RegattaImpl#getName()}). Trying to {@link RegattaLeaderboardImpl#setName(String) set} the regatta leaderboard's |
|
| 3308 | + * name can only update its {@link Leaderboard#getDisplayName() display name}. Therefore, regatta leaderboards are always |
|
| 3309 | + * keyed in {@link #leaderboardsByName} by their regatta's name. Thus, no flexible leaderboard can have a regatta's name |
|
| 3310 | + * as its name, and therefore leaderboard names <em>and</em> regatta names are unitedly unique. |
|
| 3311 | + */ |
|
| 3312 | + @Override |
|
| 3313 | + public RaceLog resolve(SimpleRaceLogIdentifier identifier) { |
|
| 3314 | + final RaceLog result; |
|
| 3315 | + final IsRegattaLike regattaLike; |
|
| 3316 | + final Regatta regatta = regattasByName.get(identifier.getRegattaLikeParentName()); |
|
| 3317 | + if (regatta != null) { |
|
| 3318 | + regattaLike = regatta; |
|
| 3319 | + } else { |
|
| 3320 | + final Leaderboard leaderboard = leaderboardsByName.get(identifier.getRegattaLikeParentName()); |
|
| 3321 | + if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) { |
|
| 3322 | + regattaLike = (FlexibleLeaderboard) leaderboard; |
|
| 3323 | + } else { |
|
| 3324 | + regattaLike = null; |
|
| 3325 | + } |
|
| 3326 | + } |
|
| 3327 | + if (regattaLike != null) { |
|
| 3328 | + final RaceColumn raceColumn = regattaLike.getRaceColumnByName(identifier.getRaceColumnName()); |
|
| 3329 | + if (raceColumn != null) { |
|
| 3330 | + final Fleet fleet = raceColumn.getFleetByName(identifier.getFleetName()); |
|
| 3331 | + if (fleet != null) { |
|
| 3332 | + result = raceColumn.getRaceLog(fleet); |
|
| 3333 | + } else { |
|
| 3334 | + result = null; |
|
| 3335 | + } |
|
| 3336 | + } else { |
|
| 3337 | + result = null; |
|
| 3338 | + } |
|
| 3339 | + } else { |
|
| 3340 | + result = null; |
|
| 3341 | + } |
|
| 3342 | + return result; |
|
| 3343 | + } |
|
| 3344 | +} |
java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java
| ... | ... | @@ -1,70 +1,70 @@ |
| 1 | -package com.sap.sailing.server.operationaltransformation;
|
|
| 2 | -
|
|
| 3 | -import java.net.URL;
|
|
| 4 | -import java.util.UUID;
|
|
| 5 | -
|
|
| 6 | -import com.sap.sailing.domain.base.Event;
|
|
| 7 | -import com.sap.sailing.server.RacingEventService;
|
|
| 8 | -import com.sap.sailing.server.RacingEventServiceOperation;
|
|
| 9 | -import com.sap.sse.common.TimePoint;
|
|
| 10 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 11 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 12 | -
|
|
| 13 | -/**
|
|
| 14 | - * Creates an {@link Event} in the server, with a new venue and an empty course area list.
|
|
| 15 | - * See the {@link AddCourseAreas} operation for adding course areas to the event's venue.
|
|
| 16 | - *
|
|
| 17 | - * @author Axel Uhl (d043530)
|
|
| 18 | - *
|
|
| 19 | - */
|
|
| 20 | -public class CreateEvent extends AbstractEventOperation<Event> {
|
|
| 21 | - private static final long serialVersionUID = 308389324918359960L;
|
|
| 22 | - private final String venue;
|
|
| 23 | - private final TimePoint startDate;
|
|
| 24 | - private final TimePoint endDate;
|
|
| 25 | - private final boolean isPublic;
|
|
| 26 | - private final String eventName;
|
|
| 27 | - private final String eventDescription;
|
|
| 28 | - private final Iterable<ImageDescriptor> images;
|
|
| 29 | - private final Iterable<VideoDescriptor> videos;
|
|
| 30 | - private final URL officialWebsiteURL;
|
|
| 31 | - private final URL sailorsInfoWebsiteURL;
|
|
| 32 | -
|
|
| 33 | - public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue,
|
|
| 34 | - boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
|
|
| 35 | - super(id);
|
|
| 36 | - this.eventName = eventName;
|
|
| 37 | - this.eventDescription = eventDescription;
|
|
| 38 | - this.startDate = startDate;
|
|
| 39 | - this.endDate = endDate;
|
|
| 40 | - this.venue = venue;
|
|
| 41 | - this.isPublic = isPublic;
|
|
| 42 | - this.officialWebsiteURL = officialWebsiteURL;
|
|
| 43 | - this.sailorsInfoWebsiteURL = sailorsInfoWebsiteURL;
|
|
| 44 | - this.images = images;
|
|
| 45 | - this.videos = videos;
|
|
| 46 | - }
|
|
| 47 | -
|
|
| 48 | - @Override
|
|
| 49 | - public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
|
|
| 50 | - // TODO Auto-generated method stub
|
|
| 51 | - return null;
|
|
| 52 | - }
|
|
| 53 | -
|
|
| 54 | - @Override
|
|
| 55 | - public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
|
|
| 56 | - // TODO Auto-generated method stub
|
|
| 57 | - return null;
|
|
| 58 | - }
|
|
| 59 | -
|
|
| 60 | - protected String getEventName() {
|
|
| 61 | - return eventName;
|
|
| 62 | - }
|
|
| 63 | -
|
|
| 64 | - @Override
|
|
| 65 | - public Event internalApplyTo(RacingEventService toState) {
|
|
| 66 | - return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic,
|
|
| 67 | - getId(), officialWebsiteURL, sailorsInfoWebsiteURL, images, videos);
|
|
| 68 | - }
|
|
| 69 | -
|
|
| 70 | -}
|
|
| 1 | +package com.sap.sailing.server.operationaltransformation; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | +import java.util.UUID; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.domain.base.Event; |
|
| 7 | +import com.sap.sailing.server.RacingEventService; |
|
| 8 | +import com.sap.sailing.server.RacingEventServiceOperation; |
|
| 9 | +import com.sap.sse.common.TimePoint; |
|
| 10 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 11 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 12 | + |
|
| 13 | +/** |
|
| 14 | + * Creates an {@link Event} in the server, with a new venue and an empty course area list. |
|
| 15 | + * See the {@link AddCourseAreas} operation for adding course areas to the event's venue. |
|
| 16 | + * |
|
| 17 | + * @author Axel Uhl (d043530) |
|
| 18 | + * |
|
| 19 | + */ |
|
| 20 | +public class CreateEvent extends AbstractEventOperation<Event> { |
|
| 21 | + private static final long serialVersionUID = 308389324918359960L; |
|
| 22 | + private final String venue; |
|
| 23 | + private final TimePoint startDate; |
|
| 24 | + private final TimePoint endDate; |
|
| 25 | + private final boolean isPublic; |
|
| 26 | + private final String eventName; |
|
| 27 | + private final String eventDescription; |
|
| 28 | + private final Iterable<ImageDescriptor> images; |
|
| 29 | + private final Iterable<VideoDescriptor> videos; |
|
| 30 | + private final URL officialWebsiteURL; |
|
| 31 | + private final URL sailorsInfoWebsiteURL; |
|
| 32 | + |
|
| 33 | + public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, |
|
| 34 | + boolean isPublic, UUID id, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) { |
|
| 35 | + super(id); |
|
| 36 | + this.eventName = eventName; |
|
| 37 | + this.eventDescription = eventDescription; |
|
| 38 | + this.startDate = startDate; |
|
| 39 | + this.endDate = endDate; |
|
| 40 | + this.venue = venue; |
|
| 41 | + this.isPublic = isPublic; |
|
| 42 | + this.officialWebsiteURL = officialWebsiteURL; |
|
| 43 | + this.sailorsInfoWebsiteURL = sailorsInfoWebsiteURL; |
|
| 44 | + this.images = images; |
|
| 45 | + this.videos = videos; |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | + @Override |
|
| 49 | + public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) { |
|
| 50 | + // TODO Auto-generated method stub |
|
| 51 | + return null; |
|
| 52 | + } |
|
| 53 | + |
|
| 54 | + @Override |
|
| 55 | + public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) { |
|
| 56 | + // TODO Auto-generated method stub |
|
| 57 | + return null; |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + protected String getEventName() { |
|
| 61 | + return eventName; |
|
| 62 | + } |
|
| 63 | + |
|
| 64 | + @Override |
|
| 65 | + public Event internalApplyTo(RacingEventService toState) { |
|
| 66 | + return toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic, |
|
| 67 | + getId(), officialWebsiteURL, sailorsInfoWebsiteURL, images, videos); |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | +} |
java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java
| ... | ... | @@ -1,61 +1,61 @@ |
| 1 | -package com.sap.sailing.server.operationaltransformation;
|
|
| 2 | -
|
|
| 3 | -import java.net.URL;
|
|
| 4 | -import java.util.UUID;
|
|
| 5 | -
|
|
| 6 | -import com.sap.sailing.server.RacingEventService;
|
|
| 7 | -import com.sap.sailing.server.RacingEventServiceOperation;
|
|
| 8 | -import com.sap.sse.common.TimePoint;
|
|
| 9 | -import com.sap.sse.common.media.ImageDescriptor;
|
|
| 10 | -import com.sap.sse.common.media.VideoDescriptor;
|
|
| 11 | -
|
|
| 12 | -public class UpdateEvent extends AbstractEventOperation<Void> {
|
|
| 13 | - private static final long serialVersionUID = -8271559266421161532L;
|
|
| 14 | - private final String venueName;
|
|
| 15 | - private final TimePoint startDate;
|
|
| 16 | - private final TimePoint endDate;
|
|
| 17 | - private final boolean isPublic;
|
|
| 18 | - private final Iterable<UUID> leaderboardGroupIds;
|
|
| 19 | - private final String eventName;
|
|
| 20 | - private final String eventDescription;
|
|
| 21 | - private final URL officialWebsiteURL;
|
|
| 22 | - private final URL sailorsInfoWebsiteURL;
|
|
| 23 | - private final Iterable<ImageDescriptor> images;
|
|
| 24 | - private final Iterable<VideoDescriptor> videos;
|
|
| 25 | -
|
|
| 26 | - public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate,
|
|
| 27 | - String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL,
|
|
| 28 | - Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) {
|
|
| 29 | - super(id);
|
|
| 30 | - this.eventName = eventName;
|
|
| 31 | - this.eventDescription = eventDescription;
|
|
| 32 | - this.startDate = startDate;
|
|
| 33 | - this.endDate = endDate;
|
|
| 34 | - this.venueName = venueName;
|
|
| 35 | - this.isPublic = isPublic;
|
|
| 36 | - this.leaderboardGroupIds = leaderboardGroupIds;
|
|
| 37 | - this.officialWebsiteURL = officialWebsiteURL;
|
|
| 38 | - this.sailorsInfoWebsiteURL = sailorsInfoWebsiteURL;
|
|
| 39 | - this.images = images;
|
|
| 40 | - this.videos = videos;
|
|
| 41 | - }
|
|
| 42 | -
|
|
| 43 | - @Override
|
|
| 44 | - public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) {
|
|
| 45 | - // TODO Auto-generated method stub
|
|
| 46 | - return null;
|
|
| 47 | - }
|
|
| 48 | -
|
|
| 49 | - @Override
|
|
| 50 | - public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) {
|
|
| 51 | - // TODO Auto-generated method stub
|
|
| 52 | - return null;
|
|
| 53 | - }
|
|
| 54 | -
|
|
| 55 | - @Override
|
|
| 56 | - public Void internalApplyTo(RacingEventService toState) {
|
|
| 57 | - toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic,
|
|
| 58 | - leaderboardGroupIds, officialWebsiteURL, sailorsInfoWebsiteURL, images, videos);
|
|
| 59 | - return null;
|
|
| 60 | - }
|
|
| 61 | -}
|
|
| 1 | +package com.sap.sailing.server.operationaltransformation; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | +import java.util.UUID; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.server.RacingEventService; |
|
| 7 | +import com.sap.sailing.server.RacingEventServiceOperation; |
|
| 8 | +import com.sap.sse.common.TimePoint; |
|
| 9 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 10 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 11 | + |
|
| 12 | +public class UpdateEvent extends AbstractEventOperation<Void> { |
|
| 13 | + private static final long serialVersionUID = -8271559266421161532L; |
|
| 14 | + private final String venueName; |
|
| 15 | + private final TimePoint startDate; |
|
| 16 | + private final TimePoint endDate; |
|
| 17 | + private final boolean isPublic; |
|
| 18 | + private final Iterable<UUID> leaderboardGroupIds; |
|
| 19 | + private final String eventName; |
|
| 20 | + private final String eventDescription; |
|
| 21 | + private final URL officialWebsiteURL; |
|
| 22 | + private final URL sailorsInfoWebsiteURL; |
|
| 23 | + private final Iterable<ImageDescriptor> images; |
|
| 24 | + private final Iterable<VideoDescriptor> videos; |
|
| 25 | + |
|
| 26 | + public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, |
|
| 27 | + String venueName, boolean isPublic, Iterable<UUID> leaderboardGroupIds, URL officialWebsiteURL, URL sailorsInfoWebsiteURL, |
|
| 28 | + Iterable<ImageDescriptor> images, Iterable<VideoDescriptor> videos) { |
|
| 29 | + super(id); |
|
| 30 | + this.eventName = eventName; |
|
| 31 | + this.eventDescription = eventDescription; |
|
| 32 | + this.startDate = startDate; |
|
| 33 | + this.endDate = endDate; |
|
| 34 | + this.venueName = venueName; |
|
| 35 | + this.isPublic = isPublic; |
|
| 36 | + this.leaderboardGroupIds = leaderboardGroupIds; |
|
| 37 | + this.officialWebsiteURL = officialWebsiteURL; |
|
| 38 | + this.sailorsInfoWebsiteURL = sailorsInfoWebsiteURL; |
|
| 39 | + this.images = images; |
|
| 40 | + this.videos = videos; |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + @Override |
|
| 44 | + public RacingEventServiceOperation<?> transformClientOp(RacingEventServiceOperation<?> serverOp) { |
|
| 45 | + // TODO Auto-generated method stub |
|
| 46 | + return null; |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + @Override |
|
| 50 | + public RacingEventServiceOperation<?> transformServerOp(RacingEventServiceOperation<?> clientOp) { |
|
| 51 | + // TODO Auto-generated method stub |
|
| 52 | + return null; |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + @Override |
|
| 56 | + public Void internalApplyTo(RacingEventService toState) { |
|
| 57 | + toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic, |
|
| 58 | + leaderboardGroupIds, officialWebsiteURL, sailorsInfoWebsiteURL, images, videos); |
|
| 59 | + return null; |
|
| 60 | + } |
|
| 61 | +} |
java/com.sap.sailing.targetplatform.base/features/target-jackson/feature.xml
| ... | ... | @@ -62,14 +62,14 @@ |
| 62 | 62 | unpack="false"/> |
| 63 | 63 | |
| 64 | 64 | <plugin |
| 65 | - id="jackson-core-lgpl" |
|
| 65 | + id="jackson-core-asl" |
|
| 66 | 66 | download-size="0" |
| 67 | 67 | install-size="0" |
| 68 | 68 | version="1.9.13" |
| 69 | 69 | unpack="false"/> |
| 70 | 70 | |
| 71 | 71 | <plugin |
| 72 | - id="jackson-mapper-lgpl" |
|
| 72 | + id="jackson-mapper-asl" |
|
| 73 | 73 | download-size="0" |
| 74 | 74 | install-size="0" |
| 75 | 75 | version="1.9.13" |
java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-asl-1.9.13.jar
| ... | ... | Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-asl-1.9.13.jar differ |
java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-lgpl-1.9.13.jar
| ... | ... | Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-lgpl-1.9.13.jar and /dev/null differ |
java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-mapper-asl-1.9.13.jar
| ... | ... | Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-mapper-asl-1.9.13.jar differ |
java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-mapper-lgpl-1.9.13.jar
| ... | ... | Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-mapper-lgpl-1.9.13.jar and /dev/null differ |
java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-remote.target
| ... | ... | @@ -14,8 +14,8 @@ |
| 14 | 14 | <repository location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.2.v20140723/"/> |
| 15 | 15 | </location> |
| 16 | 16 | <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="slicer" includeSource="true" type="InstallableUnit"> |
| 17 | -<unit id="org.eclipse.osgi" version="3.10.1.v20140909-1633"/> |
|
| 18 | -<unit id="org.eclipse.osgi.source" version="3.10.1.v20140909-1633"/> |
|
| 17 | +<unit id="org.eclipse.osgi" version="3.10.2.v20150203-1939"/> |
|
| 18 | +<unit id="org.eclipse.osgi.source" version="3.10.2.v20150203-1939"/> |
|
| 19 | 19 | <unit id="org.eclipse.osgi.services" version="3.4.0.v20140312-2051"/> |
| 20 | 20 | <unit id="org.eclipse.osgi.services.source" version="3.4.0.v20140312-2051"/> |
| 21 | 21 | <unit id="org.eclipse.equinox.common" version="3.6.200.v20130402-1505"/> |
| ... | ... | @@ -82,9 +82,9 @@ |
| 82 | 82 | <plugin id="com.sun.jersey.contribs.jersey-multipart"/> |
| 83 | 83 | <plugin id="com.sun.jersey.source"/> |
| 84 | 84 | <plugin id="com.sun.mail.javax.mail"/> |
| 85 | -<plugin id="jackson-core-lgpl"/> |
|
| 85 | +<plugin id="jackson-core-asl"/> |
|
| 86 | 86 | <plugin id="jackson-jaxrs"/> |
| 87 | -<plugin id="jackson-mapper-lgpl"/> |
|
| 87 | +<plugin id="jackson-mapper-asl"/> |
|
| 88 | 88 | <plugin id="javax.security.auth.message"/> |
| 89 | 89 | <plugin id="javax.security.auth.message.source"/> |
| 90 | 90 | <plugin id="javax.servlet" version="3.1.0.v20140303-1611"/> |
| ... | ... | @@ -95,6 +95,7 @@ |
| 95 | 95 | <plugin id="javax.ws.rs.source"/> |
| 96 | 96 | <plugin id="jcl.over.slf4j"/> |
| 97 | 97 | <plugin id="jul.to.slf4j"/> |
| 98 | +<plugin id="lz4-java"/> |
|
| 98 | 99 | <plugin id="org.apache.commons.beanutils"/> |
| 99 | 100 | <plugin id="org.apache.commons.beanutils.source"/> |
| 100 | 101 | <plugin id="org.apache.commons.codec"/> |
| ... | ... | @@ -239,7 +240,6 @@ |
| 239 | 240 | <plugin id="routeconverter"/> |
| 240 | 241 | <plugin id="slf4j.api"/> |
| 241 | 242 | <plugin id="slf4j.jdk14"/> |
| 242 | -<plugin id="lz4-java"/> |
|
| 243 | 243 | </includeBundles> |
| 244 | 244 | <targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
| 245 | 245 | </target> |
java/com.sap.sailing.targetplatform/scripts/uploadRepositoryToServer.sh
| ... | ... | @@ -22,8 +22,7 @@ echo "Uploading local repository to $REPO_HOME/sailing" |
| 22 | 22 | scp -r ../../com.sap.sailing.targetplatform.base/target/repository $USER@$SERVER:$REPO_HOME/sailing |
| 23 | 23 | |
| 24 | 24 | echo "Making readable for everyone..." |
| 25 | -ssh $USER@$SERVER "chmod -R a+r $REPO_HOME/sailing" |
|
| 26 | -ssh $USER@$SERVER "chmod -R a+x $REPO_HOME/sailing" |
|
| 25 | +ssh $USER@$SERVER "chmod -R 775 . $REPO_HOME/sailing" |
|
| 27 | 26 | |
| 28 | 27 | echo "Remote files now available:" |
| 29 | 28 | ssh $USER@$SERVER "ls -lah $REPO_HOME/sailing" |
java/com.sap.sse.common/pom.xml
| ... | ... | @@ -11,30 +11,30 @@ |
| 11 | 11 | <packaging>eclipse-plugin</packaging> |
| 12 | 12 | |
| 13 | 13 | <build> |
| 14 | - <plugins> |
|
| 15 | - <plugin> |
|
| 16 | - <groupId>org.eclipse.tycho</groupId> |
|
| 17 | - <artifactId>tycho-compiler-plugin</artifactId> |
|
| 18 | - <version>${tycho-version}</version> |
|
| 19 | - <configuration> |
|
| 20 | - <source>1.7</source> |
|
| 21 | - <target>1.7</target> |
|
| 22 | - </configuration> |
|
| 23 | - </plugin> |
|
| 24 | - <plugin> |
|
| 25 | - <groupId>org.eclipse.tycho</groupId> |
|
| 26 | - <artifactId>tycho-source-plugin</artifactId> |
|
| 27 | - <version>${tycho-version}</version> |
|
| 28 | - <executions> |
|
| 29 | - <execution> |
|
| 30 | - <id>plugin-source</id> |
|
| 31 | - <phase>generate-sources</phase> |
|
| 32 | - <goals> |
|
| 33 | - <goal>plugin-source</goal> |
|
| 34 | - </goals> |
|
| 35 | - </execution> |
|
| 36 | - </executions> |
|
| 37 | - </plugin> |
|
| 38 | - </plugins> |
|
| 14 | + <plugins> |
|
| 15 | + <plugin> |
|
| 16 | + <groupId>org.eclipse.tycho</groupId> |
|
| 17 | + <artifactId>tycho-compiler-plugin</artifactId> |
|
| 18 | + <version>${tycho-version}</version> |
|
| 19 | + <configuration> |
|
| 20 | + <source>1.7</source> |
|
| 21 | + <target>1.7</target> |
|
| 22 | + </configuration> |
|
| 23 | + </plugin> |
|
| 24 | + <plugin> |
|
| 25 | + <groupId>org.eclipse.tycho</groupId> |
|
| 26 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 27 | + <version>${tycho-version}</version> |
|
| 28 | + <executions> |
|
| 29 | + <execution> |
|
| 30 | + <id>plugin-source</id> |
|
| 31 | + <phase>generate-sources</phase> |
|
| 32 | + <goals> |
|
| 33 | + <goal>plugin-source</goal> |
|
| 34 | + </goals> |
|
| 35 | + </execution> |
|
| 36 | + </executions> |
|
| 37 | + </plugin> |
|
| 38 | + </plugins> |
|
| 39 | 39 | </build> |
| 40 | 40 | </project> |
java/com.sap.sse.common/src/com/sap/sse/common/Util.java
| ... | ... | @@ -22,114 +22,120 @@ public class Util { |
| 22 | 22 | |
| 23 | 23 | private transient int hashCode;
|
| 24 | 24 | |
| 25 | - @SuppressWarnings("unused") // required for some serialization frameworks such as GWT RPC
|
|
| 26 | - private Pair() {}
|
|
| 27 | -
|
|
| 28 | - public Pair( A a, B b ) {
|
|
| 25 | + @SuppressWarnings("unused")
|
|
| 26 | + // required for some serialization frameworks such as GWT RPC
|
|
| 27 | + private Pair() {
|
|
| 28 | + }
|
|
| 29 | +
|
|
| 30 | + public Pair(A a, B b) {
|
|
| 29 | 31 | this.a = a;
|
| 30 | 32 | this.b = b;
|
| 31 | 33 | hashCode = 0;
|
| 32 | 34 | }
|
| 33 | -
|
|
| 34 | - public A getA( ) {
|
|
| 35 | +
|
|
| 36 | + public A getA() {
|
|
| 35 | 37 | return a;
|
| 36 | 38 | }
|
| 37 | -
|
|
| 38 | - public B getB( ) {
|
|
| 39 | +
|
|
| 40 | + public B getB() {
|
|
| 39 | 41 | return b;
|
| 40 | 42 | }
|
| 41 | -
|
|
| 43 | +
|
|
| 42 | 44 | @Override
|
| 43 | - public int hashCode( ) {
|
|
| 44 | - if ( hashCode == 0 ) {
|
|
| 45 | + public int hashCode() {
|
|
| 46 | + if (hashCode == 0) {
|
|
| 45 | 47 | hashCode = 17;
|
| 46 | - hashCode = 37 * hashCode + ( a != null ? a.hashCode( ) : 0 );
|
|
| 47 | - hashCode = 37 * hashCode + ( b != null ? b.hashCode( ) : 0 );
|
|
| 48 | + hashCode = 37 * hashCode + (a != null ? a.hashCode() : 0);
|
|
| 49 | + hashCode = 37 * hashCode + (b != null ? b.hashCode() : 0);
|
|
| 48 | 50 | }
|
| 49 | 51 | return hashCode;
|
| 50 | 52 | }
|
| 51 | -
|
|
| 53 | +
|
|
| 52 | 54 | @Override
|
| 53 | - public boolean equals( Object obj ) {
|
|
| 55 | + public boolean equals(Object obj) {
|
|
| 54 | 56 | boolean result;
|
| 55 | - if ( this == obj ) {
|
|
| 57 | + if (this == obj) {
|
|
| 56 | 58 | result = true;
|
| 57 | - } else if ( obj instanceof Pair<?, ?> ) {
|
|
| 59 | + } else if (obj instanceof Pair<?, ?>) {
|
|
| 58 | 60 | Pair<?, ?> pair = (Pair<?, ?>) obj;
|
| 59 | - result = ( this.a != null && this.a.equals( pair.a ) || this.a == null && pair.a == null ) && ( this.b != null && this.b.equals( pair.b ) || this.b == null && pair.b == null );
|
|
| 61 | + result = (this.a != null && this.a.equals(pair.a) || this.a == null && pair.a == null)
|
|
| 62 | + && (this.b != null && this.b.equals(pair.b) || this.b == null && pair.b == null);
|
|
| 60 | 63 | } else {
|
| 61 | 64 | result = false;
|
| 62 | 65 | }
|
| 63 | 66 | return result;
|
| 64 | 67 | }
|
| 65 | -
|
|
| 68 | +
|
|
| 66 | 69 | @Override
|
| 67 | - public String toString( ) {
|
|
| 68 | - return "[" + (a==null?"null":a.toString( )) + ", " +
|
|
| 69 | - (b==null?"null":b.toString( )) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
|
| 70 | + public String toString() {
|
|
| 71 | + return "[" + (a == null ? "null" : a.toString()) + ", " + (b == null ? "null" : b.toString()) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
|
| 70 | 72 | }
|
| 71 | 73 | }
|
| 72 | 74 | |
| 73 | 75 | public static class Triple<A, B, C> implements Serializable {
|
| 74 | 76 | private static final long serialVersionUID = 6806146864367514601L;
|
| 75 | -
|
|
| 77 | +
|
|
| 76 | 78 | private A a;
|
| 77 | -
|
|
| 79 | +
|
|
| 78 | 80 | private B b;
|
| 79 | -
|
|
| 81 | +
|
|
| 80 | 82 | private C c;
|
| 81 | -
|
|
| 83 | +
|
|
| 82 | 84 | private transient int hashCode;
|
| 83 | -
|
|
| 84 | - @SuppressWarnings("unused") // required for some serialization frameworks such as GWT RPC
|
|
| 85 | - private Triple() {}
|
|
| 86 | -
|
|
| 87 | - public Triple( A a, B b, C c ) {
|
|
| 85 | +
|
|
| 86 | + @SuppressWarnings("unused")
|
|
| 87 | + // required for some serialization frameworks such as GWT RPC
|
|
| 88 | + private Triple() {
|
|
| 89 | + }
|
|
| 90 | +
|
|
| 91 | + public Triple(A a, B b, C c) {
|
|
| 88 | 92 | this.a = a;
|
| 89 | 93 | this.b = b;
|
| 90 | 94 | this.c = c;
|
| 91 | 95 | hashCode = 0;
|
| 92 | 96 | }
|
| 93 | -
|
|
| 94 | - public A getA( ) {
|
|
| 97 | +
|
|
| 98 | + public A getA() {
|
|
| 95 | 99 | return a;
|
| 96 | 100 | }
|
| 97 | -
|
|
| 98 | - public B getB( ) {
|
|
| 101 | +
|
|
| 102 | + public B getB() {
|
|
| 99 | 103 | return b;
|
| 100 | 104 | }
|
| 101 | -
|
|
| 102 | - public C getC( ) {
|
|
| 105 | +
|
|
| 106 | + public C getC() {
|
|
| 103 | 107 | return c;
|
| 104 | 108 | }
|
| 105 | -
|
|
| 109 | +
|
|
| 106 | 110 | @Override
|
| 107 | - public int hashCode( ) {
|
|
| 108 | - if ( hashCode == 0 ) {
|
|
| 111 | + public int hashCode() {
|
|
| 112 | + if (hashCode == 0) {
|
|
| 109 | 113 | hashCode = 17;
|
| 110 | - hashCode = 37 * hashCode + ( a != null ? a.hashCode( ) : 0 );
|
|
| 111 | - hashCode = 37 * hashCode + ( b != null ? b.hashCode( ) : 0 );
|
|
| 112 | - hashCode = 37 * hashCode + ( c != null ? c.hashCode( ) : 0 );
|
|
| 114 | + hashCode = 37 * hashCode + (a != null ? a.hashCode() : 0);
|
|
| 115 | + hashCode = 37 * hashCode + (b != null ? b.hashCode() : 0);
|
|
| 116 | + hashCode = 37 * hashCode + (c != null ? c.hashCode() : 0);
|
|
| 113 | 117 | }
|
| 114 | 118 | return hashCode;
|
| 115 | 119 | }
|
| 116 | -
|
|
| 120 | +
|
|
| 117 | 121 | @Override
|
| 118 | - public boolean equals( Object obj ) {
|
|
| 122 | + public boolean equals(Object obj) {
|
|
| 119 | 123 | boolean result;
|
| 120 | - if ( this == obj ) {
|
|
| 124 | + if (this == obj) {
|
|
| 121 | 125 | result = true;
|
| 122 | - } else if ( obj instanceof Triple<?, ?, ?> ) {
|
|
| 126 | + } else if (obj instanceof Triple<?, ?, ?>) {
|
|
| 123 | 127 | Triple<?, ?, ?> thrice = (Triple<?, ?, ?>) obj;
|
| 124 | - result = ( this.a != null && this.a.equals( thrice.a ) || this.a == null && thrice.a == null ) && ( this.b != null && this.b.equals( thrice.b ) || this.b == null && thrice.b == null ) && ( this.c != null && this.c.equals( thrice.c ) || this.c == null && thrice.c == null );
|
|
| 128 | + result = (this.a != null && this.a.equals(thrice.a) || this.a == null && thrice.a == null)
|
|
| 129 | + && (this.b != null && this.b.equals(thrice.b) || this.b == null && thrice.b == null)
|
|
| 130 | + && (this.c != null && this.c.equals(thrice.c) || this.c == null && thrice.c == null);
|
|
| 125 | 131 | } else {
|
| 126 | 132 | result = false;
|
| 127 | 133 | }
|
| 128 | 134 | return result;
|
| 129 | 135 | }
|
| 130 | -
|
|
| 136 | +
|
|
| 131 | 137 | @Override
|
| 132 | - public String toString( ) {
|
|
| 138 | + public String toString() {
|
|
| 133 | 139 | return "[" + a + ", " + b + ", " + c + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
| 134 | 140 | }
|
| 135 | 141 | }
|
java/com.sap.sse.common/src/com/sap/sse/common/media/AbstractMediaDescriptor.java
| ... | ... | @@ -1,136 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.io.Serializable; |
|
| 4 | -import java.net.URL; |
|
| 5 | -import java.util.LinkedHashSet; |
|
| 6 | -import java.util.Locale; |
|
| 7 | -import java.util.Set; |
|
| 8 | - |
|
| 9 | -import com.sap.sse.common.TimePoint; |
|
| 10 | -import com.sap.sse.common.Util; |
|
| 11 | - |
|
| 12 | -/** |
|
| 13 | - * Common media data for media items |
|
| 14 | - * |
|
| 15 | - * @author pgtaboada |
|
| 16 | - * |
|
| 17 | - */ |
|
| 18 | -public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serializable { |
|
| 19 | - private static final long serialVersionUID = -6671425870632517274L; |
|
| 20 | - |
|
| 21 | - protected String title; |
|
| 22 | - |
|
| 23 | - protected String subtitle; |
|
| 24 | - |
|
| 25 | - protected TimePoint createdAtDate; |
|
| 26 | - |
|
| 27 | - protected String copyright; |
|
| 28 | - |
|
| 29 | - protected MimeType mimeType; |
|
| 30 | - |
|
| 31 | - protected Set<String> tags = new LinkedHashSet<String>(); |
|
| 32 | - |
|
| 33 | - protected URL url; |
|
| 34 | - |
|
| 35 | - protected Locale locale; |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * Media item with minimal set of information |
|
| 39 | - * @param url |
|
| 40 | - * @param mimeType |
|
| 41 | - */ |
|
| 42 | - public AbstractMediaDescriptor(URL url, MimeType mimeType, TimePoint createdAtDate) { |
|
| 43 | - this.mimeType = mimeType; |
|
| 44 | - this.url = url; |
|
| 45 | - this.createdAtDate = createdAtDate; |
|
| 46 | - } |
|
| 47 | - |
|
| 48 | - @Override |
|
| 49 | - public MimeType getMimeType() { |
|
| 50 | - return mimeType; |
|
| 51 | - } |
|
| 52 | - |
|
| 53 | - @Override |
|
| 54 | - public URL getURL() { |
|
| 55 | - return url; |
|
| 56 | - } |
|
| 57 | - |
|
| 58 | - @Override |
|
| 59 | - public String getTitle() { |
|
| 60 | - return title; |
|
| 61 | - } |
|
| 62 | - |
|
| 63 | - @Override |
|
| 64 | - public void setTitle(String title) { |
|
| 65 | - this.title = title; |
|
| 66 | - } |
|
| 67 | - |
|
| 68 | - @Override |
|
| 69 | - public Set<String> getTags() { |
|
| 70 | - return tags; |
|
| 71 | - } |
|
| 72 | - |
|
| 73 | - @Override |
|
| 74 | - public void setTags(Iterable<String> tags) { |
|
| 75 | - this.tags.clear(); |
|
| 76 | - if (tags != null) { |
|
| 77 | - Util.addAll(tags, this.tags); |
|
| 78 | - } |
|
| 79 | - } |
|
| 80 | - |
|
| 81 | - |
|
| 82 | - @Override |
|
| 83 | - public boolean addTag(String tagName) { |
|
| 84 | - return tags.add(tagName); |
|
| 85 | - } |
|
| 86 | - |
|
| 87 | - @Override |
|
| 88 | - public boolean removeTag(String tagName) { |
|
| 89 | - return tags.remove(tagName); |
|
| 90 | - } |
|
| 91 | - |
|
| 92 | - @Override |
|
| 93 | - public String getSubtitle() { |
|
| 94 | - return subtitle; |
|
| 95 | - } |
|
| 96 | - |
|
| 97 | - @Override |
|
| 98 | - public void setSubtitle(String subtitle) { |
|
| 99 | - this.subtitle = subtitle; |
|
| 100 | - } |
|
| 101 | - |
|
| 102 | - @Override |
|
| 103 | - public TimePoint getCreatedAtDate() { |
|
| 104 | - return createdAtDate; |
|
| 105 | - } |
|
| 106 | - |
|
| 107 | - @Override |
|
| 108 | - public void setCreatedAtDate(TimePoint createdAtDate) { |
|
| 109 | - this.createdAtDate = createdAtDate; |
|
| 110 | - } |
|
| 111 | - |
|
| 112 | - @Override |
|
| 113 | - public String getCopyright() { |
|
| 114 | - return copyright; |
|
| 115 | - } |
|
| 116 | - |
|
| 117 | - @Override |
|
| 118 | - public void setCopyright(String copyright) { |
|
| 119 | - this.copyright = copyright; |
|
| 120 | - } |
|
| 121 | - |
|
| 122 | - @Override |
|
| 123 | - public Locale getLocale() { |
|
| 124 | - return locale; |
|
| 125 | - } |
|
| 126 | - |
|
| 127 | - @Override |
|
| 128 | - public void setLocale(Locale locale) { |
|
| 129 | - this.locale = locale; |
|
| 130 | - } |
|
| 131 | - |
|
| 132 | - @Override |
|
| 133 | - public boolean hasTag(String tagName) { |
|
| 134 | - return tags.contains(tagName); |
|
| 135 | - } |
|
| 136 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptor.java
| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import com.sap.sse.common.Util.Pair; |
|
| 4 | - |
|
| 5 | -public interface ImageDescriptor extends MediaDescriptor { |
|
| 6 | - void setSize(Pair<Integer, Integer> size); |
|
| 7 | - void setSize(Integer widthInPx, Integer heightInPx); |
|
| 8 | - |
|
| 9 | - Integer getWidthInPx(); |
|
| 10 | - Integer getHeightInPx(); |
|
| 11 | - |
|
| 12 | - boolean hasSize(); |
|
| 13 | - int getArea(); |
|
| 14 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/ImageDescriptorImpl.java
| ... | ... | @@ -1,62 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.net.URL; |
|
| 4 | - |
|
| 5 | -import com.sap.sse.common.TimePoint; |
|
| 6 | -import com.sap.sse.common.Util.Pair; |
|
| 7 | - |
|
| 8 | - |
|
| 9 | -public class ImageDescriptorImpl extends AbstractMediaDescriptor implements ImageDescriptor { |
|
| 10 | - private static final long serialVersionUID = -702731462768602331L; |
|
| 11 | - |
|
| 12 | - private Integer widthInPx; |
|
| 13 | - private Integer heightInPx; |
|
| 14 | - |
|
| 15 | - /** |
|
| 16 | - * @param imageURL |
|
| 17 | - * @param size |
|
| 18 | - */ |
|
| 19 | - public ImageDescriptorImpl(URL imageURL, TimePoint createdAtDate) { |
|
| 20 | - super(imageURL, MimeType.image, createdAtDate); |
|
| 21 | - } |
|
| 22 | - |
|
| 23 | - @Override |
|
| 24 | - public Integer getWidthInPx() { |
|
| 25 | - return widthInPx; |
|
| 26 | - } |
|
| 27 | - |
|
| 28 | - @Override |
|
| 29 | - public Integer getHeightInPx() { |
|
| 30 | - return heightInPx; |
|
| 31 | - } |
|
| 32 | - |
|
| 33 | - @Override |
|
| 34 | - public void setSize(Pair<Integer, Integer> size) { |
|
| 35 | - if (size != null) { |
|
| 36 | - this.widthInPx = size.getA(); |
|
| 37 | - this.heightInPx = size.getB(); |
|
| 38 | - } else { |
|
| 39 | - this.widthInPx = null; |
|
| 40 | - this.heightInPx = null; |
|
| 41 | - } |
|
| 42 | - } |
|
| 43 | - |
|
| 44 | - @Override |
|
| 45 | - public void setSize(Integer widthInPx, Integer heightInPx) { |
|
| 46 | - this.widthInPx = widthInPx; |
|
| 47 | - this.heightInPx = heightInPx; |
|
| 48 | - } |
|
| 49 | - |
|
| 50 | - @Override |
|
| 51 | - public boolean hasSize() { |
|
| 52 | - return widthInPx != null && heightInPx != null; |
|
| 53 | - } |
|
| 54 | - |
|
| 55 | - @Override |
|
| 56 | - public int getArea() { |
|
| 57 | - if(hasSize()) { |
|
| 58 | - return widthInPx * heightInPx; |
|
| 59 | - } |
|
| 60 | - return 0; |
|
| 61 | - } |
|
| 62 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/MediaDescriptor.java
| ... | ... | @@ -1,36 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.io.Serializable; |
|
| 4 | -import java.net.URL; |
|
| 5 | -import java.util.Locale; |
|
| 6 | - |
|
| 7 | -import com.sap.sse.common.TimePoint; |
|
| 8 | - |
|
| 9 | -/** |
|
| 10 | - * A common media interface for all kinds of media like images or videos. |
|
| 11 | - */ |
|
| 12 | -public interface MediaDescriptor extends Serializable { |
|
| 13 | - MimeType getMimeType(); |
|
| 14 | - URL getURL(); |
|
| 15 | - |
|
| 16 | - String getTitle(); |
|
| 17 | - void setTitle(String title); |
|
| 18 | - |
|
| 19 | - Iterable<String> getTags(); |
|
| 20 | - void setTags(Iterable<String> tags); |
|
| 21 | - boolean addTag(String tagName); |
|
| 22 | - boolean removeTag(String tagName); |
|
| 23 | - boolean hasTag(String tagName); |
|
| 24 | - |
|
| 25 | - String getSubtitle(); |
|
| 26 | - void setSubtitle(String subtitle); |
|
| 27 | - |
|
| 28 | - TimePoint getCreatedAtDate(); |
|
| 29 | - void setCreatedAtDate(TimePoint createdAtDate); |
|
| 30 | - |
|
| 31 | - String getCopyright(); |
|
| 32 | - void setCopyright(String copyright); |
|
| 33 | - |
|
| 34 | - Locale getLocale(); |
|
| 35 | - void setLocale(Locale locale); |
|
| 36 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/MediaUtils.java
| ... | ... | @@ -1,109 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.io.IOException; |
|
| 4 | -import java.net.URL; |
|
| 5 | -import java.net.URLConnection; |
|
| 6 | -import java.util.Iterator; |
|
| 7 | -import java.util.concurrent.Callable; |
|
| 8 | -import java.util.concurrent.ExecutorService; |
|
| 9 | -import java.util.concurrent.Executors; |
|
| 10 | -import java.util.concurrent.Future; |
|
| 11 | -import java.util.logging.Level; |
|
| 12 | -import java.util.logging.Logger; |
|
| 13 | -import java.util.regex.Pattern; |
|
| 14 | - |
|
| 15 | -import javax.imageio.ImageIO; |
|
| 16 | -import javax.imageio.ImageReader; |
|
| 17 | -import javax.imageio.stream.ImageInputStream; |
|
| 18 | - |
|
| 19 | -import com.sap.sse.common.Util; |
|
| 20 | -import com.sap.sse.common.Util.Pair; |
|
| 21 | - |
|
| 22 | -public class MediaUtils { |
|
| 23 | - private static final Logger logger = Logger.getLogger(MediaUtils.class.getName()); |
|
| 24 | - |
|
| 25 | - /** |
|
| 26 | - * Youtube regex detection from: |
|
| 27 | - * http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url, mantish Mar 4 |
|
| 28 | - * at 15:33 |
|
| 29 | - */ |
|
| 30 | - private static final Pattern YOUTUBE_ID_REGEX = Pattern |
|
| 31 | - .compile("^.*(youtu.be/|v/|u/\\w/|embed/|watch\\?v=|\\&v=)([^#\\&\\?]+).*$"); |
|
| 32 | - |
|
| 33 | - private static final Pattern VIMEO_REGEX = Pattern.compile("^.*(vimeo\\.com\\/).*"); |
|
| 34 | - |
|
| 35 | - private static final Pattern MP4_REGEX = Pattern.compile(".*\\.mp4$"); |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * Detect mimetype for given url. |
|
| 39 | - * |
|
| 40 | - * @param url |
|
| 41 | - * the source pointing to the video mediafile |
|
| 42 | - * @return mimetype detected or MimeType.unknown |
|
| 43 | - */ |
|
| 44 | - public static MimeType detectMimeTypeFromUrl(String url) { |
|
| 45 | - |
|
| 46 | - if (YOUTUBE_ID_REGEX.matcher(url).matches()) { |
|
| 47 | - return MimeType.youtube; |
|
| 48 | - } else if (VIMEO_REGEX.matcher(url).matches()) { |
|
| 49 | - return MimeType.vimeo; |
|
| 50 | - } else if (MP4_REGEX.matcher(url).matches()) { |
|
| 51 | - return MimeType.mp4; |
|
| 52 | - } else { |
|
| 53 | - return MimeType.unknown; |
|
| 54 | - } |
|
| 55 | - } |
|
| 56 | - |
|
| 57 | - public static Pair<Integer, Integer> getImageDimensions(URL imageURL) { |
|
| 58 | - Future<Pair<Integer, Integer>> imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL); |
|
| 59 | - try { |
|
| 60 | - return imageSizeCalculator.get(); |
|
| 61 | - } catch (Exception e) { |
|
| 62 | - return null; |
|
| 63 | - } |
|
| 64 | - } |
|
| 65 | - |
|
| 66 | - private static final ExecutorService executor = Executors.newCachedThreadPool(); |
|
| 67 | - |
|
| 68 | - private static Future<Pair<Integer, Integer>> getOrCreateImageSizeCalculator(final URL imageURL) { |
|
| 69 | - Future<Pair<Integer, Integer>> imageSizeFetcher = executor.submit(new Callable<Pair<Integer, Integer>>() { |
|
| 70 | - @Override |
|
| 71 | - public Pair<Integer, Integer> call() throws IOException { |
|
| 72 | - Pair<Integer, Integer> result = null; |
|
| 73 | - ImageInputStream in = null; |
|
| 74 | - try { |
|
| 75 | - URLConnection conn = imageURL.openConnection(); |
|
| 76 | - in = ImageIO.createImageInputStream(conn.getInputStream()); |
|
| 77 | - final Iterator<ImageReader> readers = ImageIO.getImageReaders(in); |
|
| 78 | - if (readers.hasNext()) { |
|
| 79 | - ImageReader reader = readers.next(); |
|
| 80 | - try { |
|
| 81 | - reader.setInput(in); |
|
| 82 | - result = new Pair<>(reader.getWidth(0), reader.getHeight(0)); |
|
| 83 | - } finally { |
|
| 84 | - reader.dispose(); |
|
| 85 | - } |
|
| 86 | - } |
|
| 87 | - } catch (IOException ioe) { |
|
| 88 | - logger.log(Level.SEVERE, "Stale image URL: "+imageURL, ioe); |
|
| 89 | - throw ioe; |
|
| 90 | - } finally { |
|
| 91 | - if (in != null) { |
|
| 92 | - in.close(); |
|
| 93 | - } |
|
| 94 | - } |
|
| 95 | - return result; |
|
| 96 | - } |
|
| 97 | - }); |
|
| 98 | - return imageSizeFetcher; |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - public static Util.Pair<Integer, Integer> fitImageSizeToBox(int boxWidth, int boxHeight, int imageWidth, int imageHeight, boolean neverScaleUp) { |
|
| 102 | - double scale = Math.min((double) boxWidth / (double) imageWidth, (double) boxHeight / (double) imageHeight); |
|
| 103 | - |
|
| 104 | - int h = (int) (!neverScaleUp || scale < 1.0 ? scale * imageHeight : imageHeight); |
|
| 105 | - int w = (int) (!neverScaleUp || scale < 1.0 ? scale * imageWidth : imageWidth); |
|
| 106 | - |
|
| 107 | - return new Util.Pair<Integer, Integer>(w,h); |
|
| 108 | - } |
|
| 109 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptor.java
| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.net.URL; |
|
| 4 | - |
|
| 5 | -public interface VideoDescriptor extends MediaDescriptor { |
|
| 6 | - Integer getLengthInSeconds(); |
|
| 7 | - void setLengthInSeconds(Integer lengthInSeconds); |
|
| 8 | - |
|
| 9 | - URL getThumbnailURL(); |
|
| 10 | - void setThumbnailURL(URL thumbnailURL); |
|
| 11 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/VideoDescriptorImpl.java
| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.net.URL; |
|
| 4 | - |
|
| 5 | -import com.sap.sse.common.TimePoint; |
|
| 6 | - |
|
| 7 | -public class VideoDescriptorImpl extends AbstractMediaDescriptor implements VideoDescriptor { |
|
| 8 | - private static final long serialVersionUID = 2651747912466590862L; |
|
| 9 | - |
|
| 10 | - private Integer lengthInSeconds; |
|
| 11 | - |
|
| 12 | - /** |
|
| 13 | - * URL to thumbnail image. This information works as override for youtube videos or as missing thumbnail |
|
| 14 | - * information for other formats. It can be either a link to thumbnail or even be a data/url contaning the base64 |
|
| 15 | - * encoded image. |
|
| 16 | - */ |
|
| 17 | - private URL thumbnailURL; |
|
| 18 | - |
|
| 19 | - public VideoDescriptorImpl(URL url, MimeType mimeType, TimePoint createdAtDate) { |
|
| 20 | - super(url, mimeType, createdAtDate); |
|
| 21 | - } |
|
| 22 | - |
|
| 23 | - @Override |
|
| 24 | - public Integer getLengthInSeconds() { |
|
| 25 | - return lengthInSeconds; |
|
| 26 | - } |
|
| 27 | - |
|
| 28 | - public void setLengthInSeconds(Integer lengthInSeconds) { |
|
| 29 | - this.lengthInSeconds = lengthInSeconds; |
|
| 30 | - } |
|
| 31 | - |
|
| 32 | - @Override |
|
| 33 | - public URL getThumbnailURL() { |
|
| 34 | - return thumbnailURL; |
|
| 35 | - } |
|
| 36 | - |
|
| 37 | - public void setThumbnailURL(URL thumbnailURL) { |
|
| 38 | - this.thumbnailURL = thumbnailURL; |
|
| 39 | - } |
|
| 40 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/WithImages.java
| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -public interface WithImages { |
|
| 4 | - /** |
|
| 5 | - * Returns a non-<code>null</code> live but unmodifiable collection of image resources that can be |
|
| 6 | - * used to represent the event, e.g., on a web page. |
|
| 7 | - * |
|
| 8 | - * @return a non-<code>null</code> value which may be empty |
|
| 9 | - */ |
|
| 10 | - Iterable<ImageDescriptor> getImages(); |
|
| 11 | - |
|
| 12 | - /** |
|
| 13 | - * Replaces the {@link #getImages() current contents of the image sequence by the images in |
|
| 14 | - * <code>images</code>. |
|
| 15 | - * |
|
| 16 | - * @param images |
|
| 17 | - * if <code>null</code>, the internal sequence of images is cleared but remains valid (non- |
|
| 18 | - * <code>null</code>) |
|
| 19 | - */ |
|
| 20 | - void setImages(Iterable<ImageDescriptor> images); |
|
| 21 | - |
|
| 22 | - void addImage(ImageDescriptor image); |
|
| 23 | - |
|
| 24 | - void removeImage(ImageDescriptor image); |
|
| 25 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/WithMedia.java
| ... | ... | @@ -1,12 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -import java.util.List; |
|
| 4 | - |
|
| 5 | -public interface WithMedia extends WithImages, WithVideos { |
|
| 6 | - ImageDescriptor findImageWithTag(String tagName); |
|
| 7 | - List<ImageDescriptor> findImagesWithTag(String tagName); |
|
| 8 | - boolean hasImageWithTag(String tagName); |
|
| 9 | - |
|
| 10 | - VideoDescriptor findVideoWithTag(String tagName); |
|
| 11 | - List<VideoDescriptor> findVideosWithTag(String tagName); |
|
| 12 | -} |
java/com.sap.sse.common/src/com/sap/sse/common/media/WithVideos.java
| ... | ... | @@ -1,26 +0,0 @@ |
| 1 | -package com.sap.sse.common.media; |
|
| 2 | - |
|
| 3 | -public interface WithVideos { |
|
| 4 | - |
|
| 5 | - /** |
|
| 6 | - * Returns a non-<code>null</code> live but unmodifiable collection of video resources that can be |
|
| 7 | - * used to represent the event, e.g., on a web page. |
|
| 8 | - * |
|
| 9 | - * @return a non-<code>null</code> value which may be empty |
|
| 10 | - */ |
|
| 11 | - Iterable<VideoDescriptor> getVideos(); |
|
| 12 | - |
|
| 13 | - /** |
|
| 14 | - * Replaces the {@link #getVideos() current contents of the video sequence by the videos in |
|
| 15 | - * <code>videos</code>. |
|
| 16 | - * |
|
| 17 | - * @param videos |
|
| 18 | - * if <code>null</code>, the internal sequence of videos is cleared but remains valid (non- |
|
| 19 | - * <code>null</code>) |
|
| 20 | - */ |
|
| 21 | - void setVideos(Iterable<VideoDescriptor> videos); |
|
| 22 | - |
|
| 23 | - void addVideo(VideoDescriptor video); |
|
| 24 | - |
|
| 25 | - void removeVideo(VideoDescriptor video); |
|
| 26 | -} |
java/com.sap.sse.datamining.annotations/pom.xml
| ... | ... | @@ -1,31 +1,31 @@ |
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | <project |
| 3 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | - xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 6 | - <parent> |
|
| 7 | - <artifactId>root</artifactId> |
|
| 8 | - <groupId>com.sap.sailing</groupId> |
|
| 9 | - <version>1.0.0-SNAPSHOT</version> |
|
| 10 | - </parent> |
|
| 11 | - <artifactId>com.sap.sse.datamining.annotations</artifactId> |
|
| 12 | - <packaging>eclipse-plugin</packaging> |
|
| 13 | - <build> |
|
| 14 | - <plugins> |
|
| 15 | - <plugin> |
|
| 16 | - <groupId>org.eclipse.tycho</groupId> |
|
| 17 | - <artifactId>tycho-source-plugin</artifactId> |
|
| 18 | - <version>${tycho-version}</version> |
|
| 19 | - <executions> |
|
| 20 | - <execution> |
|
| 21 | - <id>plugin-source</id> |
|
| 22 | - <phase>generate-sources</phase> |
|
| 23 | - <goals> |
|
| 24 | - <goal>plugin-source</goal> |
|
| 25 | - </goals> |
|
| 26 | - </execution> |
|
| 27 | - </executions> |
|
| 28 | - </plugin> |
|
| 29 | - </plugins> |
|
| 30 | - </build> |
|
| 3 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | + <parent> |
|
| 7 | + <artifactId>root</artifactId> |
|
| 8 | + <groupId>com.sap.sailing</groupId> |
|
| 9 | + <version>1.0.0-SNAPSHOT</version> |
|
| 10 | + </parent> |
|
| 11 | + <artifactId>com.sap.sse.datamining.annotations</artifactId> |
|
| 12 | + <packaging>eclipse-plugin</packaging> |
|
| 13 | + <build> |
|
| 14 | + <plugins> |
|
| 15 | + <plugin> |
|
| 16 | + <groupId>org.eclipse.tycho</groupId> |
|
| 17 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 18 | + <version>${tycho-version}</version> |
|
| 19 | + <executions> |
|
| 20 | + <execution> |
|
| 21 | + <id>plugin-source</id> |
|
| 22 | + <phase>generate-sources</phase> |
|
| 23 | + <goals> |
|
| 24 | + <goal>plugin-source</goal> |
|
| 25 | + </goals> |
|
| 26 | + </execution> |
|
| 27 | + </executions> |
|
| 28 | + </plugin> |
|
| 29 | + </plugins> |
|
| 30 | + </build> |
|
| 31 | 31 | </project> |
java/com.sap.sse.gwt.theme/SSETheme_GWT sdm.launch
| ... | ... | @@ -1,27 +1,27 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
| 2 | -<launchConfiguration type="com.google.gdt.eclipse.suite.webapp"> |
|
| 3 | -<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/> |
|
| 4 | -<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/> |
|
| 5 | -<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> |
|
| 6 | -<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES"> |
|
| 7 | -<listEntry value="com.sap.sse.gwt.theme.SSETheme"/> |
|
| 8 | -</listAttribute> |
|
| 9 | -<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/> |
|
| 10 | -<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/theme/SSETheme.html"/> |
|
| 11 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> |
|
| 12 | -<listEntry value="/com.sap.sse.gwt.theme"/> |
|
| 13 | -</listAttribute> |
|
| 14 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> |
|
| 15 | -<listEntry value="4"/> |
|
| 16 | -</listAttribute> |
|
| 17 | -<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> |
|
| 18 | -<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> |
|
| 19 | -<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> |
|
| 20 | -</listAttribute> |
|
| 21 | -<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/> |
|
| 22 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
|
| 23 | -<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
|
| 24 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -war "${project_loc:com.sap.sse.gwt.theme}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /theme/SSETheme.html com.sap.sse.gwt.theme.SSETheme"/> |
|
| 25 | -<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.gwt.theme"/> |
|
| 26 | -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/> |
|
| 27 | -</launchConfiguration> |
|
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | +<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
|
| 3 | +<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
|
| 4 | +<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
|
| 5 | +<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
|
| 6 | +<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
|
| 7 | +<listEntry value="com.sap.sse.gwt.theme.SSETheme"/>
|
|
| 8 | +</listAttribute>
|
|
| 9 | +<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
|
| 10 | +<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/theme/SSETheme.html"/>
|
|
| 11 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
|
| 12 | +<listEntry value="/com.sap.sse.gwt.theme"/>
|
|
| 13 | +</listAttribute>
|
|
| 14 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
|
| 15 | +<listEntry value="4"/>
|
|
| 16 | +</listAttribute>
|
|
| 17 | +<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
| 18 | +<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
|
| 19 | +<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
|
| 20 | +</listAttribute>
|
|
| 21 | +<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
|
| 22 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
|
| 23 | +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
|
| 24 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -war "${project_loc:com.sap.sse.gwt.theme}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /theme/SSETheme.html com.sap.sse.gwt.theme.SSETheme"/>
|
|
| 25 | +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.gwt.theme"/>
|
|
| 26 | +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
|
|
| 27 | +</launchConfiguration>
|
java/com.sap.sse.gwt.theme/SSETheme_GWT.launch
| ... | ... | @@ -1,26 +1,26 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
| 2 | -<launchConfiguration type="com.google.gdt.eclipse.suite.webapp"> |
|
| 3 | -<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/> |
|
| 4 | -<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/> |
|
| 5 | -<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> |
|
| 6 | -<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES"> |
|
| 7 | -<listEntry value="com.sap.sse.gwt.theme.SSETheme"/> |
|
| 8 | -</listAttribute> |
|
| 9 | -<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/theme/SSETheme.html"/> |
|
| 10 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> |
|
| 11 | -<listEntry value="/com.sap.sse.gwt.theme"/> |
|
| 12 | -</listAttribute> |
|
| 13 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> |
|
| 14 | -<listEntry value="4"/> |
|
| 15 | -</listAttribute> |
|
| 16 | -<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> |
|
| 17 | -<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> |
|
| 18 | -<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> |
|
| 19 | -</listAttribute> |
|
| 20 | -<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/> |
|
| 21 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
|
| 22 | -<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
|
| 23 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -war "${project_loc:com.sap.sse.gwt.theme}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /theme/SSETheme.html com.sap.sse.gwt.theme.SSETheme"/> |
|
| 24 | -<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.gwt.theme"/> |
|
| 25 | -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/> |
|
| 26 | -</launchConfiguration> |
|
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | +<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
|
| 3 | +<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
|
| 4 | +<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
|
| 5 | +<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
|
| 6 | +<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
|
| 7 | +<listEntry value="com.sap.sse.gwt.theme.SSETheme"/>
|
|
| 8 | +</listAttribute>
|
|
| 9 | +<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/theme/SSETheme.html"/>
|
|
| 10 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
|
| 11 | +<listEntry value="/com.sap.sse.gwt.theme"/>
|
|
| 12 | +</listAttribute>
|
|
| 13 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
|
| 14 | +<listEntry value="4"/>
|
|
| 15 | +</listAttribute>
|
|
| 16 | +<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
| 17 | +<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
|
| 18 | +<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
|
| 19 | +</listAttribute>
|
|
| 20 | +<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
|
| 21 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
|
| 22 | +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
|
| 23 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -war "${project_loc:com.sap.sse.gwt.theme}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /theme/SSETheme.html com.sap.sse.gwt.theme.SSETheme"/>
|
|
| 24 | +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.gwt.theme"/>
|
|
| 25 | +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/>
|
|
| 26 | +</launchConfiguration>
|
java/com.sap.sse.security.common/pom.xml
| ... | ... | @@ -1,32 +1,32 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
| 4 | - <modelVersion>4.0.0</modelVersion>
|
|
| 5 | - <parent>
|
|
| 6 | - <artifactId>root</artifactId>
|
|
| 7 | - <groupId>com.sap.sailing</groupId>
|
|
| 8 | - <version>1.0.0-SNAPSHOT</version>
|
|
| 9 | - </parent>
|
|
| 10 | - <artifactId>com.sap.sse.security.common</artifactId>
|
|
| 11 | - <packaging>eclipse-plugin</packaging>
|
|
| 12 | -
|
|
| 13 | - <build>
|
|
| 14 | - <plugins>
|
|
| 15 | - <plugin>
|
|
| 16 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 17 | - <artifactId>tycho-source-plugin</artifactId>
|
|
| 18 | - <version>${tycho-version}</version>
|
|
| 19 | - <executions>
|
|
| 20 | - <execution>
|
|
| 21 | - <id>plugin-source</id>
|
|
| 22 | - <phase>generate-sources</phase>
|
|
| 23 | - <goals>
|
|
| 24 | - <goal>plugin-source</goal>
|
|
| 25 | - </goals>
|
|
| 26 | - </execution>
|
|
| 27 | - </executions>
|
|
| 28 | - </plugin>
|
|
| 29 | - </plugins>
|
|
| 30 | - </build>
|
|
| 31 | -
|
|
| 32 | -</project>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>com.sap.sse.security.common</artifactId> |
|
| 11 | + <packaging>eclipse-plugin</packaging> |
|
| 12 | + |
|
| 13 | + <build> |
|
| 14 | + <plugins> |
|
| 15 | + <plugin> |
|
| 16 | + <groupId>org.eclipse.tycho</groupId> |
|
| 17 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 18 | + <version>${tycho-version}</version> |
|
| 19 | + <executions> |
|
| 20 | + <execution> |
|
| 21 | + <id>plugin-source</id> |
|
| 22 | + <phase>generate-sources</phase> |
|
| 23 | + <goals> |
|
| 24 | + <goal>plugin-source</goal> |
|
| 25 | + </goals> |
|
| 26 | + </execution> |
|
| 27 | + </executions> |
|
| 28 | + </plugin> |
|
| 29 | + </plugins> |
|
| 30 | + </build> |
|
| 31 | + |
|
| 32 | +</project> |
java/com.sap.sse.security.ui/Security UI sdm.launch
| ... | ... | @@ -1,48 +1,48 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
| 2 | -<launchConfiguration type="com.google.gdt.eclipse.suite.webapp"> |
|
| 3 | -<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/> |
|
| 4 | -<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/> |
|
| 5 | -<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> |
|
| 6 | -<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9875"/> |
|
| 7 | -<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES"> |
|
| 8 | -<listEntry value="com.sap.sse.security.ui.UserManagement"/> |
|
| 9 | -</listAttribute> |
|
| 10 | -<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/> |
|
| 11 | -<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/security/ui/Login.html"/> |
|
| 12 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> |
|
| 13 | -<listEntry value="/com.sap.sse.security.ui"/> |
|
| 14 | -</listAttribute> |
|
| 15 | -<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> |
|
| 16 | -<listEntry value="4"/> |
|
| 17 | -</listAttribute> |
|
| 18 | -<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> |
|
| 19 | -<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> |
|
| 20 | -<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> |
|
| 21 | -</listAttribute> |
|
| 22 | -<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/> |
|
| 23 | -<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> |
|
| 24 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sse.security.ui" path="1" type="4"/> "/> |
|
| 25 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/resources" path="3" type="2"/> "/> |
|
| 26 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/java" path="3" type="2"/> "/> |
|
| 27 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/> |
|
| 28 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/> |
|
| 29 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.operationaltransformation/src" path="3" type="2"/> "/> |
|
| 30 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.replication/src" path="3" type="2"/> "/> |
|
| 31 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/> |
|
| 32 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.common/src" path="3" type="2"/> "/> |
|
| 33 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.datamining.shared/src" path="3" type="2"/> "/> |
|
| 34 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt/src" path="3" type="2"/> "/> |
|
| 35 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/> |
|
| 36 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sse.security.ui"/> </runtimeClasspathEntry> "/> |
|
| 37 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security/src" path="3" type="2"/> "/> |
|
| 38 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/> |
|
| 39 | -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.common/src" path="3" type="2"/> "/> |
|
| 40 | -</listAttribute> |
|
| 41 | -<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/> |
|
| 42 | -<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> |
|
| 43 | -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
|
| 44 | -<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
|
| 45 | -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.security.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9875 -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation -startupUrl /security/ui/UserManagement.html com.sap.sse.security.ui.UserManagement"/> |
|
| 46 | -<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.security.ui"/> |
|
| 47 | -<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/> |
|
| 48 | -</launchConfiguration> |
|
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | +<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
|
| 3 | +<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
|
| 4 | +<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
|
| 5 | +<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
|
| 6 | +<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9875"/>
|
|
| 7 | +<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
|
| 8 | +<listEntry value="com.sap.sse.security.ui.UserManagement"/>
|
|
| 9 | +</listAttribute>
|
|
| 10 | +<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
|
| 11 | +<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/security/ui/Login.html"/>
|
|
| 12 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
|
| 13 | +<listEntry value="/com.sap.sse.security.ui"/>
|
|
| 14 | +</listAttribute>
|
|
| 15 | +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
|
| 16 | +<listEntry value="4"/>
|
|
| 17 | +</listAttribute>
|
|
| 18 | +<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
| 19 | +<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
|
| 20 | +<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
|
| 21 | +</listAttribute>
|
|
| 22 | +<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
|
| 23 | +<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
|
| 24 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sse.security.ui" path="1" type="4"/> "/>
|
|
| 25 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/resources" path="3" type="2"/> "/>
|
|
| 26 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/java" path="3" type="2"/> "/>
|
|
| 27 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
|
| 28 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
|
| 29 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.operationaltransformation/src" path="3" type="2"/> "/>
|
|
| 30 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.replication/src" path="3" type="2"/> "/>
|
|
| 31 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
|
| 32 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.common/src" path="3" type="2"/> "/>
|
|
| 33 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.datamining.shared/src" path="3" type="2"/> "/>
|
|
| 34 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt/src" path="3" type="2"/> "/>
|
|
| 35 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
|
| 36 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sse.security.ui"/> </runtimeClasspathEntry> "/>
|
|
| 37 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security/src" path="3" type="2"/> "/>
|
|
| 38 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/>
|
|
| 39 | +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.common/src" path="3" type="2"/> "/>
|
|
| 40 | +</listAttribute>
|
|
| 41 | +<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
|
| 42 | +<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
|
| 43 | +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
|
| 44 | +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
|
| 45 | +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.security.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9875 -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation -startupUrl /security/ui/UserManagement.html com.sap.sse.security.ui.UserManagement"/>
|
|
| 46 | +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.security.ui"/>
|
|
| 47 | +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
|
|
| 48 | +</launchConfiguration>
|
java/com.sap.sse.shared.android/META-INF/MANIFEST.MF
| ... | ... | @@ -7,4 +7,6 @@ Bundle-Vendor: SAP |
| 7 | 7 | Bundle-RequiredExecutionEnvironment: JavaSE-1.7 |
| 8 | 8 | Require-Bundle: com.sap.sse.common |
| 9 | 9 | Export-Package: com.sap.sse.concurrent, |
| 10 | + com.sap.sse.shared.media, |
|
| 11 | + com.sap.sse.shared.media.impl, |
|
| 10 | 12 | com.sap.sse.util.impl |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/ImageDescriptor.java
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.common.Util.Pair; |
|
| 4 | + |
|
| 5 | +public interface ImageDescriptor extends MediaDescriptor { |
|
| 6 | + void setSize(Pair<Integer, Integer> size); |
|
| 7 | + void setSize(Integer widthInPx, Integer heightInPx); |
|
| 8 | + |
|
| 9 | + Integer getWidthInPx(); |
|
| 10 | + Integer getHeightInPx(); |
|
| 11 | + |
|
| 12 | + boolean hasSize(); |
|
| 13 | + int getArea(); |
|
| 14 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/MediaDescriptor.java
| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | +import java.io.Serializable; |
|
| 4 | +import java.net.URL; |
|
| 5 | +import java.util.Locale; |
|
| 6 | + |
|
| 7 | +import com.sap.sse.common.TimePoint; |
|
| 8 | +import com.sap.sse.common.media.MimeType; |
|
| 9 | + |
|
| 10 | +/** |
|
| 11 | + * A common media interface for all kinds of media like images or videos. |
|
| 12 | + */ |
|
| 13 | +public interface MediaDescriptor extends Serializable { |
|
| 14 | + MimeType getMimeType(); |
|
| 15 | + URL getURL(); |
|
| 16 | + |
|
| 17 | + String getTitle(); |
|
| 18 | + void setTitle(String title); |
|
| 19 | + |
|
| 20 | + Iterable<String> getTags(); |
|
| 21 | + void setTags(Iterable<String> tags); |
|
| 22 | + boolean addTag(String tagName); |
|
| 23 | + boolean removeTag(String tagName); |
|
| 24 | + boolean hasTag(String tagName); |
|
| 25 | + |
|
| 26 | + String getSubtitle(); |
|
| 27 | + void setSubtitle(String subtitle); |
|
| 28 | + |
|
| 29 | + TimePoint getCreatedAtDate(); |
|
| 30 | + void setCreatedAtDate(TimePoint createdAtDate); |
|
| 31 | + |
|
| 32 | + String getCopyright(); |
|
| 33 | + void setCopyright(String copyright); |
|
| 34 | + |
|
| 35 | + Locale getLocale(); |
|
| 36 | + void setLocale(Locale locale); |
|
| 37 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/MediaUtils.java
| ... | ... | @@ -0,0 +1,110 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | +import java.io.IOException; |
|
| 4 | +import java.net.URL; |
|
| 5 | +import java.net.URLConnection; |
|
| 6 | +import java.util.Iterator; |
|
| 7 | +import java.util.concurrent.Callable; |
|
| 8 | +import java.util.concurrent.ExecutorService; |
|
| 9 | +import java.util.concurrent.Executors; |
|
| 10 | +import java.util.concurrent.Future; |
|
| 11 | +import java.util.logging.Level; |
|
| 12 | +import java.util.logging.Logger; |
|
| 13 | +import java.util.regex.Pattern; |
|
| 14 | + |
|
| 15 | +import javax.imageio.ImageIO; |
|
| 16 | +import javax.imageio.ImageReader; |
|
| 17 | +import javax.imageio.stream.ImageInputStream; |
|
| 18 | + |
|
| 19 | +import com.sap.sse.common.Util; |
|
| 20 | +import com.sap.sse.common.Util.Pair; |
|
| 21 | +import com.sap.sse.common.media.MimeType; |
|
| 22 | + |
|
| 23 | +public class MediaUtils { |
|
| 24 | + private static final Logger logger = Logger.getLogger(MediaUtils.class.getName()); |
|
| 25 | + |
|
| 26 | + /** |
|
| 27 | + * Youtube regex detection from: |
|
| 28 | + * http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url, mantish Mar 4 |
|
| 29 | + * at 15:33 |
|
| 30 | + */ |
|
| 31 | + private static final Pattern YOUTUBE_ID_REGEX = Pattern |
|
| 32 | + .compile("^.*(youtu.be/|v/|u/\\w/|embed/|watch\\?v=|\\&v=)([^#\\&\\?]+).*$"); |
|
| 33 | + |
|
| 34 | + private static final Pattern VIMEO_REGEX = Pattern.compile("^.*(vimeo\\.com\\/).*"); |
|
| 35 | + |
|
| 36 | + private static final Pattern MP4_REGEX = Pattern.compile(".*\\.mp4$"); |
|
| 37 | + |
|
| 38 | + /** |
|
| 39 | + * Detect mimetype for given url. |
|
| 40 | + * |
|
| 41 | + * @param url |
|
| 42 | + * the source pointing to the video mediafile |
|
| 43 | + * @return mimetype detected or MimeType.unknown |
|
| 44 | + */ |
|
| 45 | + public static MimeType detectMimeTypeFromUrl(String url) { |
|
| 46 | + |
|
| 47 | + if (YOUTUBE_ID_REGEX.matcher(url).matches()) { |
|
| 48 | + return MimeType.youtube; |
|
| 49 | + } else if (VIMEO_REGEX.matcher(url).matches()) { |
|
| 50 | + return MimeType.vimeo; |
|
| 51 | + } else if (MP4_REGEX.matcher(url).matches()) { |
|
| 52 | + return MimeType.mp4; |
|
| 53 | + } else { |
|
| 54 | + return MimeType.unknown; |
|
| 55 | + } |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + public static Pair<Integer, Integer> getImageDimensions(URL imageURL) { |
|
| 59 | + Future<Pair<Integer, Integer>> imageSizeCalculator = getOrCreateImageSizeCalculator(imageURL); |
|
| 60 | + try { |
|
| 61 | + return imageSizeCalculator.get(); |
|
| 62 | + } catch (Exception e) { |
|
| 63 | + return null; |
|
| 64 | + } |
|
| 65 | + } |
|
| 66 | + |
|
| 67 | + private static final ExecutorService executor = Executors.newCachedThreadPool(); |
|
| 68 | + |
|
| 69 | + private static Future<Pair<Integer, Integer>> getOrCreateImageSizeCalculator(final URL imageURL) { |
|
| 70 | + Future<Pair<Integer, Integer>> imageSizeFetcher = executor.submit(new Callable<Pair<Integer, Integer>>() { |
|
| 71 | + @Override |
|
| 72 | + public Pair<Integer, Integer> call() throws IOException { |
|
| 73 | + Pair<Integer, Integer> result = null; |
|
| 74 | + ImageInputStream in = null; |
|
| 75 | + try { |
|
| 76 | + URLConnection conn = imageURL.openConnection(); |
|
| 77 | + in = ImageIO.createImageInputStream(conn.getInputStream()); |
|
| 78 | + final Iterator<ImageReader> readers = ImageIO.getImageReaders(in); |
|
| 79 | + if (readers.hasNext()) { |
|
| 80 | + ImageReader reader = readers.next(); |
|
| 81 | + try { |
|
| 82 | + reader.setInput(in); |
|
| 83 | + result = new Pair<>(reader.getWidth(0), reader.getHeight(0)); |
|
| 84 | + } finally { |
|
| 85 | + reader.dispose(); |
|
| 86 | + } |
|
| 87 | + } |
|
| 88 | + } catch (IOException ioe) { |
|
| 89 | + logger.log(Level.SEVERE, "Stale image URL: "+imageURL, ioe); |
|
| 90 | + throw ioe; |
|
| 91 | + } finally { |
|
| 92 | + if (in != null) { |
|
| 93 | + in.close(); |
|
| 94 | + } |
|
| 95 | + } |
|
| 96 | + return result; |
|
| 97 | + } |
|
| 98 | + }); |
|
| 99 | + return imageSizeFetcher; |
|
| 100 | + } |
|
| 101 | + |
|
| 102 | + public static Util.Pair<Integer, Integer> fitImageSizeToBox(int boxWidth, int boxHeight, int imageWidth, int imageHeight, boolean neverScaleUp) { |
|
| 103 | + double scale = Math.min((double) boxWidth / (double) imageWidth, (double) boxHeight / (double) imageHeight); |
|
| 104 | + |
|
| 105 | + int h = (int) (!neverScaleUp || scale < 1.0 ? scale * imageHeight : imageHeight); |
|
| 106 | + int w = (int) (!neverScaleUp || scale < 1.0 ? scale * imageWidth : imageWidth); |
|
| 107 | + |
|
| 108 | + return new Util.Pair<Integer, Integer>(w,h); |
|
| 109 | + } |
|
| 110 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/VideoDescriptor.java
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | + |
|
| 5 | +public interface VideoDescriptor extends MediaDescriptor { |
|
| 6 | + Integer getLengthInSeconds(); |
|
| 7 | + void setLengthInSeconds(Integer lengthInSeconds); |
|
| 8 | + |
|
| 9 | + URL getThumbnailURL(); |
|
| 10 | + void setThumbnailURL(URL thumbnailURL); |
|
| 11 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/WithImages.java
| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | + |
|
| 4 | +public interface WithImages { |
|
| 5 | + /** |
|
| 6 | + * Returns a non-<code>null</code> live but unmodifiable collection of image resources that can be |
|
| 7 | + * used to represent the event, e.g., on a web page. |
|
| 8 | + * |
|
| 9 | + * @return a non-<code>null</code> value which may be empty |
|
| 10 | + */ |
|
| 11 | + Iterable<ImageDescriptor> getImages(); |
|
| 12 | + |
|
| 13 | + /** |
|
| 14 | + * Replaces the {@link #getImages() current contents of the image sequence by the images in |
|
| 15 | + * <code>images</code>. |
|
| 16 | + * |
|
| 17 | + * @param images |
|
| 18 | + * if <code>null</code>, the internal sequence of images is cleared but remains valid (non- |
|
| 19 | + * <code>null</code>) |
|
| 20 | + */ |
|
| 21 | + void setImages(Iterable<ImageDescriptor> images); |
|
| 22 | + |
|
| 23 | + void addImage(ImageDescriptor image); |
|
| 24 | + |
|
| 25 | + void removeImage(ImageDescriptor image); |
|
| 26 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/WithMedia.java
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | +import java.util.List; |
|
| 4 | + |
|
| 5 | +public interface WithMedia extends WithImages, WithVideos { |
|
| 6 | + ImageDescriptor findImageWithTag(String tagName); |
|
| 7 | + List<ImageDescriptor> findImagesWithTag(String tagName); |
|
| 8 | + boolean hasImageWithTag(String tagName); |
|
| 9 | + |
|
| 10 | + VideoDescriptor findVideoWithTag(String tagName); |
|
| 11 | + List<VideoDescriptor> findVideosWithTag(String tagName); |
|
| 12 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/WithVideos.java
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +package com.sap.sse.shared.media; |
|
| 2 | + |
|
| 3 | + |
|
| 4 | +public interface WithVideos { |
|
| 5 | + |
|
| 6 | + /** |
|
| 7 | + * Returns a non-<code>null</code> live but unmodifiable collection of video resources that can be |
|
| 8 | + * used to represent the event, e.g., on a web page. |
|
| 9 | + * |
|
| 10 | + * @return a non-<code>null</code> value which may be empty |
|
| 11 | + */ |
|
| 12 | + Iterable<VideoDescriptor> getVideos(); |
|
| 13 | + |
|
| 14 | + /** |
|
| 15 | + * Replaces the {@link #getVideos() current contents of the video sequence by the videos in |
|
| 16 | + * <code>videos</code>. |
|
| 17 | + * |
|
| 18 | + * @param videos |
|
| 19 | + * if <code>null</code>, the internal sequence of videos is cleared but remains valid (non- |
|
| 20 | + * <code>null</code>) |
|
| 21 | + */ |
|
| 22 | + void setVideos(Iterable<VideoDescriptor> videos); |
|
| 23 | + |
|
| 24 | + void addVideo(VideoDescriptor video); |
|
| 25 | + |
|
| 26 | + void removeVideo(VideoDescriptor video); |
|
| 27 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/impl/AbstractMediaDescriptor.java
| ... | ... | @@ -0,0 +1,138 @@ |
| 1 | +package com.sap.sse.shared.media.impl; |
|
| 2 | + |
|
| 3 | +import java.io.Serializable; |
|
| 4 | +import java.net.URL; |
|
| 5 | +import java.util.LinkedHashSet; |
|
| 6 | +import java.util.Locale; |
|
| 7 | +import java.util.Set; |
|
| 8 | + |
|
| 9 | +import com.sap.sse.common.TimePoint; |
|
| 10 | +import com.sap.sse.common.Util; |
|
| 11 | +import com.sap.sse.common.media.MimeType; |
|
| 12 | +import com.sap.sse.shared.media.MediaDescriptor; |
|
| 13 | + |
|
| 14 | +/** |
|
| 15 | + * Common media data for media items |
|
| 16 | + * |
|
| 17 | + * @author pgtaboada |
|
| 18 | + * |
|
| 19 | + */ |
|
| 20 | +public abstract class AbstractMediaDescriptor implements MediaDescriptor, Serializable { |
|
| 21 | + private static final long serialVersionUID = -6671425870632517274L; |
|
| 22 | + |
|
| 23 | + protected String title; |
|
| 24 | + |
|
| 25 | + protected String subtitle; |
|
| 26 | + |
|
| 27 | + protected TimePoint createdAtDate; |
|
| 28 | + |
|
| 29 | + protected String copyright; |
|
| 30 | + |
|
| 31 | + protected MimeType mimeType; |
|
| 32 | + |
|
| 33 | + protected Set<String> tags = new LinkedHashSet<String>(); |
|
| 34 | + |
|
| 35 | + protected URL url; |
|
| 36 | + |
|
| 37 | + protected Locale locale; |
|
| 38 | + |
|
| 39 | + /** |
|
| 40 | + * Media item with minimal set of information |
|
| 41 | + * @param url |
|
| 42 | + * @param mimeType |
|
| 43 | + */ |
|
| 44 | + public AbstractMediaDescriptor(URL url, MimeType mimeType, TimePoint createdAtDate) { |
|
| 45 | + this.mimeType = mimeType; |
|
| 46 | + this.url = url; |
|
| 47 | + this.createdAtDate = createdAtDate; |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + @Override |
|
| 51 | + public MimeType getMimeType() { |
|
| 52 | + return mimeType; |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + @Override |
|
| 56 | + public URL getURL() { |
|
| 57 | + return url; |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + @Override |
|
| 61 | + public String getTitle() { |
|
| 62 | + return title; |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + @Override |
|
| 66 | + public void setTitle(String title) { |
|
| 67 | + this.title = title; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + @Override |
|
| 71 | + public Set<String> getTags() { |
|
| 72 | + return tags; |
|
| 73 | + } |
|
| 74 | + |
|
| 75 | + @Override |
|
| 76 | + public void setTags(Iterable<String> tags) { |
|
| 77 | + this.tags.clear(); |
|
| 78 | + if (tags != null) { |
|
| 79 | + Util.addAll(tags, this.tags); |
|
| 80 | + } |
|
| 81 | + } |
|
| 82 | + |
|
| 83 | + |
|
| 84 | + @Override |
|
| 85 | + public boolean addTag(String tagName) { |
|
| 86 | + return tags.add(tagName); |
|
| 87 | + } |
|
| 88 | + |
|
| 89 | + @Override |
|
| 90 | + public boolean removeTag(String tagName) { |
|
| 91 | + return tags.remove(tagName); |
|
| 92 | + } |
|
| 93 | + |
|
| 94 | + @Override |
|
| 95 | + public String getSubtitle() { |
|
| 96 | + return subtitle; |
|
| 97 | + } |
|
| 98 | + |
|
| 99 | + @Override |
|
| 100 | + public void setSubtitle(String subtitle) { |
|
| 101 | + this.subtitle = subtitle; |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + @Override |
|
| 105 | + public TimePoint getCreatedAtDate() { |
|
| 106 | + return createdAtDate; |
|
| 107 | + } |
|
| 108 | + |
|
| 109 | + @Override |
|
| 110 | + public void setCreatedAtDate(TimePoint createdAtDate) { |
|
| 111 | + this.createdAtDate = createdAtDate; |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + @Override |
|
| 115 | + public String getCopyright() { |
|
| 116 | + return copyright; |
|
| 117 | + } |
|
| 118 | + |
|
| 119 | + @Override |
|
| 120 | + public void setCopyright(String copyright) { |
|
| 121 | + this.copyright = copyright; |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + @Override |
|
| 125 | + public Locale getLocale() { |
|
| 126 | + return locale; |
|
| 127 | + } |
|
| 128 | + |
|
| 129 | + @Override |
|
| 130 | + public void setLocale(Locale locale) { |
|
| 131 | + this.locale = locale; |
|
| 132 | + } |
|
| 133 | + |
|
| 134 | + @Override |
|
| 135 | + public boolean hasTag(String tagName) { |
|
| 136 | + return tags.contains(tagName); |
|
| 137 | + } |
|
| 138 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/impl/ImageDescriptorImpl.java
| ... | ... | @@ -0,0 +1,64 @@ |
| 1 | +package com.sap.sse.shared.media.impl; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | + |
|
| 5 | +import com.sap.sse.common.TimePoint; |
|
| 6 | +import com.sap.sse.common.Util.Pair; |
|
| 7 | +import com.sap.sse.common.media.MimeType; |
|
| 8 | +import com.sap.sse.shared.media.ImageDescriptor; |
|
| 9 | + |
|
| 10 | + |
|
| 11 | +public class ImageDescriptorImpl extends AbstractMediaDescriptor implements ImageDescriptor { |
|
| 12 | + private static final long serialVersionUID = -702731462768602331L; |
|
| 13 | + |
|
| 14 | + private Integer widthInPx; |
|
| 15 | + private Integer heightInPx; |
|
| 16 | + |
|
| 17 | + /** |
|
| 18 | + * @param imageURL |
|
| 19 | + * @param size |
|
| 20 | + */ |
|
| 21 | + public ImageDescriptorImpl(URL imageURL, TimePoint createdAtDate) { |
|
| 22 | + super(imageURL, MimeType.image, createdAtDate); |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + @Override |
|
| 26 | + public Integer getWidthInPx() { |
|
| 27 | + return widthInPx; |
|
| 28 | + } |
|
| 29 | + |
|
| 30 | + @Override |
|
| 31 | + public Integer getHeightInPx() { |
|
| 32 | + return heightInPx; |
|
| 33 | + } |
|
| 34 | + |
|
| 35 | + @Override |
|
| 36 | + public void setSize(Pair<Integer, Integer> size) { |
|
| 37 | + if (size != null) { |
|
| 38 | + this.widthInPx = size.getA(); |
|
| 39 | + this.heightInPx = size.getB(); |
|
| 40 | + } else { |
|
| 41 | + this.widthInPx = null; |
|
| 42 | + this.heightInPx = null; |
|
| 43 | + } |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public void setSize(Integer widthInPx, Integer heightInPx) { |
|
| 48 | + this.widthInPx = widthInPx; |
|
| 49 | + this.heightInPx = heightInPx; |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | + @Override |
|
| 53 | + public boolean hasSize() { |
|
| 54 | + return widthInPx != null && heightInPx != null; |
|
| 55 | + } |
|
| 56 | + |
|
| 57 | + @Override |
|
| 58 | + public int getArea() { |
|
| 59 | + if(hasSize()) { |
|
| 60 | + return widthInPx * heightInPx; |
|
| 61 | + } |
|
| 62 | + return 0; |
|
| 63 | + } |
|
| 64 | +} |
java/com.sap.sse.shared.android/src/com/sap/sse/shared/media/impl/VideoDescriptorImpl.java
| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | +package com.sap.sse.shared.media.impl; |
|
| 2 | + |
|
| 3 | +import java.net.URL; |
|
| 4 | + |
|
| 5 | +import com.sap.sse.common.TimePoint; |
|
| 6 | +import com.sap.sse.common.media.MimeType; |
|
| 7 | +import com.sap.sse.shared.media.VideoDescriptor; |
|
| 8 | + |
|
| 9 | +public class VideoDescriptorImpl extends AbstractMediaDescriptor implements VideoDescriptor { |
|
| 10 | + private static final long serialVersionUID = 2651747912466590862L; |
|
| 11 | + |
|
| 12 | + private Integer lengthInSeconds; |
|
| 13 | + |
|
| 14 | + /** |
|
| 15 | + * URL to thumbnail image. This information works as override for youtube videos or as missing thumbnail |
|
| 16 | + * information for other formats. It can be either a link to thumbnail or even be a data/url contaning the base64 |
|
| 17 | + * encoded image. |
|
| 18 | + */ |
|
| 19 | + private URL thumbnailURL; |
|
| 20 | + |
|
| 21 | + public VideoDescriptorImpl(URL url, MimeType mimeType, TimePoint createdAtDate) { |
|
| 22 | + super(url, mimeType, createdAtDate); |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + @Override |
|
| 26 | + public Integer getLengthInSeconds() { |
|
| 27 | + return lengthInSeconds; |
|
| 28 | + } |
|
| 29 | + |
|
| 30 | + public void setLengthInSeconds(Integer lengthInSeconds) { |
|
| 31 | + this.lengthInSeconds = lengthInSeconds; |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + @Override |
|
| 35 | + public URL getThumbnailURL() { |
|
| 36 | + return thumbnailURL; |
|
| 37 | + } |
|
| 38 | + |
|
| 39 | + public void setThumbnailURL(URL thumbnailURL) { |
|
| 40 | + this.thumbnailURL = thumbnailURL; |
|
| 41 | + } |
|
| 42 | +} |
java/org.json.simple/pom.xml
| ... | ... | @@ -1,40 +1,40 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
| 4 | - <modelVersion>4.0.0</modelVersion>
|
|
| 5 | - <parent>
|
|
| 6 | - <artifactId>root</artifactId>
|
|
| 7 | - <groupId>com.sap.sailing</groupId>
|
|
| 8 | - <version>1.0.0-SNAPSHOT</version>
|
|
| 9 | - </parent>
|
|
| 10 | - <artifactId>org.json.simple</artifactId>
|
|
| 11 | - <version>1.1.0-SNAPSHOT</version>
|
|
| 12 | - <packaging>eclipse-plugin</packaging>
|
|
| 13 | - <build>
|
|
| 14 | - <plugins>
|
|
| 15 | - <plugin>
|
|
| 16 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 17 | - <artifactId>tycho-compiler-plugin</artifactId>
|
|
| 18 | - <version>${tycho-version}</version>
|
|
| 19 | - <configuration>
|
|
| 20 | - <source>1.7</source>
|
|
| 21 | - <target>1.7</target>
|
|
| 22 | - </configuration>
|
|
| 23 | - </plugin>
|
|
| 24 | - <plugin>
|
|
| 25 | - <groupId>org.eclipse.tycho</groupId>
|
|
| 26 | - <artifactId>tycho-source-plugin</artifactId>
|
|
| 27 | - <version>${tycho-version}</version>
|
|
| 28 | - <executions>
|
|
| 29 | - <execution>
|
|
| 30 | - <id>plugin-source</id>
|
|
| 31 | - <phase>generate-sources</phase>
|
|
| 32 | - <goals>
|
|
| 33 | - <goal>plugin-source</goal>
|
|
| 34 | - </goals>
|
|
| 35 | - </execution>
|
|
| 36 | - </executions>
|
|
| 37 | - </plugin>
|
|
| 38 | - </plugins>
|
|
| 39 | - </build>
|
|
| 40 | -</project>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>org.json.simple</artifactId> |
|
| 11 | + <version>1.1.0-SNAPSHOT</version> |
|
| 12 | + <packaging>eclipse-plugin</packaging> |
|
| 13 | + <build> |
|
| 14 | + <plugins> |
|
| 15 | + <plugin> |
|
| 16 | + <groupId>org.eclipse.tycho</groupId> |
|
| 17 | + <artifactId>tycho-compiler-plugin</artifactId> |
|
| 18 | + <version>${tycho-version}</version> |
|
| 19 | + <configuration> |
|
| 20 | + <source>1.7</source> |
|
| 21 | + <target>1.7</target> |
|
| 22 | + </configuration> |
|
| 23 | + </plugin> |
|
| 24 | + <plugin> |
|
| 25 | + <groupId>org.eclipse.tycho</groupId> |
|
| 26 | + <artifactId>tycho-source-plugin</artifactId> |
|
| 27 | + <version>${tycho-version}</version> |
|
| 28 | + <executions> |
|
| 29 | + <execution> |
|
| 30 | + <id>plugin-source</id> |
|
| 31 | + <phase>generate-sources</phase> |
|
| 32 | + <goals> |
|
| 33 | + <goal>plugin-source</goal> |
|
| 34 | + </goals> |
|
| 35 | + </execution> |
|
| 36 | + </executions> |
|
| 37 | + </plugin> |
|
| 38 | + </plugins> |
|
| 39 | + </build> |
|
| 40 | +</project> |
java/pom.xml
| ... | ... | @@ -134,8 +134,8 @@ |
| 134 | 134 | <module>com.sap.sailing.autoload</module> |
| 135 | 135 | <module>com.sap.sailing.feature.p2build</module> |
| 136 | 136 | <module>com.sap.sailing.polars</module> |
| 137 | - <module>com.sap.sailing.polars.datamining</module> |
|
| 138 | - <module>com.sap.sailing.polars.datamining.shared</module> |
|
| 137 | + <module>com.sap.sailing.polars.datamining</module> |
|
| 138 | + <module>com.sap.sailing.polars.datamining.shared</module> |
|
| 139 | 139 | <module>com.sap.sailing.polars.test</module> |
| 140 | 140 | <!-- |
| 141 | 141 | com.sap.sailing.targetplatform.base |
| ... | ... | @@ -264,15 +264,15 @@ |
| 264 | 264 | <version>${tycho-version}</version> |
| 265 | 265 | <configuration> |
| 266 | 266 | <resolver>p2</resolver> |
| 267 | - <dependency-resolution> |
|
| 268 | - <extraRequirements> |
|
| 269 | - <requirement> |
|
| 270 | - <type>eclipse-plugin</type> |
|
| 271 | - <id>com.google.gwt.dev</id> |
|
| 272 | - <versionRange>0.0.0</versionRange> |
|
| 273 | - </requirement> |
|
| 274 | - </extraRequirements> |
|
| 275 | - </dependency-resolution> |
|
| 267 | + <dependency-resolution> |
|
| 268 | + <extraRequirements> |
|
| 269 | + <requirement> |
|
| 270 | + <type>eclipse-plugin</type> |
|
| 271 | + <id>com.google.gwt.dev</id> |
|
| 272 | + <versionRange>0.0.0</versionRange> |
|
| 273 | + </requirement> |
|
| 274 | + </extraRequirements> |
|
| 275 | + </dependency-resolution> |
|
| 276 | 276 | <target> |
| 277 | 277 | <artifact> |
| 278 | 278 | <groupId>${project.groupId}</groupId> |
mobile/com.sap.sailing.android.shared/build.gradle
| ... | ... | @@ -51,6 +51,9 @@ dependencies { |
| 51 | 51 | /* Google Play Services */ |
| 52 | 52 | compile "com.google.android.gms:play-services-location:${rootProject.ext.play_services}" |
| 53 | 53 | |
| 54 | + /* licence dialog */ |
|
| 55 | + compile('de.psdev.licensesdialog:licensesdialog:1.8.0') |
|
| 56 | + |
|
| 54 | 57 | /* all local jar-libs */ |
| 55 | 58 | compile fileTree(dir: "libs", include: ["*.jar"]) |
| 56 | 59 |
mobile/com.sap.sailing.android.shared/pom.xml
| ... | ... | @@ -1,17 +1,17 @@ |
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | <project |
| 3 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | - xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 6 | - <parent> |
|
| 7 | - <groupId>com.sap.sailing</groupId> |
|
| 8 | - <artifactId>mobile</artifactId> |
|
| 9 | - <version>1.0.0-SNAPSHOT</version> |
|
| 10 | - </parent> |
|
| 11 | - <artifactId>com.sap.sailing.android.shared</artifactId> |
|
| 12 | - <packaging>apklib</packaging> |
|
| 3 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | + <parent> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <artifactId>mobile</artifactId> |
|
| 9 | + <version>1.0.0-SNAPSHOT</version> |
|
| 10 | + </parent> |
|
| 11 | + <artifactId>com.sap.sailing.android.shared</artifactId> |
|
| 12 | + <packaging>apklib</packaging> |
|
| 13 | 13 | |
| 14 | - <dependencies> |
|
| 14 | + <dependencies> |
|
| 15 | 15 | <dependency> |
| 16 | 16 | <groupId>com.sap.sailing</groupId> |
| 17 | 17 | <artifactId>org.json.simple</artifactId> |
| ... | ... | @@ -86,12 +86,19 @@ |
| 86 | 86 | <groupId>android</groupId> |
| 87 | 87 | <artifactId>android</artifactId> |
| 88 | 88 | </dependency> |
| 89 | - </dependencies> |
|
| 89 | + |
|
| 90 | + <dependency> |
|
| 91 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 92 | + <artifactId>licensesdialog</artifactId> |
|
| 93 | + <version>1.8.0</version> |
|
| 94 | + <type>aar</type> |
|
| 95 | + </dependency> |
|
| 96 | + </dependencies> |
|
| 90 | 97 | |
| 91 | - <build> |
|
| 92 | - <sourceDirectory>src</sourceDirectory> |
|
| 93 | - <finalName>${project.artifactId}</finalName> |
|
| 94 | - <plugins> |
|
| 98 | + <build> |
|
| 99 | + <sourceDirectory>src</sourceDirectory> |
|
| 100 | + <finalName>${project.artifactId}</finalName> |
|
| 101 | + <plugins> |
|
| 95 | 102 | <plugin> |
| 96 | 103 | <groupId>com.jayway.maven.plugins.android.generation2</groupId> |
| 97 | 104 | <artifactId>android-maven-plugin</artifactId> |
| ... | ... | @@ -101,6 +108,6 @@ |
| 101 | 108 | </sdk> |
| 102 | 109 | </configuration> |
| 103 | 110 | </plugin> |
| 104 | - </plugins> |
|
| 105 | - </build> |
|
| 111 | + </plugins> |
|
| 112 | + </build> |
|
| 106 | 113 | </project> |
mobile/com.sap.sailing.android.shared/project.properties
| ... | ... | @@ -15,3 +15,4 @@ target=Google Inc.:Google APIs:22 |
| 15 | 15 | android.library=true |
| 16 | 16 | |
| 17 | 17 | android.library.reference.1=../google-android-support-v7-appcompat_lib |
| 18 | +android.library.reference.2=../licensesdialog_lib/de.psdev.licensesdialog |
mobile/com.sap.sailing.android.shared/res/layout/fragment_about.xml
| ... | ... | @@ -0,0 +1,64 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|
| 3 | + android:layout_width="match_parent" |
|
| 4 | + android:layout_height="match_parent"> |
|
| 5 | + |
|
| 6 | + <View |
|
| 7 | + android:id="@+id/center_anchor" |
|
| 8 | + android:layout_width="match_parent" |
|
| 9 | + android:layout_height="0dp" |
|
| 10 | + android:layout_centerInParent="true" |
|
| 11 | + /> |
|
| 12 | + |
|
| 13 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansButton |
|
| 14 | + android:id="@+id/licence_button" |
|
| 15 | + android:layout_width="match_parent" |
|
| 16 | + android:layout_height="@dimen/about_button_height" |
|
| 17 | + android:layout_above="@id/center_anchor" |
|
| 18 | + android:layout_centerHorizontal="true" |
|
| 19 | + android:layout_marginBottom="@dimen/about_button_top_bottom_margin" |
|
| 20 | + android:layout_marginLeft="@dimen/about_button_side_margin" |
|
| 21 | + android:layout_marginRight="@dimen/about_button_side_margin" |
|
| 22 | + android:layout_marginTop="@dimen/about_button_top_bottom_margin" |
|
| 23 | + android:background="@drawable/rounded_btn_yellow" |
|
| 24 | + android:text="@string/licence_information" |
|
| 25 | + android:textAllCaps="false" |
|
| 26 | + android:textSize="@dimen/about_button_text_size" |
|
| 27 | + android:textStyle="bold"/> |
|
| 28 | + |
|
| 29 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansButton |
|
| 30 | + android:id="@+id/eula_button" |
|
| 31 | + android:layout_width="match_parent" |
|
| 32 | + android:layout_height="@dimen/about_button_height" |
|
| 33 | + android:layout_below="@id/center_anchor" |
|
| 34 | + android:layout_centerHorizontal="true" |
|
| 35 | + android:layout_marginBottom="@dimen/about_button_top_bottom_margin" |
|
| 36 | + android:layout_marginLeft="@dimen/about_button_side_margin" |
|
| 37 | + android:layout_marginRight="@dimen/about_button_side_margin" |
|
| 38 | + android:layout_marginTop="@dimen/about_button_top_bottom_margin" |
|
| 39 | + android:background="@drawable/rounded_btn_yellow" |
|
| 40 | + android:text="@string/eula" |
|
| 41 | + android:textAllCaps="false" |
|
| 42 | + android:textSize="@dimen/about_button_text_size" |
|
| 43 | + android:textStyle="bold"/> |
|
| 44 | + |
|
| 45 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
|
| 46 | + android:id="@+id/system_information_application_version_header" |
|
| 47 | + android:layout_width="wrap_content" |
|
| 48 | + android:layout_height="wrap_content" |
|
| 49 | + android:text="@string/application_version" |
|
| 50 | + android:layout_marginLeft="@dimen/about_button_side_margin" |
|
| 51 | + android:layout_alignParentLeft="true" |
|
| 52 | + android:layout_alignParentStart="true" |
|
| 53 | + android:layout_below="@id/eula_button"/> |
|
| 54 | + |
|
| 55 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
|
| 56 | + android:id="@+id/system_information_application_version" |
|
| 57 | + android:layout_width="wrap_content" |
|
| 58 | + android:layout_height="wrap_content" |
|
| 59 | + android:layout_marginLeft="@dimen/about_button_side_margin" |
|
| 60 | + android:layout_alignParentLeft="true" |
|
| 61 | + android:layout_alignParentStart="true" |
|
| 62 | + android:layout_below="@id/system_information_application_version_header"/> |
|
| 63 | + |
|
| 64 | +</RelativeLayout> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/res/values-de/eula.xml
| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<resources> |
|
| 3 | + <string name="eula_url">http://www.sap.com/corporate-de/about/legal/privacy</string> |
|
| 4 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/res/values-de/strings.xml
| ... | ... | @@ -32,4 +32,16 @@ |
| 32 | 32 | <string name="your_regattas">Ihre Regattas:</string> |
| 33 | 33 | <string name="options_refresh">Aktualisieren</string> |
| 34 | 34 | |
| 35 | + <!-- Eula --> |
|
| 36 | + <string name="eula_title">Datenschutzbestimmungen</string> |
|
| 37 | + <string name="eula_message">Mit der Verwendung dieser App stimmen Sie den Datenschutzbestimmungen der SAP SE zu. Die Datenschutzbestimmungen finden Sie hier.</string> |
|
| 38 | + <string name="confirm">Zustimmen</string> |
|
| 39 | + <string name="skip">Überspringen</string> |
|
| 40 | + <string name="linked_eula_message_part">hier</string> |
|
| 41 | + |
|
| 42 | + <!-- About this app --> |
|
| 43 | + <string name="about_this_app">Über diese App</string> |
|
| 44 | + <string name="eula">Datenschutz</string> |
|
| 45 | + <string name="licence_information">Lizenzhinweise</string> |
|
| 46 | + |
|
| 35 | 47 | </resources> |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/res/values/colors.xml
| ... | ... | @@ -43,6 +43,7 @@ |
| 43 | 43 | <color name="sap_green">#8AB54E</color> |
| 44 | 44 | <color name="sap_red">#E94A1B</color> |
| 45 | 45 | <color name="sap_yellow">#EEAA29</color> |
| 46 | + <color name="sap_blue">#008FCC</color> |
|
| 46 | 47 | <color name="gray">#333333</color> |
| 47 | 48 | <color name="colorPrimary">@color/gray</color> |
| 48 | 49 | </resources> |
mobile/com.sap.sailing.android.shared/res/values/dimens.xml
| ... | ... | @@ -24,4 +24,10 @@ |
| 24 | 24 | <!-- Default screen margins, per the Android Design guidelines. --> |
| 25 | 25 | <dimen name="activity_horizontal_margin">16dp</dimen> |
| 26 | 26 | |
| 27 | + <!-- Values for buttons --> |
|
| 28 | + <dimen name="about_button_top_bottom_margin">10dp</dimen> |
|
| 29 | + <dimen name="about_button_side_margin">16dp</dimen> |
|
| 30 | + <dimen name="about_button_height">80dp</dimen> |
|
| 31 | + <dimen name="about_button_text_size">18sp</dimen> |
|
| 32 | + |
|
| 27 | 33 | </resources> |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/res/values/eula.xml
| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<resources> |
|
| 3 | + <string name="eula_url">http://www.sap.com/corporate-en/about/legal/privacy</string> |
|
| 4 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/res/values/strings.xml
| ... | ... | @@ -47,4 +47,17 @@ |
| 47 | 47 | <string name="checkin_digest" translatable="false">CheckinDigest</string> |
| 48 | 48 | <string name="leaderboard_name" translatable="false">leaderboard_name</string> |
| 49 | 49 | <string name="mark_id" translatable="false">mark_id</string> |
| 50 | + |
|
| 51 | + <!-- Eula --> |
|
| 52 | + <string name="eula_title">EULA</string> |
|
| 53 | + <string name="eula_message">By using this App you confirm to accept the SAP SE end user license agreement. Please read this EULA here.</string> |
|
| 54 | + <string name="confirm">Confirm</string> |
|
| 55 | + <string name="skip">Skip</string> |
|
| 56 | + <string name="linked_eula_message_part">here</string> |
|
| 57 | + |
|
| 58 | + <!-- About this app --> |
|
| 59 | + <string name="about_this_app">About this app</string> |
|
| 60 | + <string name="eula">EULA</string> |
|
| 61 | + <string name="licence_information">Licence Information</string> |
|
| 62 | + |
|
| 50 | 63 | </resources> |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/ui/activities/AbstractBaseActivity.java
| ... | ... | @@ -25,10 +25,12 @@ public abstract class AbstractBaseActivity extends SendingServiceAwareActivity { |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | public void showProgressDialog(String title, String message) { |
| 28 | - progressDialog = new ProgressDialog(this); |
|
| 29 | - progressDialog.setTitle(title); |
|
| 30 | - progressDialog.setMessage(message); |
|
| 31 | - progressDialog.show(); |
|
| 28 | + if (progressDialog == null || !progressDialog.isShowing()) { |
|
| 29 | + progressDialog = new ProgressDialog(this); |
|
| 30 | + progressDialog.setTitle(title); |
|
| 31 | + progressDialog.setMessage(message); |
|
| 32 | + progressDialog.show(); |
|
| 33 | + } |
|
| 32 | 34 | } |
| 33 | 35 | |
| 34 | 36 | public void showProgressDialog(int string1Id, int string2Id) { |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/ui/activities/AbstractStartActivity.java
| ... | ... | @@ -9,7 +9,6 @@ import com.google.android.gms.common.ConnectionResult; |
| 9 | 9 | import com.google.android.gms.common.GooglePlayServicesUtil; |
| 10 | 10 | import com.sap.sailing.android.shared.BuildConfig; |
| 11 | 11 | import com.sap.sailing.android.shared.R; |
| 12 | -import com.sap.sailing.android.shared.data.AbstractCheckinData; |
|
| 13 | 12 | import com.sap.sailing.android.shared.logging.ExLog; |
| 14 | 13 | import com.sap.sailing.android.shared.ui.customviews.OpenSansToolbar; |
| 15 | 14 | import com.sap.sailing.android.ui.fragments.AbstractHomeFragment; |
| ... | ... | @@ -54,13 +53,6 @@ public abstract class AbstractStartActivity extends CheckinDataActivity { |
| 54 | 53 | intent.setData(null); |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | - @Override |
|
| 58 | - public void onCheckinDataAvailable(AbstractCheckinData data) { |
|
| 59 | - if (data != null) { |
|
| 60 | - getHomeFragment().displayUserConfirmationScreen(data); |
|
| 61 | - } |
|
| 62 | - } |
|
| 63 | - |
|
| 64 | 56 | public abstract AbstractHomeFragment getHomeFragment(); |
| 65 | 57 | |
| 66 | 58 | @Override |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/ui/dialogs/AboutDialog.java
| ... | ... | @@ -1,23 +0,0 @@ |
| 1 | -package com.sap.sailing.android.shared.ui.dialogs; |
|
| 2 | - |
|
| 3 | -import android.app.AlertDialog; |
|
| 4 | -import android.app.Dialog; |
|
| 5 | -import android.content.Context; |
|
| 6 | - |
|
| 7 | -import com.sap.sailing.android.shared.R; |
|
| 8 | -import com.sap.sailing.android.shared.util.AppUtils; |
|
| 9 | - |
|
| 10 | -public class AboutDialog { |
|
| 11 | - private Dialog dialog; |
|
| 12 | - |
|
| 13 | - public AboutDialog(Context context) { |
|
| 14 | - AlertDialog.Builder builder = new AlertDialog.Builder(context); |
|
| 15 | - |
|
| 16 | - builder.setMessage(AppUtils.with(context).getBuildInfo()).setTitle(context.getString(R.string.application_version)); |
|
| 17 | - dialog = builder.create(); |
|
| 18 | - } |
|
| 19 | - |
|
| 20 | - public void show() { |
|
| 21 | - dialog.show(); |
|
| 22 | - } |
|
| 23 | -} |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/EulaHelper.java
| ... | ... | @@ -0,0 +1,97 @@ |
| 1 | +package com.sap.sailing.android.shared.util; |
|
| 2 | + |
|
| 3 | +import android.app.AlertDialog; |
|
| 4 | +import android.content.Context; |
|
| 5 | +import android.content.DialogInterface; |
|
| 6 | +import android.content.Intent; |
|
| 7 | +import android.content.SharedPreferences; |
|
| 8 | +import android.net.Uri; |
|
| 9 | +import android.text.SpannableString; |
|
| 10 | +import android.text.Spanned; |
|
| 11 | +import android.text.method.LinkMovementMethod; |
|
| 12 | +import android.text.style.ClickableSpan; |
|
| 13 | +import android.view.View; |
|
| 14 | +import android.widget.TextView; |
|
| 15 | + |
|
| 16 | +import com.sap.sailing.android.shared.R; |
|
| 17 | + |
|
| 18 | +public class EulaHelper { |
|
| 19 | + |
|
| 20 | + private static final String EULA_PREFERENCES = "eula.preferences"; |
|
| 21 | + private static final String EULA_CONFIRMED = "eula.confirmed"; |
|
| 22 | + |
|
| 23 | + public static void showTrackingEulaDialog(final Context context) { |
|
| 24 | + AlertDialog.Builder builder = new AlertDialog.Builder(context); |
|
| 25 | + builder.setTitle(R.string.eula_title); |
|
| 26 | + builder.setMessage(getSpannableMessage(context)); |
|
| 27 | + builder.setCancelable(false); |
|
| 28 | + builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { |
|
| 29 | + @Override |
|
| 30 | + public void onClick(DialogInterface dialog, int which) { |
|
| 31 | + storeEulaAccepted(context); |
|
| 32 | + } |
|
| 33 | + }); |
|
| 34 | + AlertDialog alertDialog = builder.show(); |
|
| 35 | + ((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + public static void showEulaDialog(final Context context) { |
|
| 39 | + AlertDialog.Builder builder = new AlertDialog.Builder(context); |
|
| 40 | + builder.setTitle(R.string.eula_title); |
|
| 41 | + builder.setMessage(getSpannableMessage(context)); |
|
| 42 | + builder.setCancelable(false); |
|
| 43 | + builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { |
|
| 44 | + @Override |
|
| 45 | + public void onClick(DialogInterface dialog, int which) { |
|
| 46 | + storeEulaAccepted(context); |
|
| 47 | + } |
|
| 48 | + }); |
|
| 49 | + builder.setNegativeButton(R.string.skip, null); |
|
| 50 | + AlertDialog alertDialog = builder.show(); |
|
| 51 | + ((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); |
|
| 52 | + } |
|
| 53 | + |
|
| 54 | + private static void storeEulaAccepted(Context context) { |
|
| 55 | + SharedPreferences preferences = context.getApplicationContext().getSharedPreferences(EULA_PREFERENCES, Context.MODE_PRIVATE); |
|
| 56 | + SharedPreferences.Editor editor = preferences.edit(); |
|
| 57 | + editor.putBoolean(EULA_CONFIRMED, true); |
|
| 58 | + editor.apply(); |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + public static boolean isEulaAccepted(Context context) { |
|
| 62 | + boolean accepted = false; |
|
| 63 | + SharedPreferences preferences = context.getApplicationContext().getSharedPreferences(EULA_PREFERENCES, Context.MODE_PRIVATE); |
|
| 64 | + if (preferences.contains(EULA_CONFIRMED)) { |
|
| 65 | + accepted = preferences.getBoolean(EULA_CONFIRMED, false); |
|
| 66 | + } |
|
| 67 | + return accepted; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + public static void openEulaPage(Context context) { |
|
| 71 | + String url = context.getString(R.string.eula_url); |
|
| 72 | + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); |
|
| 73 | + context.startActivity(browserIntent); |
|
| 74 | + } |
|
| 75 | + |
|
| 76 | + /** |
|
| 77 | + * Prepare text for dialog with clickable text part. |
|
| 78 | + * @param context |
|
| 79 | + * @return |
|
| 80 | + */ |
|
| 81 | + private static SpannableString getSpannableMessage(final Context context) { |
|
| 82 | + String message = context.getString(R.string.eula_message); |
|
| 83 | + String clickableText = context.getString(R.string.linked_eula_message_part); |
|
| 84 | + |
|
| 85 | + SpannableString spannableString = new SpannableString(message); |
|
| 86 | + ClickableSpan clickableSpan = new ClickableSpan() { |
|
| 87 | + @Override |
|
| 88 | + public void onClick(View widget) { |
|
| 89 | + openEulaPage(context); |
|
| 90 | + } |
|
| 91 | + }; |
|
| 92 | + |
|
| 93 | + spannableString.setSpan(clickableSpan, message.indexOf(clickableText), message.indexOf(clickableText) + clickableText.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); |
|
| 94 | + |
|
| 95 | + return spannableString; |
|
| 96 | + } |
|
| 97 | +} |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/LicenseHelper.java
| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | +package com.sap.sailing.android.shared.util; |
|
| 2 | + |
|
| 3 | +import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20; |
|
| 4 | +import de.psdev.licensesdialog.licenses.License; |
|
| 5 | +import de.psdev.licensesdialog.model.Notice; |
|
| 6 | + |
|
| 7 | +public class LicenseHelper { |
|
| 8 | + public Notice getOpenSansNotice() { |
|
| 9 | + String name = "Google Fonts - Open Sans"; |
|
| 10 | + String url = "https://www.google.com/fonts/specimen/Open+Sans"; |
|
| 11 | + String copyright = "Copyright (C) Steve Matteson"; |
|
| 12 | + License license = new ApacheSoftwareLicense20(); |
|
| 13 | + return new Notice(name, url, copyright, license); |
|
| 14 | + } |
|
| 15 | + |
|
| 16 | + public Notice getJsonSimpleNotice() { |
|
| 17 | + String name = "Json Simple"; |
|
| 18 | + String url = "http://code.google.com/p/json-simple/"; |
|
| 19 | + String copyright = "Copyright (C) Yidong Fang"; |
|
| 20 | + License license = new ApacheSoftwareLicense20(); |
|
| 21 | + return new Notice(name, url, copyright, license); |
|
| 22 | + } |
|
| 23 | + |
|
| 24 | + public Notice getAndroidSupportNotice() { |
|
| 25 | + String name = "Android Support Library"; |
|
| 26 | + String url = "http://developer.android.com/tools/support-library/index.html"; |
|
| 27 | + String copyright = "Copyright (C) Google"; |
|
| 28 | + License license = new ApacheSoftwareLicense20(); |
|
| 29 | + return new Notice(name, url, copyright, license); |
|
| 30 | + } |
|
| 31 | + |
|
| 32 | + public Notice getAdvancedRecyclerViewNotice() { |
|
| 33 | + String name = "Advanced RecyclerView"; |
|
| 34 | + String url = "https://github.com/h6ah4i/android-advancedrecyclerview"; |
|
| 35 | + String copyright = "Copyright (C) 2015 Haruki Hasegawa"; |
|
| 36 | + License license = new ApacheSoftwareLicense20(); |
|
| 37 | + return new Notice(name, url, copyright, license); |
|
| 38 | + } |
|
| 39 | + |
|
| 40 | + public Notice getDialogNotice() { |
|
| 41 | + String name = "LicensesDialog"; |
|
| 42 | + String url = "http://psdev.de"; |
|
| 43 | + String copyright = "Copyright 2013 Philip Schiffer <admin@psdev.de>"; |
|
| 44 | + License license = new ApacheSoftwareLicense20(); |
|
| 45 | + return new Notice(name, url, copyright, license); |
|
| 46 | + } |
|
| 47 | +} |
mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/LocationHelper.java
| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | +package com.sap.sailing.android.shared.util; |
|
| 2 | + |
|
| 3 | +import android.content.Context; |
|
| 4 | +import android.content.Intent; |
|
| 5 | +import android.location.LocationManager; |
|
| 6 | + |
|
| 7 | +public class LocationHelper { |
|
| 8 | + |
|
| 9 | + /** |
|
| 10 | + * Helper method to check if device receives gps updates |
|
| 11 | + * @param context |
|
| 12 | + * @return |
|
| 13 | + */ |
|
| 14 | + public static boolean isGPSEnabled(Context context) { |
|
| 15 | + LocationManager service = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); |
|
| 16 | + return service.isProviderEnabled(LocationManager.GPS_PROVIDER); |
|
| 17 | + } |
|
| 18 | + |
|
| 19 | + /** |
|
| 20 | + * Helper method to access androids location settings |
|
| 21 | + * @param context |
|
| 22 | + */ |
|
| 23 | + public static void openLocationSettings(Context context) { |
|
| 24 | + context.startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); |
|
| 25 | + } |
|
| 26 | +} |
mobile/com.sap.sailing.android.tracking.app/.classpath
| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | -<classpath>
|
|
| 3 | - <classpathentry kind="src" path="src"/>
|
|
| 4 | - <classpathentry kind="src" path="gen"/>
|
|
| 5 | - <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
| 6 | - <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
| 7 | - <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
| 8 | - <classpathentry combineaccessrules="false" kind="src" path="/com.sap.sailing.domain.common"/>
|
|
| 9 | - <classpathentry kind="output" path="bin/classes"/>
|
|
| 10 | -</classpath>
|
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<classpath> |
|
| 3 | + <classpathentry kind="src" path="src"/> |
|
| 4 | + <classpathentry kind="src" path="gen"/> |
|
| 5 | + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> |
|
| 6 | + <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> |
|
| 7 | + <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/> |
|
| 8 | + <classpathentry combineaccessrules="false" kind="src" path="/com.sap.sailing.domain.common"/> |
|
| 9 | + <classpathentry kind="output" path="bin/classes"/> |
|
| 10 | +</classpath> |
mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml
| ... | ... | @@ -36,7 +36,7 @@ |
| 36 | 36 | <activity |
| 37 | 37 | android:name=".ui.activities.StartActivity" |
| 38 | 38 | android:label="@string/app_name" |
| 39 | - android:screenOrientation="unspecified"> |
|
| 39 | + android:screenOrientation="portrait"> |
|
| 40 | 40 | <intent-filter> |
| 41 | 41 | <action android:name="android.intent.action.MAIN"/> |
| 42 | 42 | |
| ... | ... | @@ -62,16 +62,24 @@ |
| 62 | 62 | </activity> |
| 63 | 63 | <activity |
| 64 | 64 | android:name=".ui.activities.LeaderboardWebViewActivity" |
| 65 | - android:label="@string/title_activity_webview" |
|
| 66 | - android:screenOrientation="unspecified"> |
|
| 65 | + android:label="@string/title_activity_leaderboard" |
|
| 66 | + android:screenOrientation="portrait"> |
|
| 67 | 67 | <meta-data |
| 68 | 68 | android:name="android.support.PARENT_ACTIVITY" |
| 69 | 69 | android:value=".ui.activities.LeaderboardWebViewActivity"/> |
| 70 | 70 | </activity> |
| 71 | 71 | <activity |
| 72 | + android:name=".ui.activities.EventActivity" |
|
| 73 | + android:label="@string/title_activity_event" |
|
| 74 | + android:screenOrientation="portrait"> |
|
| 75 | + <meta-data |
|
| 76 | + android:name="android.support.PARENT_ACTIVITY" |
|
| 77 | + android:value=".ui.activities.EventActivity"/> |
|
| 78 | + </activity> |
|
| 79 | + <activity |
|
| 72 | 80 | android:name=".ui.activities.RegattaActivity" |
| 73 | 81 | android:label="@string/title_activity_regatta" |
| 74 | - android:screenOrientation="unspecified"> |
|
| 82 | + android:screenOrientation="portrait"> |
|
| 75 | 83 | <meta-data |
| 76 | 84 | android:name="android.support.PARENT_ACTIVITY" |
| 77 | 85 | android:value=".ui.activities.StartActivity"/> |
| ... | ... | @@ -79,14 +87,17 @@ |
| 79 | 87 | <activity |
| 80 | 88 | android:name=".ui.activities.TrackingActivity" |
| 81 | 89 | android:label="@string/title_activity_tracking" |
| 82 | - android:screenOrientation="unspecified"> |
|
| 90 | + android:screenOrientation="portrait"> |
|
| 83 | 91 | <meta-data |
| 84 | 92 | android:name="android.support.PARENT_ACTIVITY" |
| 85 | 93 | android:value=".ui.activities.StartActivity"/> |
| 86 | 94 | </activity> |
| 87 | 95 | <activity |
| 88 | 96 | android:name=".ui.activities.SettingsActivity" |
| 89 | - android:screenOrientation="unspecified"/> |
|
| 97 | + android:screenOrientation="portrait"/> |
|
| 98 | + <activity |
|
| 99 | + android:name=".ui.activities.AboutActivity" |
|
| 100 | + android:screenOrientation="portrait"/> |
|
| 90 | 101 | |
| 91 | 102 | <service |
| 92 | 103 | android:name=".services.TrackingService" |
mobile/com.sap.sailing.android.tracking.app/build.gradle
| ... | ... | @@ -75,6 +75,9 @@ dependencies { |
| 75 | 75 | compile "com.google.android.gms:play-services-gcm:${rootProject.ext.play_services}" |
| 76 | 76 | compile "com.google.android.gms:play-services-location:${rootProject.ext.play_services}" |
| 77 | 77 | |
| 78 | + /* licence dialog */ |
|
| 79 | + compile('de.psdev.licensesdialog:licensesdialog:1.8.0') |
|
| 80 | + |
|
| 78 | 81 | /* local dependencies */ |
| 79 | 82 | compile project(":mobile:com.sap.sailing.android.shared") |
| 80 | 83 |
mobile/com.sap.sailing.android.tracking.app/pom.xml
| ... | ... | @@ -62,6 +62,13 @@ |
| 62 | 62 | <version>1.0.0-SNAPSHOT</version> |
| 63 | 63 | <type>apklib</type> |
| 64 | 64 | </dependency> |
| 65 | + |
|
| 66 | + <dependency> |
|
| 67 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 68 | + <artifactId>licensesdialog</artifactId> |
|
| 69 | + <version>1.8.0</version> |
|
| 70 | + <type>aar</type> |
|
| 71 | + </dependency> |
|
| 65 | 72 | </dependencies> |
| 66 | 73 | |
| 67 | 74 | <build> |
mobile/com.sap.sailing.android.tracking.app/project.properties
| ... | ... | @@ -14,3 +14,4 @@ |
| 14 | 14 | target=Google Inc.:Google APIs:22 |
| 15 | 15 | android.library.reference.1=../google-play-services_lib |
| 16 | 16 | android.library.reference.2=../com.sap.sailing.android.shared |
| 17 | +android.library.reference.3=../licensesdialog_lib/de.psdev.licensesdialog |
mobile/com.sap.sailing.android.tracking.app/res/drawable/rounded_btn_blue.xml
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android"> |
|
| 3 | + |
|
| 4 | + <solid android:color="@color/sap_blue"/> |
|
| 5 | + |
|
| 6 | + <corners |
|
| 7 | + android:bottomLeftRadius="5dip" |
|
| 8 | + android:bottomRightRadius="5dip" |
|
| 9 | + android:topLeftRadius="5dip" |
|
| 10 | + android:topRightRadius="5dip"/> |
|
| 11 | +</shape> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/layout-land/fragment_regatta.xml
| ... | ... | @@ -126,8 +126,9 @@ |
| 126 | 126 | android:layout_width="wrap_content" |
| 127 | 127 | android:layout_height="wrap_content" |
| 128 | 128 | android:layout_above="@+id/competitor_info_layout" |
| 129 | - android:layout_toRightOf="@+id/add_photo" |
|
| 130 | - android:layout_toEndOf="@+id/add_photo" |
|
| 129 | + android:layout_marginRight="10dp" |
|
| 130 | + android:layout_alignParentRight="true" |
|
| 131 | + android:layout_alignParentEnd="true" |
|
| 131 | 132 | android:background="@drawable/background_transparent_box" |
| 132 | 133 | android:orientation="horizontal" |
| 133 | 134 | android:padding="0dp"> |
| ... | ... | @@ -151,6 +152,7 @@ |
| 151 | 152 | android:orientation="vertical" |
| 152 | 153 | android:scrollbars="vertical" |
| 153 | 154 | android:background="@color/black" |
| 155 | + android:fillViewport="true" |
|
| 154 | 156 | android:layout_weight="1"> |
| 155 | 157 | |
| 156 | 158 | <RelativeLayout |
| ... | ... | @@ -201,7 +203,7 @@ |
| 201 | 203 | <LinearLayout |
| 202 | 204 | android:id="@+id/three_boxes_regatta_starts" |
| 203 | 205 | android:layout_width="match_parent" |
| 204 | - android:layout_height="fill_parent" |
|
| 206 | + android:layout_height="wrap_content" |
|
| 205 | 207 | android:layout_below="@+id/regatta_starts_in" |
| 206 | 208 | android:baselineAligned="false" |
| 207 | 209 | android:gravity="center" |
| ... | ... | @@ -303,6 +305,26 @@ |
| 303 | 305 | </LinearLayout> |
| 304 | 306 | </LinearLayout> |
| 305 | 307 | </RelativeLayout> |
| 308 | + |
|
| 309 | + <RelativeLayout |
|
| 310 | + android:layout_width="wrap_content" |
|
| 311 | + android:layout_height="@dimen/regatta_button_height" |
|
| 312 | + android:layout_alignParentBottom="true" |
|
| 313 | + android:paddingBottom="5dp"> |
|
| 314 | + |
|
| 315 | + <com.sap.sailing.android.tracking.app.customviews.OpenSansButton |
|
| 316 | + android:id="@+id/show_event_button" |
|
| 317 | + android:layout_width="match_parent" |
|
| 318 | + android:layout_height="match_parent" |
|
| 319 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 320 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 321 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 322 | + android:padding="@dimen/regatta_button_padding" |
|
| 323 | + android:text="@string/show_event" |
|
| 324 | + android:background="@drawable/rounded_btn_blue" |
|
| 325 | + tools:text="Show Event"/> |
|
| 326 | + |
|
| 327 | + </RelativeLayout> |
|
| 306 | 328 | </RelativeLayout> |
| 307 | 329 | </ScrollView> |
| 308 | 330 | </LinearLayout> |
| ... | ... | @@ -319,9 +341,9 @@ |
| 319 | 341 | <RelativeLayout |
| 320 | 342 | android:id="@+id/start_tracking_box" |
| 321 | 343 | android:layout_width="fill_parent" |
| 322 | - android:layout_height="60dp" |
|
| 344 | + android:layout_height="@dimen/regatta_button_height" |
|
| 323 | 345 | android:layout_above="@id/bottomLayout" |
| 324 | - android:background="@color/gray"> |
|
| 346 | + android:background="@color/black"> |
|
| 325 | 347 | |
| 326 | 348 | <View |
| 327 | 349 | android:id="@+id/white_bar" |
| ... | ... | @@ -342,12 +364,12 @@ |
| 342 | 364 | android:id="@+id/show_leaderboards_button" |
| 343 | 365 | android:layout_width="fill_parent" |
| 344 | 366 | android:layout_height="fill_parent" |
| 345 | - android:layout_margin="10dp" |
|
| 346 | - android:layout_marginLeft="4dp" |
|
| 347 | - android:layout_marginRight="4dp" |
|
| 367 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 368 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 369 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 348 | 370 | android:layout_weight="0.50" |
| 349 | 371 | android:background="@drawable/rounded_btn_yellow" |
| 350 | - android:padding="5dp" |
|
| 372 | + android:padding="@dimen/regatta_button_padding" |
|
| 351 | 373 | android:text="@string/show_leaderboard" |
| 352 | 374 | android:textAllCaps="true" |
| 353 | 375 | android:textStyle="bold"/> |
| ... | ... | @@ -356,12 +378,12 @@ |
| 356 | 378 | android:id="@+id/start_tracking" |
| 357 | 379 | android:layout_width="fill_parent" |
| 358 | 380 | android:layout_height="fill_parent" |
| 359 | - android:layout_margin="10dp" |
|
| 360 | - android:layout_marginLeft="4dp" |
|
| 361 | - android:layout_marginRight="4dp" |
|
| 381 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 382 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 383 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 362 | 384 | android:layout_weight="0.50" |
| 363 | 385 | android:background="@drawable/rounded_btn_green" |
| 364 | - android:padding="5dp" |
|
| 386 | + android:padding="@dimen/regatta_button_padding" |
|
| 365 | 387 | android:text="@string/start_tracking" |
| 366 | 388 | android:textAllCaps="true" |
| 367 | 389 | android:textStyle="bold"/> |
mobile/com.sap.sailing.android.tracking.app/res/layout-land/fragment_speed.xml
| ... | ... | @@ -32,19 +32,7 @@ |
| 32 | 32 | android:layout_centerInParent="true" |
| 33 | 33 | android:gravity="center" |
| 34 | 34 | android:textColor="@color/white" |
| 35 | - android:text="@string/initial_hyphen" |
|
| 36 | - android:textSize="124sp" |
|
| 37 | - android:textStyle="bold"/> |
|
| 38 | - |
|
| 39 | - <com.sap.sailing.android.shared.ui.customviews.AutoResizeLightTextView |
|
| 40 | - android:id="@+id/speed_unit_text_view" |
|
| 41 | - android:layout_width="wrap_content" |
|
| 42 | - android:layout_height="wrap_content" |
|
| 43 | - android:layout_toRightOf="@+id/speed_text_view" |
|
| 44 | - android:layout_toEndOf="@+id/speed_text_view" |
|
| 45 | - android:layout_alignBaseline="@id/speed_text_view" |
|
| 46 | - android:text="@string/knots" |
|
| 47 | - android:textColor="@color/white" |
|
| 35 | + android:singleLine="true" |
|
| 48 | 36 | android:textSize="124sp" |
| 49 | 37 | android:textStyle="bold"/> |
| 50 | 38 | </RelativeLayout> |
mobile/com.sap.sailing.android.tracking.app/res/layout-land/fragment_tracking.xml
| ... | ... | @@ -133,7 +133,7 @@ |
| 133 | 133 | |
| 134 | 134 | <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
| 135 | 135 | android:id="@+id/tracking_time_info_label" |
| 136 | - android:layout_width="fill_parent" |
|
| 136 | + android:layout_width="wrap_content" |
|
| 137 | 137 | android:layout_height="35dp" |
| 138 | 138 | android:layout_alignParentLeft="true" |
| 139 | 139 | android:layout_alignParentStart="true" |
| ... | ... | @@ -143,15 +143,27 @@ |
| 143 | 143 | android:paddingRight="10dp" |
| 144 | 144 | android:text="@string/tracking_time"/> |
| 145 | 145 | |
| 146 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
|
| 147 | + android:id="@+id/wait_for_gps" |
|
| 148 | + android:layout_width="wrap_content" |
|
| 149 | + android:layout_height="35dp" |
|
| 150 | + android:layout_toRightOf="@+id/tracking_time_info_label" |
|
| 151 | + android:layout_toEndOf="@+id/tracking_time_info_label" |
|
| 152 | + android:paddingLeft="10dp" |
|
| 153 | + android:paddingRight="10dp" |
|
| 154 | + android:layout_below="@+id/tracking_status_label" |
|
| 155 | + android:gravity="center_vertical" |
|
| 156 | + android:text="@string/waiting_for_gps"/> |
|
| 157 | + |
|
| 146 | 158 | <com.sap.sailing.android.shared.ui.customviews.AutoResizeTextView |
| 147 | 159 | tools:ignore="InconsistentLayout" |
| 148 | 160 | android:id="@+id/tracking_time_label" |
| 149 | - android:layout_width="match_parent" |
|
| 161 | + android:layout_width="wrap_content" |
|
| 150 | 162 | android:layout_height="35dp" |
| 151 | 163 | android:layout_alignBaseline="@+id/tracking_time_info_label" |
| 152 | 164 | android:layout_alignBottom="@+id/tracking_time_info_label" |
| 153 | - android:layout_alignParentLeft="true" |
|
| 154 | - android:layout_alignParentStart="true" |
|
| 165 | + android:layout_alignParentRight="true" |
|
| 166 | + android:layout_alignParentEnd="true" |
|
| 155 | 167 | android:gravity="end" |
| 156 | 168 | android:paddingLeft="10dp" |
| 157 | 169 | android:paddingRight="10dp" |
mobile/com.sap.sailing.android.tracking.app/res/layout/activity_event.xml
| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|
| 3 | + android:id="@+id/container" |
|
| 4 | + android:orientation="vertical" |
|
| 5 | + android:layout_width="match_parent" |
|
| 6 | + android:layout_height="match_parent"> |
|
| 7 | + |
|
| 8 | +</LinearLayout> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_event.xml
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|
| 3 | + android:layout_width="match_parent" |
|
| 4 | + android:layout_height="match_parent" |
|
| 5 | + android:orientation="vertical"> |
|
| 6 | + |
|
| 7 | + <WebView |
|
| 8 | + android:id="@+id/web_view" |
|
| 9 | + android:layout_width="fill_parent" |
|
| 10 | + android:layout_height="fill_parent"/> |
|
| 11 | + |
|
| 12 | +</LinearLayout> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_regatta.xml
| ... | ... | @@ -312,9 +312,9 @@ |
| 312 | 312 | <RelativeLayout |
| 313 | 313 | android:id="@+id/start_tracking_box" |
| 314 | 314 | android:layout_width="fill_parent" |
| 315 | - android:layout_height="100dp" |
|
| 315 | + android:layout_height="200dp" |
|
| 316 | 316 | android:layout_above="@id/bottomLayout" |
| 317 | - android:background="@color/gray"> |
|
| 317 | + android:background="@color/black"> |
|
| 318 | 318 | |
| 319 | 319 | <View |
| 320 | 320 | android:id="@+id/white_bar" |
| ... | ... | @@ -326,39 +326,63 @@ |
| 326 | 326 | android:background="@color/white_transparent"/> |
| 327 | 327 | |
| 328 | 328 | <LinearLayout |
| 329 | - android:layout_width="fill_parent" |
|
| 330 | - android:layout_height="fill_parent" |
|
| 329 | + android:id="@+id/event_buttons" |
|
| 330 | + android:layout_width="match_parent" |
|
| 331 | + android:layout_height="@dimen/regatta_button_height" |
|
| 331 | 332 | android:layout_below="@id/white_bar" |
| 332 | 333 | android:orientation="horizontal"> |
| 333 | 334 | |
| 335 | + <com.sap.sailing.android.tracking.app.customviews.OpenSansButton |
|
| 336 | + android:id="@+id/show_event_button" |
|
| 337 | + android:layout_width="0dp" |
|
| 338 | + android:layout_height="match_parent" |
|
| 339 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 340 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 341 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 342 | + android:padding="@dimen/regatta_button_padding" |
|
| 343 | + android:layout_weight="1" |
|
| 344 | + android:text="@string/show_event" |
|
| 345 | + android:background="@drawable/rounded_btn_blue" |
|
| 346 | + android:textAllCaps="true" |
|
| 347 | + android:textStyle="bold" |
|
| 348 | + tools:text="Show Event"/> |
|
| 349 | + |
|
| 334 | 350 | <com.sap.sailing.android.shared.ui.customviews.OpenSansButton |
| 335 | 351 | android:id="@+id/show_leaderboards_button" |
| 336 | - android:layout_width="fill_parent" |
|
| 337 | - android:layout_height="fill_parent" |
|
| 338 | - android:layout_margin="10dp" |
|
| 339 | - android:layout_marginLeft="4dp" |
|
| 340 | - android:layout_marginRight="4dp" |
|
| 341 | - android:layout_weight="0.50" |
|
| 352 | + android:layout_width="0dp" |
|
| 353 | + android:layout_height="match_parent" |
|
| 354 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 355 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 356 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 357 | + android:layout_weight="1" |
|
| 342 | 358 | android:background="@drawable/rounded_btn_yellow" |
| 343 | - android:padding="10dp" |
|
| 359 | + android:padding="@dimen/regatta_button_padding" |
|
| 344 | 360 | android:text="@string/show_leaderboard" |
| 345 | 361 | android:textAllCaps="true" |
| 346 | 362 | android:textStyle="bold"/> |
| 347 | 363 | |
| 364 | + </LinearLayout> |
|
| 365 | + |
|
| 366 | + <RelativeLayout |
|
| 367 | + android:layout_width="match_parent" |
|
| 368 | + android:layout_height="@dimen/regatta_button_height" |
|
| 369 | + android:layout_below="@+id/event_buttons"> |
|
| 370 | + |
|
| 348 | 371 | <com.sap.sailing.android.shared.ui.customviews.OpenSansButton |
| 349 | 372 | android:id="@+id/start_tracking" |
| 350 | 373 | android:layout_width="fill_parent" |
| 351 | - android:layout_height="fill_parent" |
|
| 352 | - android:layout_margin="10dp" |
|
| 353 | - android:layout_marginLeft="4dp" |
|
| 354 | - android:layout_marginRight="4dp" |
|
| 355 | - android:layout_weight="0.50" |
|
| 374 | + android:layout_height="match_parent" |
|
| 375 | + android:layout_margin="@dimen/regatta_button_margin" |
|
| 376 | + android:layout_marginLeft="@dimen/regatta_button_side_margin" |
|
| 377 | + android:layout_marginRight="@dimen/regatta_button_side_margin" |
|
| 356 | 378 | android:background="@drawable/rounded_btn_green" |
| 357 | - android:padding="10dp" |
|
| 379 | + android:padding="@dimen/regatta_button_padding" |
|
| 358 | 380 | android:text="@string/start_tracking" |
| 359 | 381 | android:textAllCaps="true" |
| 360 | 382 | android:textStyle="bold"/> |
| 361 | - </LinearLayout> |
|
| 383 | + |
|
| 384 | + </RelativeLayout> |
|
| 385 | + |
|
| 362 | 386 | </RelativeLayout> |
| 363 | 387 | |
| 364 | 388 | <RelativeLayout |
mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_speed.xml
| ... | ... | @@ -30,21 +30,10 @@ |
| 30 | 30 | android:layout_centerInParent="true" |
| 31 | 31 | android:gravity="center" |
| 32 | 32 | android:textColor="@color/white" |
| 33 | - android:text="@string/initial_hyphen" |
|
| 33 | + android:singleLine="true" |
|
| 34 | 34 | android:textSize="124sp" |
| 35 | - android:textStyle="bold"/> |
|
| 36 | - |
|
| 37 | - <com.sap.sailing.android.shared.ui.customviews.AutoResizeLightTextView |
|
| 38 | - android:id="@+id/speed_unit_text_view" |
|
| 39 | - android:layout_width="wrap_content" |
|
| 40 | - android:layout_height="wrap_content" |
|
| 41 | - android:layout_toRightOf="@+id/speed_text_view" |
|
| 42 | - android:layout_toEndOf="@+id/speed_text_view" |
|
| 43 | - android:layout_alignBaseline="@id/speed_text_view" |
|
| 44 | - android:text="@string/knots" |
|
| 45 | - android:textColor="@color/white" |
|
| 46 | - android:textSize="124sp" |
|
| 47 | - android:textStyle="bold"/> |
|
| 48 | - </RelativeLayout> |
|
| 35 | + android:textStyle="bold" |
|
| 36 | + tools:text="13.556Kn"/> |
|
| 37 | + </RelativeLayout> |
|
| 49 | 38 | |
| 50 | 39 | </RelativeLayout> |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_stop_button.xml
| ... | ... | @@ -16,13 +16,24 @@ |
| 16 | 16 | |
| 17 | 17 | <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
| 18 | 18 | android:id="@+id/tracking_time" |
| 19 | - android:layout_width="fill_parent" |
|
| 19 | + android:layout_width="wrap_content" |
|
| 20 | 20 | android:layout_height="wrap_content" |
| 21 | 21 | android:paddingLeft="10dp" |
| 22 | 22 | android:paddingRight="10dp" |
| 23 | 23 | android:layout_alignParentTop="true" |
| 24 | 24 | android:text="@string/tracking_time"/> |
| 25 | 25 | |
| 26 | + <com.sap.sailing.android.shared.ui.customviews.OpenSansTextView |
|
| 27 | + android:id="@+id/wait_for_gps" |
|
| 28 | + android:layout_width="wrap_content" |
|
| 29 | + android:layout_height="wrap_content" |
|
| 30 | + android:layout_toRightOf="@+id/tracking_time" |
|
| 31 | + android:layout_toEndOf="@+id/tracking_time" |
|
| 32 | + android:paddingLeft="10dp" |
|
| 33 | + android:paddingRight="10dp" |
|
| 34 | + android:layout_alignParentTop="true" |
|
| 35 | + android:text="@string/waiting_for_gps"/> |
|
| 36 | + |
|
| 26 | 37 | <com.sap.sailing.android.shared.ui.customviews.AutoResizeLightTextView |
| 27 | 38 | tools:ignore="InconsistentLayout" |
| 28 | 39 | android:id="@+id/tracking_time_label" |
mobile/com.sap.sailing.android.tracking.app/res/values-de/strings.xml
| ... | ... | @@ -17,7 +17,8 @@ |
| 17 | 17 | <string name="tracker_started">SAP Sailing Tracker gestartet</string> |
| 18 | 18 | <string name="tracker_stopped">SAP Sailing Tracker gestoppt</string> |
| 19 | 19 | <string name="title_activity_regatta">Regatta</string> |
| 20 | - <string name="title_activity_webview">Leaderboard</string> |
|
| 20 | + <string name="title_activity_leaderboard">Leaderboard</string> |
|
| 21 | + <string name="title_activity_event">Event</string> |
|
| 21 | 22 | <string name="title_activity_start">GPS Tracker einstellen</string> |
| 22 | 23 | <string name="title_activity_tracking">Tracking</string> |
| 23 | 24 | <string name="please_confirm">Bitte bestätigen</string> |
| ... | ... | @@ -64,14 +65,17 @@ |
| 64 | 65 | <string name="speed_over_ground">Speed over Ground</string> |
| 65 | 66 | <string name="none">Keine</string> |
| 66 | 67 | <string name="show_leaderboard">Leaderboard</string> |
| 68 | + <string name="show_event">Zum Event</string> |
|
| 67 | 69 | <string name="desc_regatta_user_image">Benutzerdefiniertes Bild für Regatta</string> |
| 68 | 70 | <string name="desc_add_photo_button">Foto hinzufügen Button</string> |
| 69 | 71 | <string name="error_while_receiving_server_data">Fehler beim Empfang vom Server</string> |
| 70 | 72 | <string name="info_already_checked_in_this_qr_code">Bereits für diese Regatta eingecheckt</string> |
| 71 | 73 | <string name="warning">Warnung</string> |
| 74 | + <string name="enable_gps">GPS ist nicht aktiviert. Das Tracking erfordert GPS Positionen. Möchten Sie GPS in den Einstellungen aktivieren?</string> |
|
| 72 | 75 | <string name="gps_turned_off">GPS ist nicht aktiviert. Bitte aktivieren Sie den Standortzugriff (GPS) in Ihren Android-Einstellungen!</string> |
| 73 | - <string name="knots">Kn</string> |
|
| 76 | + <string name="knots">%sKn</string> |
|
| 74 | 77 | <string name="preferences">Einstellungen</string> |
| 75 | 78 | <string name="tracking_notification_text">Tracking läuft für %s</string> |
| 79 | + <string name="waiting_for_gps">Warte auf GPS-Signal</string> |
|
| 76 | 80 | |
| 77 | 81 | </resources> |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/values-land/dimens.xml
| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<resources> |
|
| 3 | + |
|
| 4 | + <!-- Values for regatta buttons--> |
|
| 5 | + <dimen name="regatta_button_height">60dp</dimen> |
|
| 6 | + <dimen name="regatta_button_padding">5dp</dimen> |
|
| 7 | + |
|
| 8 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/res/values/api_endpoints.xml
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | <string name="preference_server_checkin_path" translatable="false">/sailingserver/api/v1/leaderboards/{leaderboard-name}/device_mappings/start</string> |
| 5 | 5 | <string name="preference_server_checkout_path" translatable="false">/sailingserver/api/v1/leaderboards/{leaderboard-name}/device_mappings/end</string> |
| 6 | 6 | <string name="preference_server_event_path" translatable="false">/sailingserver/api/v1/events/{event_id}</string> |
| 7 | + <string name="preference_server_event_url" translatable="false">/gwt/Home.html?navigationTab=Regattas#EventPlace:eventId=%s</string> |
|
| 7 | 8 | <string name="preference_server_leaderboard_path" translatable="false">/sailingserver/api/v1/leaderboards/{leaderboard_name}</string> |
| 8 | 9 | <string name="preference_server_competitor_path" translatable="false">/sailingserver/api/v1/competitors/{competitor_id}</string> |
| 9 | 10 | <string name="preference_server_team_info_path" translatable="false">/sailingserver/api/v1/competitors/{competitor_id}/team</string> |
mobile/com.sap.sailing.android.tracking.app/res/values/dimens.xml
| ... | ... | @@ -4,4 +4,10 @@ |
| 4 | 4 | <dimen name="activity_horizontal_margin">16dp</dimen> |
| 5 | 5 | <!-- <dimen name="activity_vertical_margin">16dp</dimen> --> |
| 6 | 6 | |
| 7 | + <!-- Values for regatta buttons--> |
|
| 8 | + <dimen name="regatta_button_height">90dp</dimen> |
|
| 9 | + <dimen name="regatta_button_side_margin">4dp</dimen> |
|
| 10 | + <dimen name="regatta_button_margin">10dp</dimen> |
|
| 11 | + <dimen name="regatta_button_padding">10dp</dimen> |
|
| 12 | + |
|
| 7 | 13 | </resources> |
mobile/com.sap.sailing.android.tracking.app/res/values/strings.xml
| ... | ... | @@ -12,7 +12,8 @@ |
| 12 | 12 | <string name="tracker_started">SAP Sailing Tracker started</string> |
| 13 | 13 | <string name="tracker_stopped">SAP Sailing Tracker stopped</string> |
| 14 | 14 | <string name="title_activity_regatta">Regatta</string> |
| 15 | - <string name="title_activity_webview">Leader board</string> |
|
| 15 | + <string name="title_activity_leaderboard">Leader board</string> |
|
| 16 | + <string name="title_activity_event">Event</string> |
|
| 16 | 17 | <string name="title_activity_start">Setup GPS-Tracker</string> |
| 17 | 18 | <string name="title_activity_tracking">Tracking</string> |
| 18 | 19 | <string name="please_confirm">Please confirm</string> |
| ... | ... | @@ -47,11 +48,13 @@ |
| 47 | 48 | <string name="speed_over_ground">Speed over Ground</string> |
| 48 | 49 | <string name="none">None</string> |
| 49 | 50 | <string name="show_leaderboard">Leader board</string> |
| 51 | + <string name="show_event">Event</string> |
|
| 50 | 52 | <string name="error_while_receiving_server_data">Error while receiving server data</string> |
| 51 | 53 | <string name="info_already_checked_in_this_qr_code">Already checked in to this regatta</string> |
| 52 | 54 | <string name="warning">Warning</string> |
| 55 | + <string name="enable_gps">GPS is turned off. Tracking requires GPS positions. Do you want to turn on GPS in the location settings?</string> |
|
| 53 | 56 | <string name="gps_turned_off">GPS is turned off. Please turn on location access (GPS) in your Android Settings!</string> |
| 54 | - <string name="knots">Kn</string> |
|
| 57 | + <string name="knots">%sKn</string> |
|
| 55 | 58 | <string name="preferences">Preferences</string> |
| 56 | 59 | |
| 57 | 60 | <string name="initial_timer_text_zerozero" translatable="false">00:00:00</string> |
| ... | ... | @@ -59,4 +62,5 @@ |
| 59 | 62 | <string name="initial_hyphen_degrees" translatable="false">-°</string> |
| 60 | 63 | <string name="content_description_flag_icon" translatable="false">flag icon</string> |
| 61 | 64 | <string name="tracking_notification_text">Currently Tracking %s</string> |
| 65 | + <string name="waiting_for_gps">Waiting for GPS</string> |
|
| 62 | 66 | </resources> |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TrackingService.java
| ... | ... | @@ -60,6 +60,7 @@ public class TrackingService extends Service implements GoogleApiClient.Connecti |
| 60 | 60 | private final int UPDATE_INTERVAL_DEFAULT = 3000; |
| 61 | 61 | private final int UPDATE_INTERVAL_POWERSAVE_MODE = 30000; |
| 62 | 62 | private final float BATTERY_POWER_SAVE_TRESHOLD = 0.2f; |
| 63 | + private boolean initialLocation; |
|
| 63 | 64 | |
| 64 | 65 | private String checkinDigest; |
| 65 | 66 | private EventInfo event; |
| ... | ... | @@ -69,6 +70,7 @@ public class TrackingService extends Service implements GoogleApiClient.Connecti |
| 69 | 70 | super.onCreate(); |
| 70 | 71 | prefs = new AppPreferences(this); |
| 71 | 72 | |
| 73 | + initialLocation = true; |
|
| 72 | 74 | // http://developer.android.com/training/location/receive-location-updates.html |
| 73 | 75 | locationRequest = LocationRequest.create(); |
| 74 | 76 | locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); |
| ... | ... | @@ -180,6 +182,9 @@ public class TrackingService extends Service implements GoogleApiClient.Connecti |
| 180 | 182 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) |
| 181 | 183 | @Override |
| 182 | 184 | public void onLocationChanged(Location location) { |
| 185 | + if (initialLocation) { |
|
| 186 | + storeInitialTrackingTimestamp(); |
|
| 187 | + } |
|
| 183 | 188 | updateResendIntervalSetting(); |
| 184 | 189 | reportGPSQualityBearingAndSpeed(location.getAccuracy(), location.getBearing(), location.getSpeed(), |
| 185 | 190 | location.getLatitude(), location.getLongitude(), location.getAltitude()); |
| ... | ... | @@ -210,6 +215,13 @@ public class TrackingService extends Service implements GoogleApiClient.Connecti |
| 210 | 215 | } |
| 211 | 216 | } |
| 212 | 217 | |
| 218 | + private void storeInitialTrackingTimestamp() { |
|
| 219 | + if (prefs.getTrackingTimerStarted() == 0) { |
|
| 220 | + prefs.setTrackingTimerStarted(System.currentTimeMillis()); |
|
| 221 | + } |
|
| 222 | + initialLocation = false; |
|
| 223 | + } |
|
| 224 | + |
|
| 213 | 225 | /** |
| 214 | 226 | * Update whether message sending service should retry every 3 seconds or every 30. |
| 215 | 227 | */ |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/AboutActivity.java
| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | +package com.sap.sailing.android.tracking.app.ui.activities; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | +import android.view.Menu; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.android.shared.ui.customviews.OpenSansToolbar; |
|
| 7 | +import com.sap.sailing.android.tracking.app.R; |
|
| 8 | +import com.sap.sailing.android.tracking.app.ui.fragments.AboutFragment; |
|
| 9 | + |
|
| 10 | +public class AboutActivity extends BaseActivity { |
|
| 11 | + |
|
| 12 | + @Override |
|
| 13 | + protected void onCreate(Bundle savedInstanceState) { |
|
| 14 | + super.onCreate(savedInstanceState); |
|
| 15 | + setContentView(com.sap.sailing.android.shared.R.layout.fragment_container); |
|
| 16 | + |
|
| 17 | + OpenSansToolbar toolbar = (OpenSansToolbar) findViewById(R.id.toolbar); |
|
| 18 | + if (toolbar != null) { |
|
| 19 | + toolbar.hideSubtitle(); |
|
| 20 | + toolbar.setTitleSize(20); |
|
| 21 | + setSupportActionBar(toolbar); |
|
| 22 | + toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); |
|
| 23 | + } |
|
| 24 | + if (getSupportActionBar() != null) { |
|
| 25 | + getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
|
| 26 | + getSupportActionBar().setHomeButtonEnabled(true); |
|
| 27 | + toolbar.setNavigationIcon(R.drawable.sap_logo_64_sq); |
|
| 28 | + toolbar.setPadding(20, 0, 0, 0); |
|
| 29 | + toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); |
|
| 30 | + getSupportActionBar().setTitle(R.string.about_this_app); |
|
| 31 | + } |
|
| 32 | + replaceFragment(R.id.content_frame, AboutFragment.newInstance()); |
|
| 33 | + } |
|
| 34 | + |
|
| 35 | + /** |
|
| 36 | + * Empty method to avoid creation of parent menu. |
|
| 37 | + */ |
|
| 38 | + @Override |
|
| 39 | + public boolean onCreateOptionsMenu(Menu menu) { |
|
| 40 | + return true; |
|
| 41 | + } |
|
| 42 | +} |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/BaseActivity.java
| ... | ... | @@ -8,8 +8,8 @@ import android.view.MenuItem; |
| 8 | 8 | |
| 9 | 9 | import com.sap.sailing.android.shared.logging.ExLog; |
| 10 | 10 | import com.sap.sailing.android.shared.ui.activities.AbstractBaseActivity; |
| 11 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 12 | 11 | import com.sap.sailing.android.tracking.app.R; |
| 12 | +import com.sap.sailing.android.tracking.app.utils.AboutHelper; |
|
| 13 | 13 | import com.sap.sailing.android.tracking.app.utils.AppPreferences; |
| 14 | 14 | |
| 15 | 15 | public class BaseActivity extends AbstractBaseActivity { |
| ... | ... | @@ -33,18 +33,15 @@ public class BaseActivity extends AbstractBaseActivity { |
| 33 | 33 | @Override |
| 34 | 34 | public boolean onOptionsItemSelected(MenuItem item) { |
| 35 | 35 | switch (item.getItemId()) { |
| 36 | - case R.id.options_menu_settings: |
|
| 37 | - ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 38 | - startActivity(new Intent(this, SettingsActivity.class)); |
|
| 39 | - return true; |
|
| 40 | - case R.id.options_menu_info: |
|
| 41 | - ExLog.i(this, TAG, "Clicked INFO."); |
|
| 42 | - AboutDialog dialog = new AboutDialog(this); |
|
| 43 | - dialog.show(); |
|
| 44 | - // startActivity(new Intent(this, SystemInformationActivity.class)); |
|
| 45 | - return true; |
|
| 46 | - default: |
|
| 47 | - return super.onOptionsItemSelected(item); |
|
| 36 | + case R.id.options_menu_settings: |
|
| 37 | + ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 38 | + startActivity(new Intent(this, SettingsActivity.class)); |
|
| 39 | + return true; |
|
| 40 | + case R.id.options_menu_info: |
|
| 41 | + AboutHelper.showInfoActivity(this); |
|
| 42 | + return true; |
|
| 43 | + default: |
|
| 44 | + return super.onOptionsItemSelected(item); |
|
| 48 | 45 | } |
| 49 | 46 | } |
| 50 | 47 |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/EventActivity.java
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +package com.sap.sailing.android.tracking.app.ui.activities; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | + |
|
| 5 | +import com.sap.sailing.android.tracking.app.R; |
|
| 6 | +import com.sap.sailing.android.tracking.app.ui.fragments.EventFragment; |
|
| 7 | +import com.sap.sailing.android.tracking.app.valueobjects.EventInfo; |
|
| 8 | + |
|
| 9 | +public class EventActivity extends BaseActivity { |
|
| 10 | + |
|
| 11 | + public final static String EVENT = "event.info"; |
|
| 12 | + |
|
| 13 | + @Override |
|
| 14 | + protected void onCreate(Bundle savedInstanceState) { |
|
| 15 | + super.onCreate(savedInstanceState); |
|
| 16 | + EventInfo eventInfo = getIntent().getParcelableExtra(EVENT); |
|
| 17 | + |
|
| 18 | + setContentView(R.layout.activity_event); |
|
| 19 | + |
|
| 20 | + replaceFragment(R.id.container, EventFragment.newInstance(eventInfo)); |
|
| 21 | + } |
|
| 22 | +} |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/LeaderboardWebViewActivity.java
| ... | ... | @@ -37,7 +37,7 @@ public class LeaderboardWebViewActivity extends BaseActivity { |
| 37 | 37 | getSupportActionBar().setHomeButtonEnabled(true); |
| 38 | 38 | toolbar.setNavigationIcon(R.drawable.sap_logo_64_sq); |
| 39 | 39 | toolbar.setPadding(20, 0, 0, 0); |
| 40 | - getSupportActionBar().setTitle(getString(R.string.title_activity_webview)); |
|
| 40 | + getSupportActionBar().setTitle(getString(R.string.title_activity_leaderboard)); |
|
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | replaceFragment(R.id.content_frame, new LeaderboardFragment()); |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java
| ... | ... | @@ -43,7 +43,6 @@ import com.sap.sailing.android.shared.data.http.HttpGetRequest; |
| 43 | 43 | import com.sap.sailing.android.shared.data.http.HttpJsonPostRequest; |
| 44 | 44 | import com.sap.sailing.android.shared.logging.ExLog; |
| 45 | 45 | import com.sap.sailing.android.shared.ui.activities.AbstractRegattaActivity; |
| 46 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 47 | 46 | import com.sap.sailing.android.shared.util.NetworkHelper; |
| 48 | 47 | import com.sap.sailing.android.shared.util.NetworkHelper.NetworkHelperError; |
| 49 | 48 | import com.sap.sailing.android.shared.util.NetworkHelper.NetworkHelperFailureListener; |
| ... | ... | @@ -52,6 +51,7 @@ import com.sap.sailing.android.shared.util.UniqueDeviceUuid; |
| 52 | 51 | import com.sap.sailing.android.tracking.app.BuildConfig; |
| 53 | 52 | import com.sap.sailing.android.tracking.app.R; |
| 54 | 53 | import com.sap.sailing.android.tracking.app.ui.fragments.RegattaFragment; |
| 54 | +import com.sap.sailing.android.tracking.app.utils.AboutHelper; |
|
| 55 | 55 | import com.sap.sailing.android.tracking.app.utils.AppPreferences; |
| 56 | 56 | import com.sap.sailing.android.tracking.app.utils.BitmapHelper; |
| 57 | 57 | import com.sap.sailing.android.tracking.app.utils.CheckinManager; |
| ... | ... | @@ -89,7 +89,7 @@ public class RegattaActivity extends AbstractRegattaActivity implements RegattaF |
| 89 | 89 | checkinDigest = intent.getStringExtra(getString(R.string.checkin_digest)); |
| 90 | 90 | |
| 91 | 91 | checkinUrl = DatabaseHelper.getInstance().getCheckinUrl(this, checkinDigest); |
| 92 | - manager = new CheckinManager(checkinUrl.urlString, this); |
|
| 92 | + manager = new CheckinManager(checkinUrl.urlString, this, false); |
|
| 93 | 93 | |
| 94 | 94 | competitor = DatabaseHelper.getInstance().getCompetitor(this, checkinDigest); |
| 95 | 95 | event = DatabaseHelper.getInstance().getEventInfo(this, checkinDigest); |
| ... | ... | @@ -144,28 +144,26 @@ public class RegattaActivity extends AbstractRegattaActivity implements RegattaF |
| 144 | 144 | @Override |
| 145 | 145 | public boolean onOptionsItemSelected(MenuItem item) { |
| 146 | 146 | switch (item.getItemId()) { |
| 147 | - case R.id.options_menu_settings: |
|
| 148 | - ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 149 | - startActivity(new Intent(this, SettingsActivity.class)); |
|
| 150 | - return true; |
|
| 151 | - case R.id.options_menu_checkout: |
|
| 152 | - ExLog.i(this, TAG, "Clicked CHECKOUT."); |
|
| 153 | - checkout(); |
|
| 154 | - return true; |
|
| 155 | - case R.id.options_menu_add_team_image: |
|
| 156 | - ExLog.i(this, TAG, "Clicked ADD TEAM IMAGE"); |
|
| 157 | - getRegattaFragment().showChooseExistingPictureOrTakeNewPhotoAlert(); |
|
| 158 | - return true; |
|
| 159 | - case R.id.options_menu_refresh: |
|
| 160 | - manager.callServerAndGenerateCheckinData(); |
|
| 161 | - return true; |
|
| 162 | - case R.id.options_menu_info: |
|
| 163 | - ExLog.i(this, TAG, "Clicked INFO."); |
|
| 164 | - AboutDialog dialog = new AboutDialog(this); |
|
| 165 | - dialog.show(); |
|
| 166 | - return true; |
|
| 167 | - default: |
|
| 168 | - return super.onOptionsItemSelected(item); |
|
| 147 | + case R.id.options_menu_settings: |
|
| 148 | + ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 149 | + startActivity(new Intent(this, SettingsActivity.class)); |
|
| 150 | + return true; |
|
| 151 | + case R.id.options_menu_checkout: |
|
| 152 | + ExLog.i(this, TAG, "Clicked CHECKOUT."); |
|
| 153 | + checkout(); |
|
| 154 | + return true; |
|
| 155 | + case R.id.options_menu_add_team_image: |
|
| 156 | + ExLog.i(this, TAG, "Clicked ADD TEAM IMAGE"); |
|
| 157 | + getRegattaFragment().showChooseExistingPictureOrTakeNewPhotoAlert(); |
|
| 158 | + return true; |
|
| 159 | + case R.id.options_menu_refresh: |
|
| 160 | + manager.callServerAndGenerateCheckinData(); |
|
| 161 | + return true; |
|
| 162 | + case R.id.options_menu_info: |
|
| 163 | + AboutHelper.showInfoActivity(this); |
|
| 164 | + return true; |
|
| 165 | + default: |
|
| 166 | + return super.onOptionsItemSelected(item); |
|
| 169 | 167 | } |
| 170 | 168 | } |
| 171 | 169 |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/StartActivity.java
| ... | ... | @@ -1,17 +1,24 @@ |
| 1 | 1 | package com.sap.sailing.android.tracking.app.ui.activities; |
| 2 | 2 | |
| 3 | +import java.util.List; |
|
| 4 | + |
|
| 3 | 5 | import android.content.Intent; |
| 4 | 6 | import android.os.Bundle; |
| 5 | 7 | import android.view.Menu; |
| 6 | 8 | import android.view.MenuInflater; |
| 7 | 9 | import android.view.MenuItem; |
| 8 | 10 | |
| 11 | +import com.sap.sailing.android.shared.data.AbstractCheckinData; |
|
| 9 | 12 | import com.sap.sailing.android.shared.logging.ExLog; |
| 10 | 13 | import com.sap.sailing.android.shared.ui.activities.AbstractStartActivity; |
| 11 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 14 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 12 | 15 | import com.sap.sailing.android.tracking.app.R; |
| 13 | 16 | import com.sap.sailing.android.tracking.app.ui.fragments.HomeFragment; |
| 17 | +import com.sap.sailing.android.tracking.app.utils.AboutHelper; |
|
| 14 | 18 | import com.sap.sailing.android.tracking.app.utils.AppPreferences; |
| 19 | +import com.sap.sailing.android.tracking.app.utils.CheckinManager; |
|
| 20 | +import com.sap.sailing.android.tracking.app.utils.DatabaseHelper; |
|
| 21 | +import com.sap.sailing.android.tracking.app.valueobjects.CheckinData; |
|
| 15 | 22 | import com.sap.sailing.android.ui.fragments.AbstractHomeFragment; |
| 16 | 23 | |
| 17 | 24 | public class StartActivity extends AbstractStartActivity { |
| ... | ... | @@ -28,6 +35,7 @@ public class StartActivity extends AbstractStartActivity { |
| 28 | 35 | getSupportActionBar().setHomeButtonEnabled(false); |
| 29 | 36 | } |
| 30 | 37 | replaceFragment(R.id.content_frame, new HomeFragment()); |
| 38 | + refreshDatabase(); |
|
| 31 | 39 | } |
| 32 | 40 | |
| 33 | 41 | @Override |
| ... | ... | @@ -41,6 +49,14 @@ public class StartActivity extends AbstractStartActivity { |
| 41 | 49 | } |
| 42 | 50 | |
| 43 | 51 | @Override |
| 52 | + protected void onResume() { |
|
| 53 | + super.onResume(); |
|
| 54 | + if (!EulaHelper.isEulaAccepted(this)) { |
|
| 55 | + EulaHelper.showTrackingEulaDialog(this); |
|
| 56 | + } |
|
| 57 | + } |
|
| 58 | + |
|
| 59 | + @Override |
|
| 44 | 60 | public AbstractHomeFragment getHomeFragment() { |
| 45 | 61 | HomeFragment homeFragment = (HomeFragment) getSupportFragmentManager().findFragmentById(R.id.content_frame); |
| 46 | 62 | return homeFragment; |
| ... | ... | @@ -62,18 +78,15 @@ public class StartActivity extends AbstractStartActivity { |
| 62 | 78 | @Override |
| 63 | 79 | public boolean onOptionsItemSelected(MenuItem item) { |
| 64 | 80 | switch (item.getItemId()) { |
| 65 | - case R.id.options_menu_settings: |
|
| 66 | - ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 67 | - startActivity(new Intent(this, SettingsActivity.class)); |
|
| 68 | - return true; |
|
| 69 | - case R.id.options_menu_info: |
|
| 70 | - ExLog.i(this, TAG, "Clicked INFO."); |
|
| 71 | - AboutDialog dialog = new AboutDialog(this); |
|
| 72 | - dialog.show(); |
|
| 73 | - // startActivity(new Intent(this, SystemInformationActivity.class)); |
|
| 74 | - return true; |
|
| 75 | - default: |
|
| 76 | - return super.onOptionsItemSelected(item); |
|
| 81 | + case R.id.options_menu_settings: |
|
| 82 | + ExLog.i(this, TAG, "Clicked SETTINGS."); |
|
| 83 | + startActivity(new Intent(this, SettingsActivity.class)); |
|
| 84 | + return true; |
|
| 85 | + case R.id.options_menu_info: |
|
| 86 | + AboutHelper.showInfoActivity(this); |
|
| 87 | + return true; |
|
| 88 | + default: |
|
| 89 | + return super.onOptionsItemSelected(item); |
|
| 77 | 90 | } |
| 78 | 91 | } |
| 79 | 92 | |
| ... | ... | @@ -81,4 +94,38 @@ public class StartActivity extends AbstractStartActivity { |
| 81 | 94 | protected int getOptionsMenuResId() { |
| 82 | 95 | return R.menu.options_menu; |
| 83 | 96 | } |
| 97 | + |
|
| 98 | + @Override |
|
| 99 | + public void onCheckinDataAvailable(AbstractCheckinData data) { |
|
| 100 | + if(data != null && data instanceof CheckinData) { |
|
| 101 | + CheckinData checkinData = (CheckinData) data; |
|
| 102 | + if (!checkinData.isUpdate()) { |
|
| 103 | + getHomeFragment().displayUserConfirmationScreen(data); |
|
| 104 | + } else if (checkinData.isUpdate()) { |
|
| 105 | + updateRegatta(data); |
|
| 106 | + } |
|
| 107 | + } |
|
| 108 | + } |
|
| 109 | + |
|
| 110 | + private void updateRegatta(AbstractCheckinData data) { |
|
| 111 | + if (data instanceof CheckinData) |
|
| 112 | + { |
|
| 113 | + CheckinData checkinData = (CheckinData) data; |
|
| 114 | + try { |
|
| 115 | + DatabaseHelper.getInstance().deleteRegattaFromDatabase(this, checkinData.getCheckinUrl().checkinDigest); |
|
| 116 | + DatabaseHelper.getInstance().storeCheckinRow(this, checkinData.getEvent(), checkinData.getCompetitor(), checkinData.getLeaderboard(), checkinData.getCheckinUrl()); |
|
| 117 | + } catch (DatabaseHelper.GeneralDatabaseHelperException e) { |
|
| 118 | + ExLog.e(this, TAG, "Batch insert failed: " + e.getMessage()); |
|
| 119 | + displayDatabaseError(); |
|
| 120 | + } |
|
| 121 | + } |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + private void refreshDatabase() { |
|
| 125 | + List<String> checkinUrls = DatabaseHelper.getInstance().getCheckinUrls(this); |
|
| 126 | + for(String checkinUrl : checkinUrls) { |
|
| 127 | + CheckinManager manager = new CheckinManager(checkinUrl, this, true); |
|
| 128 | + manager.callServerAndGenerateCheckinData(); |
|
| 129 | + } |
|
| 130 | + } |
|
| 84 | 131 | } |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java
| ... | ... | @@ -15,6 +15,7 @@ import android.support.v4.app.FragmentStatePagerAdapter; |
| 15 | 15 | import android.support.v4.view.ViewPager; |
| 16 | 16 | import android.support.v4.view.ViewPager.OnPageChangeListener; |
| 17 | 17 | import android.support.v7.widget.Toolbar; |
| 18 | +import android.view.View; |
|
| 18 | 19 | import android.widget.TextView; |
| 19 | 20 | |
| 20 | 21 | import com.sap.sailing.android.shared.logging.ExLog; |
| ... | ... | @@ -41,7 +42,8 @@ import com.viewpagerindicator.CirclePageIndicator; |
| 41 | 42 | public class TrackingActivity extends BaseActivity implements GPSQualityListener, APIConnectivityListener { |
| 42 | 43 | |
| 43 | 44 | TrackingService trackingService; |
| 44 | - boolean trackingServiceBound; |
|
| 45 | + private boolean trackingServiceBound; |
|
| 46 | + private boolean gpsReceived; |
|
| 45 | 47 | |
| 46 | 48 | MessageSendingService messageSendingService; |
| 47 | 49 | boolean messageSendingServiceBound; |
| ... | ... | @@ -75,9 +77,13 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 75 | 77 | super.onCreate(savedInstanceState); |
| 76 | 78 | |
| 77 | 79 | prefs = new AppPreferences(this); |
| 78 | - |
|
| 79 | - checkinDigest = getIntent().getExtras().getString( |
|
| 80 | - getString(R.string.tracking_activity_checkin_digest_parameter)); |
|
| 80 | + Bundle extras = getIntent().getExtras(); |
|
| 81 | + if (extras != null) { |
|
| 82 | + checkinDigest = extras.getString(getString(R.string.tracking_activity_checkin_digest_parameter)); |
|
| 83 | + } else { |
|
| 84 | + checkinDigest = prefs.getTrackerIsTrackingCheckinDigest(); |
|
| 85 | + } |
|
| 86 | + lastSpeedIndicatorText = getString(R.string.initial_hyphen); |
|
| 81 | 87 | |
| 82 | 88 | setContentView(R.layout.fragment_hud_container); |
| 83 | 89 | |
| ... | ... | @@ -169,6 +175,12 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 169 | 175 | } |
| 170 | 176 | |
| 171 | 177 | @Override |
| 178 | + protected void onDestroy() { |
|
| 179 | + ServiceHelper.getInstance().stopTrackingService(this); |
|
| 180 | + super.onDestroy(); |
|
| 181 | + } |
|
| 182 | + |
|
| 183 | + @Override |
|
| 172 | 184 | public void onStop() { |
| 173 | 185 | super.onStop(); |
| 174 | 186 | if (trackingServiceBound) { |
| ... | ... | @@ -207,7 +219,8 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 207 | 219 | super.onResume(); |
| 208 | 220 | |
| 209 | 221 | timer = new TimerRunnable(); |
| 210 | - timer.start(); |
|
| 222 | + Thread thread = new Thread(timer); |
|
| 223 | + thread.start(); |
|
| 211 | 224 | |
| 212 | 225 | if (mPagerAdapter == null) { |
| 213 | 226 | mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager()); |
| ... | ... | @@ -218,7 +231,7 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 218 | 231 | |
| 219 | 232 | LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE); |
| 220 | 233 | boolean gpsEnabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER); |
| 221 | - if (gpsEnabled == false) { |
|
| 234 | + if (!gpsEnabled) { |
|
| 222 | 235 | showErrorPopup(R.string.warning, R.string.gps_turned_off); |
| 223 | 236 | } |
| 224 | 237 | } |
| ... | ... | @@ -386,10 +399,24 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 386 | 399 | * Update UI with a string containing the time since tracking started, e.g. 01:22:45 |
| 387 | 400 | */ |
| 388 | 401 | public void updateTimer() { |
| 389 | - long diff = System.currentTimeMillis() - prefs.getTrackingTimerStarted(); |
|
| 390 | - TextView textView = (TextView) findViewById(R.id.tracking_time_label); |
|
| 391 | - if (textView != null) { |
|
| 392 | - textView.setText(getTimeFormatString(diff)); |
|
| 402 | + long trackingTimerStarted = prefs.getTrackingTimerStarted(); |
|
| 403 | + if (trackingTimerStarted > 0) { |
|
| 404 | + hideWaitForGPSText(); |
|
| 405 | + long diff = System.currentTimeMillis() - trackingTimerStarted; |
|
| 406 | + TextView textView = (TextView) findViewById(R.id.tracking_time_label); |
|
| 407 | + if (textView != null) { |
|
| 408 | + textView.setText(getTimeFormatString(diff)); |
|
| 409 | + } |
|
| 410 | + } |
|
| 411 | + } |
|
| 412 | + |
|
| 413 | + private void hideWaitForGPSText() { |
|
| 414 | + if (!gpsReceived) { |
|
| 415 | + View waitForGPSLabel = findViewById(R.id.wait_for_gps); |
|
| 416 | + if (waitForGPSLabel != null) { |
|
| 417 | + waitForGPSLabel.setVisibility(View.GONE); |
|
| 418 | + gpsReceived = true; |
|
| 419 | + } |
|
| 393 | 420 | } |
| 394 | 421 | } |
| 395 | 422 | |
| ... | ... | @@ -403,15 +430,10 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener |
| 403 | 430 | |
| 404 | 431 | private class TimerRunnable implements Runnable { |
| 405 | 432 | |
| 406 | - public Thread t; |
|
| 407 | - public volatile boolean running = true; |
|
| 433 | + private boolean running; |
|
| 408 | 434 | |
| 409 | - public void start() { |
|
| 435 | + TimerRunnable() { |
|
| 410 | 436 | running = true; |
| 411 | - if (t == null) { |
|
| 412 | - t = new Thread(this); |
|
| 413 | - t.start(); |
|
| 414 | - } |
|
| 415 | 437 | } |
| 416 | 438 | |
| 417 | 439 | @Override |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/AboutFragment.java
| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | +package com.sap.sailing.android.tracking.app.ui.fragments; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | +import android.support.annotation.Nullable; |
|
| 5 | +import android.view.LayoutInflater; |
|
| 6 | +import android.view.View; |
|
| 7 | +import android.view.ViewGroup; |
|
| 8 | + |
|
| 9 | +import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView; |
|
| 10 | +import com.sap.sailing.android.shared.util.AppUtils; |
|
| 11 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 12 | +import com.sap.sailing.android.shared.util.LicenseHelper; |
|
| 13 | +import com.sap.sailing.android.tracking.app.R; |
|
| 14 | + |
|
| 15 | +import de.psdev.licensesdialog.LicensesDialog; |
|
| 16 | +import de.psdev.licensesdialog.model.Notices; |
|
| 17 | + |
|
| 18 | +public class AboutFragment extends com.sap.sailing.android.ui.fragments.BaseFragment { |
|
| 19 | + |
|
| 20 | + public static AboutFragment newInstance() { |
|
| 21 | + AboutFragment fragment = new AboutFragment(); |
|
| 22 | + Bundle args = new Bundle(); |
|
| 23 | + fragment.setArguments(args); |
|
| 24 | + return fragment; |
|
| 25 | + } |
|
| 26 | + |
|
| 27 | + @Nullable |
|
| 28 | + @Override |
|
| 29 | + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
|
| 30 | + View view = inflater.inflate(R.layout.fragment_about, container, false); |
|
| 31 | + view.findViewById(R.id.licence_button).setOnClickListener(new View.OnClickListener() { |
|
| 32 | + @Override |
|
| 33 | + public void onClick(View v) { |
|
| 34 | + showLicenceDialog(); |
|
| 35 | + } |
|
| 36 | + }); |
|
| 37 | + view.findViewById(R.id.eula_button).setOnClickListener(new View.OnClickListener() { |
|
| 38 | + @Override |
|
| 39 | + public void onClick(View v) { |
|
| 40 | + EulaHelper.openEulaPage(getActivity()); |
|
| 41 | + } |
|
| 42 | + }); |
|
| 43 | + OpenSansTextView versionTextView = (OpenSansTextView) view.findViewById(R.id.system_information_application_version); |
|
| 44 | + versionTextView.setText(AppUtils.with(getActivity()).getBuildInfo()); |
|
| 45 | + return view; |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | + private void showLicenceDialog() { |
|
| 49 | + Notices notices = new Notices(); |
|
| 50 | + LicenseHelper licenseHelper = new LicenseHelper(); |
|
| 51 | + notices.addNotice(licenseHelper.getAndroidSupportNotice()); |
|
| 52 | + notices.addNotice(licenseHelper.getOpenSansNotice()); |
|
| 53 | + notices.addNotice(licenseHelper.getJsonSimpleNotice()); |
|
| 54 | + notices.addNotice(licenseHelper.getDialogNotice()); |
|
| 55 | + LicensesDialog.Builder builder = new LicensesDialog.Builder(getActivity()); |
|
| 56 | + builder.setTitle(getString(R.string.licence_information)); |
|
| 57 | + builder.setNotices(notices); |
|
| 58 | + builder.build().show(); |
|
| 59 | + } |
|
| 60 | +} |
|
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/EventFragment.java
| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | +package com.sap.sailing.android.tracking.app.ui.fragments; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | +import android.support.annotation.Nullable; |
|
| 5 | +import android.view.LayoutInflater; |
|
| 6 | +import android.view.View; |
|
| 7 | +import android.view.ViewGroup; |
|
| 8 | +import android.webkit.WebSettings; |
|
| 9 | +import android.webkit.WebView; |
|
| 10 | +import android.webkit.WebViewClient; |
|
| 11 | +import android.widget.Toast; |
|
| 12 | + |
|
| 13 | +import com.sap.sailing.android.tracking.app.R; |
|
| 14 | +import com.sap.sailing.android.tracking.app.utils.AppPreferences; |
|
| 15 | +import com.sap.sailing.android.tracking.app.valueobjects.EventInfo; |
|
| 16 | + |
|
| 17 | +public class EventFragment extends BaseFragment { |
|
| 18 | + |
|
| 19 | + private static final String EVENT_INFO = "event.info"; |
|
| 20 | + |
|
| 21 | + private WebView mWebView; |
|
| 22 | + |
|
| 23 | + public static EventFragment newInstance(EventInfo eventInfo) { |
|
| 24 | + Bundle args = new Bundle(); |
|
| 25 | + args.putParcelable(EVENT_INFO, eventInfo); |
|
| 26 | + EventFragment fragment = new EventFragment(); |
|
| 27 | + fragment.setArguments(args); |
|
| 28 | + return fragment; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Nullable |
|
| 32 | + @Override |
|
| 33 | + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
|
| 34 | + View view = inflater.inflate(R.layout.fragment_event, container, false); |
|
| 35 | + mWebView = (WebView) view.findViewById(R.id.web_view); |
|
| 36 | + return view; |
|
| 37 | + } |
|
| 38 | + |
|
| 39 | + @Override |
|
| 40 | + public void onResume() { |
|
| 41 | + super.onResume(); |
|
| 42 | + EventInfo eventInfo = getArguments().getParcelable(EVENT_INFO); |
|
| 43 | + WebSettings webSettings = mWebView.getSettings(); |
|
| 44 | + webSettings.setJavaScriptEnabled(true); |
|
| 45 | + |
|
| 46 | + mWebView.setWebViewClient(new WebViewClient() { |
|
| 47 | + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { |
|
| 48 | + Toast.makeText(getActivity(), description, Toast.LENGTH_SHORT).show(); |
|
| 49 | + } |
|
| 50 | + }); |
|
| 51 | + |
|
| 52 | + String url = getEventURL(eventInfo); |
|
| 53 | + mWebView.loadUrl(url); |
|
| 54 | + |
|
| 55 | + } |
|
| 56 | + |
|
| 57 | + private String getEventURL(EventInfo eventInfo) { |
|
| 58 | + AppPreferences preferences = new AppPreferences(getActivity()); |
|
| 59 | + return eventInfo.server + preferences.getServerEventUrl(eventInfo.id); |
|
| 60 | + } |
|
| 61 | +} |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/HomeFragment.java
| ... | ... | @@ -145,7 +145,7 @@ public class HomeFragment extends AbstractHomeFragment implements LoaderCallback |
| 145 | 145 | @Override |
| 146 | 146 | public void handleScannedOrUrlMatchedUri(Uri uri) { |
| 147 | 147 | String uriString = uri.toString(); |
| 148 | - CheckinManager manager = new CheckinManager(uriString, (StartActivity) getActivity()); |
|
| 148 | + CheckinManager manager = new CheckinManager(uriString, (StartActivity) getActivity(), false); |
|
| 149 | 149 | manager.callServerAndGenerateCheckinData(); |
| 150 | 150 | } |
| 151 | 151 |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.android.tracking.app.ui.fragments; |
| 2 | 2 | |
| 3 | +import java.io.File; |
|
| 4 | +import java.io.FileNotFoundException; |
|
| 5 | +import java.io.IOException; |
|
| 6 | +import java.io.InputStream; |
|
| 7 | +import java.util.concurrent.TimeUnit; |
|
| 8 | + |
|
| 3 | 9 | import android.annotation.TargetApi; |
| 4 | 10 | import android.app.Activity; |
| 5 | 11 | import android.app.AlertDialog; |
| ... | ... | @@ -16,20 +22,20 @@ import android.view.LayoutInflater; |
| 16 | 22 | import android.view.View; |
| 17 | 23 | import android.view.View.OnClickListener; |
| 18 | 24 | import android.view.ViewGroup; |
| 19 | -import android.widget.*; |
|
| 25 | +import android.widget.Button; |
|
| 26 | +import android.widget.ImageButton; |
|
| 27 | +import android.widget.LinearLayout; |
|
| 28 | +import android.widget.RelativeLayout; |
|
| 29 | +import android.widget.TextView; |
|
| 20 | 30 | |
| 21 | 31 | import com.sap.sailing.android.shared.logging.ExLog; |
| 22 | 32 | import com.sap.sailing.android.tracking.app.BuildConfig; |
| 23 | 33 | import com.sap.sailing.android.tracking.app.R; |
| 34 | +import com.sap.sailing.android.tracking.app.ui.activities.EventActivity; |
|
| 24 | 35 | import com.sap.sailing.android.tracking.app.ui.activities.LeaderboardWebViewActivity; |
| 25 | 36 | import com.sap.sailing.android.tracking.app.ui.activities.RegattaActivity; |
| 26 | 37 | import com.sap.sailing.android.tracking.app.ui.activities.TrackingActivity; |
| 27 | - |
|
| 28 | -import java.io.File; |
|
| 29 | -import java.io.FileNotFoundException; |
|
| 30 | -import java.io.IOException; |
|
| 31 | -import java.io.InputStream; |
|
| 32 | -import java.util.concurrent.TimeUnit; |
|
| 38 | +import com.sap.sailing.android.shared.util.LocationHelper; |
|
| 33 | 39 | |
| 34 | 40 | public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 35 | 41 | |
| ... | ... | @@ -57,6 +63,9 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 57 | 63 | Button showLeaderboardButton = (Button) view.findViewById(R.id.show_leaderboards_button); |
| 58 | 64 | showLeaderboardButton.setOnClickListener(this); |
| 59 | 65 | |
| 66 | + Button showEventButton = (Button) view.findViewById(R.id.show_event_button); |
|
| 67 | + showEventButton.setOnClickListener(this); |
|
| 68 | + |
|
| 60 | 69 | Button changePhotoButton = (Button) view.findViewById(R.id.change_photo_button); |
| 61 | 70 | changePhotoButton.setOnClickListener(this); |
| 62 | 71 | |
| ... | ... | @@ -154,12 +163,17 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 154 | 163 | case R.id.show_leaderboards_button: |
| 155 | 164 | startLeaderboardActivity(); |
| 156 | 165 | break; |
| 166 | + case R.id.show_event_button: |
|
| 167 | + startEventActivity(); |
|
| 168 | + break; |
|
| 157 | 169 | case R.id.start_tracking: |
| 158 | 170 | if (showingThankYouNote) { |
| 159 | 171 | RegattaActivity regattaActivity = (RegattaActivity) getActivity(); |
| 160 | 172 | regattaActivity.checkout(); |
| 161 | - } else { |
|
| 173 | + } else if (LocationHelper.isGPSEnabled(getActivity())) { |
|
| 162 | 174 | startTrackingActivity(); |
| 175 | + } else { |
|
| 176 | + showNoGPSError(); |
|
| 163 | 177 | } |
| 164 | 178 | break; |
| 165 | 179 | case R.id.add_photo_button: |
| ... | ... | @@ -176,6 +190,20 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 176 | 190 | } |
| 177 | 191 | } |
| 178 | 192 | |
| 193 | + private void showNoGPSError() { |
|
| 194 | + new AlertDialog.Builder(getActivity()) |
|
| 195 | + .setCancelable(true).setTitle(getString(R.string.warning)) |
|
| 196 | + .setMessage(getString(R.string.enable_gps)) |
|
| 197 | + .setNegativeButton(getString(R.string.no), null) |
|
| 198 | + .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { |
|
| 199 | + @Override |
|
| 200 | + public void onClick(DialogInterface dialog, int which) { |
|
| 201 | + LocationHelper.openLocationSettings(getActivity()); |
|
| 202 | + } |
|
| 203 | + }) |
|
| 204 | + .show(); |
|
| 205 | + } |
|
| 206 | + |
|
| 179 | 207 | public void setChangePhotoButtonHidden(boolean hidden) { |
| 180 | 208 | LinearLayout changePhotoLayout = (LinearLayout) getActivity().findViewById(R.id.change_photo); |
| 181 | 209 | if (hidden) { |
| ... | ... | @@ -225,7 +253,7 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 225 | 253 | RegattaActivity activity = (RegattaActivity) getActivity(); |
| 226 | 254 | |
| 227 | 255 | if (requestCode == CAMERA_REQUEST_CODE) { |
| 228 | - File photoFile = ((RegattaActivity) getActivity()).getImageFile(CAMERA_TEMP_FILE); |
|
| 256 | + File photoFile = activity.getImageFile(CAMERA_TEMP_FILE); |
|
| 229 | 257 | Bitmap photo; |
| 230 | 258 | try { |
| 231 | 259 | photo = decodeUri(Uri.fromFile(photoFile)); |
| ... | ... | @@ -239,7 +267,7 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 239 | 267 | ExLog.i(getActivity(), TAG, "update photo, io exception: " + e.getMessage()); |
| 240 | 268 | } |
| 241 | 269 | } finally { |
| 242 | - ((RegattaActivity) getActivity()).deleteFile(CAMERA_TEMP_FILE); |
|
| 270 | + activity.deleteFile(CAMERA_TEMP_FILE); |
|
| 243 | 271 | } |
| 244 | 272 | } else if (requestCode == SELECT_PHOTO_REQUEST_CODE) { |
| 245 | 273 | Uri selectedImage = data.getData(); |
| ... | ... | @@ -302,7 +330,14 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { |
| 302 | 330 | intent.putExtra(LeaderboardWebViewActivity.LEADERBOARD_EXTRA_EVENT_ID, activity.event.id); |
| 303 | 331 | intent.putExtra(LeaderboardWebViewActivity.LEADERBOARD_EXTRA_LEADERBOARD_NAME, activity.leaderboard.name); |
| 304 | 332 | |
| 305 | - getActivity().startActivity(intent); |
|
| 333 | + startActivity(intent); |
|
| 334 | + } |
|
| 335 | + |
|
| 336 | + private void startEventActivity() { |
|
| 337 | + RegattaActivity activity = (RegattaActivity) getActivity(); |
|
| 338 | + Intent intent = new Intent(getActivity(), EventActivity.class); |
|
| 339 | + intent.putExtra(EventActivity.EVENT, activity.event); |
|
| 340 | + startActivity(intent); |
|
| 306 | 341 | } |
| 307 | 342 | |
| 308 | 343 | private void startTrackingActivity() { |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/SpeedFragment.java
| ... | ... | @@ -34,11 +34,11 @@ public class SpeedFragment extends BaseFragment { |
| 34 | 34 | String formattedSpeed = df.format(speedInKnots); |
| 35 | 35 | |
| 36 | 36 | TextView speedText = (TextView) getActivity().findViewById(R.id.speed_text_view); |
| 37 | - speedText.setText(formattedSpeed); |
|
| 37 | + speedText.setText(getString(R.string.knots, formattedSpeed)); |
|
| 38 | 38 | TrackingActivity activity = (TrackingActivity) getActivity(); |
| 39 | 39 | |
| 40 | 40 | if (activity != null) { |
| 41 | - activity.lastSpeedIndicatorText = speedText.getText().toString(); |
|
| 41 | + activity.lastSpeedIndicatorText = formattedSpeed; |
|
| 42 | 42 | } |
| 43 | 43 | } |
| 44 | 44 | } |
| ... | ... | @@ -51,9 +51,9 @@ public class SpeedFragment extends BaseFragment { |
| 51 | 51 | |
| 52 | 52 | TrackingActivity activity = (TrackingActivity) getActivity(); |
| 53 | 53 | if (activity != null) { |
| 54 | - speedText.setText(activity.lastSpeedIndicatorText); |
|
| 54 | + speedText.setText(getString(R.string.knots,activity.lastSpeedIndicatorText)); |
|
| 55 | 55 | } else { |
| 56 | - speedText.setText("0"); |
|
| 56 | + speedText.setText(getString(R.string.knots,"0")); |
|
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | } |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/StopTrackingButtonFragment.java
| ... | ... | @@ -14,24 +14,20 @@ import com.sap.sailing.android.tracking.app.ui.activities.TrackingActivity; |
| 14 | 14 | public class StopTrackingButtonFragment extends BaseFragment { |
| 15 | 15 | |
| 16 | 16 | private final static String SIS_TRACKING_TIMER = "savedInstanceTrackingTimer"; |
| 17 | + private TextView timerView; |
|
| 17 | 18 | |
| 18 | 19 | @Override |
| 19 | 20 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| 20 | 21 | super.onCreateView(inflater, container, savedInstanceState); |
| 21 | 22 | ViewGroup view = (ViewGroup) inflater.inflate(R.layout.fragment_stop_button, container, false); |
| 23 | + timerView = (TextView) view.findViewById(R.id.tracking_time_label); |
|
| 22 | 24 | |
| 23 | 25 | Button stopTracking = (Button) view.findViewById(R.id.stop_tracking); |
| 24 | 26 | stopTracking.setOnClickListener(new OnClickListener() { |
| 25 | 27 | @Override |
| 26 | 28 | public void onClick(View v) { |
| 27 | - switch (v.getId()) { |
|
| 28 | - case R.id.stop_tracking: |
|
| 29 | - TrackingActivity activity = (TrackingActivity) getActivity(); |
|
| 30 | - activity.showStopTrackingConfirmationDialog(); |
|
| 31 | - break; |
|
| 32 | - default: |
|
| 33 | - break; |
|
| 34 | - } |
|
| 29 | + TrackingActivity activity = (TrackingActivity) getActivity(); |
|
| 30 | + activity.showStopTrackingConfirmationDialog(); |
|
| 35 | 31 | } |
| 36 | 32 | }); |
| 37 | 33 | |
| ... | ... | @@ -41,17 +37,16 @@ public class StopTrackingButtonFragment extends BaseFragment { |
| 41 | 37 | @Override |
| 42 | 38 | public void onSaveInstanceState(Bundle outState) { |
| 43 | 39 | super.onSaveInstanceState(outState); |
| 44 | - |
|
| 45 | - TextView timerView = (TextView) getActivity().findViewById(R.id.tracking_time_label); |
|
| 46 | - outState.putString(SIS_TRACKING_TIMER, timerView.getText().toString()); |
|
| 40 | + if (timerView != null) { |
|
| 41 | + outState.putString(SIS_TRACKING_TIMER, timerView.getText().toString()); |
|
| 42 | + } |
|
| 47 | 43 | } |
| 48 | 44 | |
| 49 | 45 | @Override |
| 50 | 46 | public void onActivityCreated(Bundle savedInstanceState) { |
| 51 | 47 | super.onActivityCreated(savedInstanceState); |
| 52 | 48 | |
| 53 | - if (savedInstanceState != null) { |
|
| 54 | - TextView timerView = (TextView) getActivity().findViewById(R.id.tracking_time_label); |
|
| 49 | + if (savedInstanceState != null && timerView!= null) { |
|
| 55 | 50 | timerView.setText(savedInstanceState.getString(SIS_TRACKING_TIMER)); |
| 56 | 51 | } |
| 57 | 52 | } |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/TrackingFragment.java
| ... | ... | @@ -42,9 +42,6 @@ public class TrackingFragment extends BaseFragment { |
| 42 | 42 | ViewGroup view = (ViewGroup) inflater.inflate(R.layout.fragment_tracking, container, false); |
| 43 | 43 | |
| 44 | 44 | prefs = new AppPreferences(getActivity()); |
| 45 | - if (prefs.getTrackingTimerStarted() == 0) { |
|
| 46 | - prefs.setTrackingTimerStarted(System.currentTimeMillis()); |
|
| 47 | - } |
|
| 48 | 45 | |
| 49 | 46 | return view; |
| 50 | 47 | } |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/AboutHelper.java
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +package com.sap.sailing.android.tracking.app.utils; |
|
| 2 | + |
|
| 3 | +import android.content.Context; |
|
| 4 | +import android.content.Intent; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.android.tracking.app.ui.activities.AboutActivity; |
|
| 7 | + |
|
| 8 | +public class AboutHelper { |
|
| 9 | + |
|
| 10 | + public static void showInfoActivity(Context context) { |
|
| 11 | + Intent intent = new Intent(context, AboutActivity.class); |
|
| 12 | + context.startActivity(intent); |
|
| 13 | + } |
|
| 14 | +} |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/AppPreferences.java
| ... | ... | @@ -40,6 +40,10 @@ public class AppPreferences extends BaseAppPreferences { |
| 40 | 40 | return context.getString(R.string.preference_server_event_path, "/events").replace("{event_id}", eventId); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | + public String getServerEventUrl(String eventId) { |
|
| 44 | + return context.getString(R.string.preference_server_event_url, eventId); |
|
| 45 | + } |
|
| 46 | + |
|
| 43 | 47 | public String getServerLeaderboardPath(String leaderboardName) { |
| 44 | 48 | return context.getString(R.string.preference_server_leaderboard_path, "/leaderboards").replace( |
| 45 | 49 | "{leaderboard_name}", leaderboardName); |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/CheckinManager.java
| ... | ... | @@ -36,11 +36,13 @@ public class CheckinManager { |
| 36 | 36 | private CheckinDataActivity activity; |
| 37 | 37 | private AppPreferences prefs; |
| 38 | 38 | private String url; |
| 39 | + private boolean update; |
|
| 39 | 40 | |
| 40 | - public CheckinManager(String url, CheckinDataActivity activity) { |
|
| 41 | + public CheckinManager(String url, CheckinDataActivity activity, boolean update) { |
|
| 41 | 42 | this.activity = activity; |
| 42 | 43 | this.url = url; |
| 43 | 44 | prefs = new AppPreferences(activity); |
| 45 | + this.update = update; |
|
| 44 | 46 | } |
| 45 | 47 | |
| 46 | 48 | public void callServerAndGenerateCheckinData() { |
| ... | ... | @@ -218,6 +220,7 @@ public class CheckinManager { |
| 218 | 220 | |
| 219 | 221 | private void saveCheckinDataAndNotifyListeners(URLData urlData, String leaderboardName) { |
| 220 | 222 | CheckinData data = new CheckinData(); |
| 223 | + data.setUpdate(update); |
|
| 221 | 224 | data.competitorName = urlData.competitorName; |
| 222 | 225 | data.competitorId = urlData.competitorId; |
| 223 | 226 | data.competitorSailId = urlData.competitorSailId; |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java
| ... | ... | @@ -23,6 +23,7 @@ import com.sap.sailing.android.shared.data.CheckinUrlInfo; |
| 23 | 23 | import com.sap.sailing.android.shared.data.LeaderboardInfo; |
| 24 | 24 | |
| 25 | 25 | import java.util.ArrayList; |
| 26 | +import java.util.List; |
|
| 26 | 27 | |
| 27 | 28 | public class DatabaseHelper { |
| 28 | 29 | |
| ... | ... | @@ -38,6 +39,21 @@ public class DatabaseHelper { |
| 38 | 39 | return mInstance; |
| 39 | 40 | } |
| 40 | 41 | |
| 42 | + public List<String> getCheckinUrls(Context context) { |
|
| 43 | + List<String> checkinUrls = new ArrayList<>(); |
|
| 44 | + ContentResolver cr = context.getContentResolver(); |
|
| 45 | + Cursor cursor = cr.query(CheckinUri.CONTENT_URI, null, null, null, null); |
|
| 46 | + cursor.moveToFirst(); |
|
| 47 | + while (!cursor.isAfterLast()) { |
|
| 48 | + String checkinUrl = cursor.getString(cursor.getColumnIndex(CheckinUri.CHECKIN_URI_VALUE)); |
|
| 49 | + if (!checkinUrls.contains(checkinUrl)){ |
|
| 50 | + checkinUrls.add(checkinUrl); |
|
| 51 | + } |
|
| 52 | + cursor.moveToNext(); |
|
| 53 | + } |
|
| 54 | + return checkinUrls; |
|
| 55 | + } |
|
| 56 | + |
|
| 41 | 57 | public long getEventRowIdForCheckinDigest(Context context, String checkinDigest) { |
| 42 | 58 | int result = 0; |
| 43 | 59 |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CheckinData.java
| ... | ... | @@ -26,6 +26,7 @@ public class CheckinData extends AbstractCheckinData { |
| 26 | 26 | public String deviceUid; |
| 27 | 27 | public String uriString; |
| 28 | 28 | public String checkinDigest; |
| 29 | + private boolean update; |
|
| 29 | 30 | |
| 30 | 31 | public void setCheckinDigestFromString(String checkinString) throws UnsupportedEncodingException, |
| 31 | 32 | NoSuchAlgorithmException { |
| ... | ... | @@ -75,4 +76,12 @@ public class CheckinData extends AbstractCheckinData { |
| 75 | 76 | checkinUrlInfo.checkinDigest = checkinDigest; |
| 76 | 77 | return checkinUrlInfo; |
| 77 | 78 | } |
| 79 | + |
|
| 80 | + public boolean isUpdate() { |
|
| 81 | + return update; |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + public void setUpdate(boolean update) { |
|
| 85 | + this.update = update; |
|
| 86 | + } |
|
| 78 | 87 | } |
| ... | ... | \ No newline at end of file |
mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/EventInfo.java
| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | package com.sap.sailing.android.tracking.app.valueobjects; |
| 2 | 2 | |
| 3 | -public class EventInfo { |
|
| 3 | +import android.os.Parcel; |
|
| 4 | +import android.os.Parcelable; |
|
| 5 | + |
|
| 6 | +public class EventInfo implements Parcelable{ |
|
| 4 | 7 | |
| 5 | 8 | public String id; |
| 6 | 9 | public String name; |
| ... | ... | @@ -13,10 +16,59 @@ public class EventInfo { |
| 13 | 16 | public String checkinDigest; |
| 14 | 17 | public String server; |
| 15 | 18 | |
| 19 | + public EventInfo() { |
|
| 20 | + |
|
| 21 | + } |
|
| 22 | + |
|
| 23 | + public EventInfo(Parcel in) { |
|
| 24 | + |
|
| 25 | + id = in.readString(); |
|
| 26 | + name = in.readString(); |
|
| 27 | + leaderboardName = in.readString(); |
|
| 28 | + competitorId = in.readString(); |
|
| 29 | + imageUrl = in.readString(); |
|
| 30 | + startMillis = in.readLong(); |
|
| 31 | + endMillis = in.readLong(); |
|
| 32 | + rowId = in.readInt(); |
|
| 33 | + checkinDigest = in.readString(); |
|
| 34 | + server = in.readString(); |
|
| 35 | + } |
|
| 36 | + |
|
| 37 | + public static final Creator<EventInfo> CREATOR = new Creator<EventInfo>() { |
|
| 38 | + @Override |
|
| 39 | + public EventInfo createFromParcel(Parcel in) { |
|
| 40 | + return new EventInfo(in); |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + @Override |
|
| 44 | + public EventInfo[] newArray(int size) { |
|
| 45 | + return new EventInfo[size]; |
|
| 46 | + } |
|
| 47 | + }; |
|
| 48 | + |
|
| 16 | 49 | @Override |
| 17 | 50 | public String toString() { |
| 18 | 51 | return "eventName: " + name + ", leaderboardName: " + leaderboardName + ", competitorId: " + competitorId |
| 19 | 52 | + ", eventImageUrl: " + imageUrl + ", eventStartMillis: " + startMillis + ", eventEndMillis: " |
| 20 | 53 | + endMillis + ", eventRowId: " + ", checkinDigest: " + checkinDigest + rowId + ", server: " + server; |
| 21 | 54 | } |
| 55 | + |
|
| 56 | + @Override |
|
| 57 | + public int describeContents() { |
|
| 58 | + return 0; |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + @Override |
|
| 62 | + public void writeToParcel(Parcel dest, int flags) { |
|
| 63 | + dest.writeString(id); |
|
| 64 | + dest.writeString(name); |
|
| 65 | + dest.writeString(leaderboardName); |
|
| 66 | + dest.writeString(competitorId); |
|
| 67 | + dest.writeString(imageUrl); |
|
| 68 | + dest.writeLong(startMillis); |
|
| 69 | + dest.writeLong(endMillis); |
|
| 70 | + dest.writeInt(rowId); |
|
| 71 | + dest.writeString(checkinDigest); |
|
| 72 | + dest.writeString(server); |
|
| 73 | + } |
|
| 22 | 74 | } |
mobile/com.sap.sailing.buoy.positioning/AndroidManifest.xml
| ... | ... | @@ -72,6 +72,9 @@ |
| 72 | 72 | android:screenOrientation="portrait"/> |
| 73 | 73 | <activity |
| 74 | 74 | android:name=".ui.activities.SettingActivity"/> |
| 75 | + <activity |
|
| 76 | + android:name=".ui.activities.AboutActivity" |
|
| 77 | + android:screenOrientation="portrait"/> |
|
| 75 | 78 | |
| 76 | 79 | <service |
| 77 | 80 | android:name="com.sap.sailing.android.shared.services.sending.MessageSendingService" |
mobile/com.sap.sailing.buoy.positioning/build.gradle
| ... | ... | @@ -74,6 +74,9 @@ dependencies { |
| 74 | 74 | /* Google Play Services */ |
| 75 | 75 | compile "com.google.android.gms:play-services-location:${rootProject.ext.play_services}" |
| 76 | 76 | |
| 77 | + /* licence dialog */ |
|
| 78 | + compile('de.psdev.licensesdialog:licensesdialog:1.8.0') |
|
| 79 | + |
|
| 77 | 80 | /* local dependencies */ |
| 78 | 81 | compile project(":mobile:com.sap.sailing.android.shared") |
| 79 | 82 |
mobile/com.sap.sailing.buoy.positioning/pom.xml
| ... | ... | @@ -63,6 +63,14 @@ |
| 63 | 63 | <version>1.0.0-SNAPSHOT</version> |
| 64 | 64 | <type>apklib</type> |
| 65 | 65 | </dependency> |
| 66 | + |
|
| 67 | + <dependency> |
|
| 68 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 69 | + <artifactId>licensesdialog</artifactId> |
|
| 70 | + <version>1.8.0</version> |
|
| 71 | + <type>aar</type> |
|
| 72 | + </dependency> |
|
| 73 | + |
|
| 66 | 74 | </dependencies> |
| 67 | 75 | |
| 68 | 76 | <build> |
mobile/com.sap.sailing.buoy.positioning/project.properties
| ... | ... | @@ -14,3 +14,4 @@ |
| 14 | 14 | target=Google Inc.:Google APIs:22 |
| 15 | 15 | android.library.reference.1=../google-play-services_lib |
| 16 | 16 | android.library.reference.2=../com.sap.sailing.android.shared |
| 17 | +android.library.reference.3=../licensesdialog_lib/de.psdev.licensesdialog |
mobile/com.sap.sailing.buoy.positioning/res/menu/about_menu.xml
| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | 2 | <menu xmlns:android="http://schemas.android.com/apk/res/android"> |
| 3 | + |
|
| 3 | 4 | <item |
| 4 | 5 | android:id="@+id/about" |
| 5 | 6 | android:title="@string/about"/> |
mobile/com.sap.sailing.buoy.positioning/res/values-de/strings.xml
| ... | ... | @@ -12,8 +12,11 @@ |
| 12 | 12 | <string name="accuracy">Genauigkeit</string> |
| 13 | 13 | <string name="position_set">Die Position wurde gesetzt</string> |
| 14 | 14 | <string name="no_information">Keine Information</string> |
| 15 | - <string name="title_activity_settings">Einstellungen</string> |
|
| 16 | - <string name="action_settings">Einstellungen</string> |
|
| 15 | + <string name="title_activity_settings">@string/settings</string> |
|
| 16 | + <string name="error_message_no_position">Positionieren Sie das Gerät in der Nähe der Markierung und betätigen Sie \'Position Setzen\', um die Position |
|
| 17 | + der Markierung zu setzen. Nutzen Sie die Anzeige der GPS-Qualität und entscheiden Sie, ob die Position genau genug ist. Bitte aktivieren Sie |
|
| 18 | + GPS auf Ihrem Gerät oder warten Sie bis ein GPS-Signal verfügbar ist.</string> |
|
| 19 | + <string name="action_settings">@string/settings</string> |
|
| 17 | 20 | <string name="settings">Einstellungen</string> |
| 18 | 21 | |
| 19 | 22 | <string name="server">Polling Einstellungen</string> |
mobile/com.sap.sailing.buoy.positioning/res/values/strings.xml
| ... | ... | @@ -16,9 +16,10 @@ |
| 16 | 16 | <string name="accuracy">Accuracy</string> |
| 17 | 17 | <string name="position_set">The position has been set</string> |
| 18 | 18 | <string name="no_information">No information</string> |
| 19 | - <string name="title_activity_settings">Settings</string> |
|
| 20 | - |
|
| 21 | - <string name="action_settings">Settings</string> |
|
| 19 | + <string name="title_activity_settings">@string/settings</string> |
|
| 20 | + <string name="error_message_no_position">Position the device close to the mark and press \'set position\' to set the marks position. |
|
| 21 | + Use the accuracy indicator to decide if the shown position is good enough. Please activate GPS or wait for GPS availability.</string> |
|
| 22 | + <string name="action_settings">@string/settings</string> |
|
| 22 | 23 | <string name="settings">Settings</string> |
| 23 | 24 | |
| 24 | 25 | <string name="server">Polling</string> |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/activities/AboutActivity.java
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +package com.sap.sailing.android.buoy.positioning.app.ui.activities; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | +import android.view.Menu; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.android.buoy.positioning.app.R; |
|
| 7 | +import com.sap.sailing.android.buoy.positioning.app.ui.fragments.AboutFragment; |
|
| 8 | +import com.sap.sailing.android.shared.ui.customviews.OpenSansToolbar; |
|
| 9 | + |
|
| 10 | +public class AboutActivity extends BaseActivity { |
|
| 11 | + @Override |
|
| 12 | + protected void onCreate(Bundle savedInstanceState) { |
|
| 13 | + super.onCreate(savedInstanceState); |
|
| 14 | + setContentView(com.sap.sailing.android.shared.R.layout.fragment_container); |
|
| 15 | + |
|
| 16 | + OpenSansToolbar toolbar = (OpenSansToolbar) findViewById(R.id.toolbar); |
|
| 17 | + if (toolbar != null) { |
|
| 18 | + toolbar.hideSubtitle(); |
|
| 19 | + toolbar.setTitleSize(20); |
|
| 20 | + setSupportActionBar(toolbar); |
|
| 21 | + toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); |
|
| 22 | + } |
|
| 23 | + if (getSupportActionBar() != null) { |
|
| 24 | + getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
|
| 25 | + getSupportActionBar().setHomeButtonEnabled(true); |
|
| 26 | + toolbar.setNavigationIcon(R.drawable.sap_logo_64_sq); |
|
| 27 | + toolbar.setPadding(20, 0, 0, 0); |
|
| 28 | + toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); |
|
| 29 | + getSupportActionBar().setTitle(R.string.about_this_app); |
|
| 30 | + } |
|
| 31 | + replaceFragment(R.id.content_frame, AboutFragment.newInstance()); |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + /** |
|
| 35 | + * Empty method to avoid creation of parent menu. |
|
| 36 | + */ |
|
| 37 | + @Override |
|
| 38 | + public boolean onCreateOptionsMenu(Menu menu) { |
|
| 39 | + return true; |
|
| 40 | + } |
|
| 41 | +} |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/activities/PositioningActivity.java
| ... | ... | @@ -11,12 +11,12 @@ import android.view.MenuItem; |
| 11 | 11 | import com.sap.sailing.android.buoy.positioning.app.R; |
| 12 | 12 | import com.sap.sailing.android.buoy.positioning.app.ui.fragments.BuoyFragment; |
| 13 | 13 | import com.sap.sailing.android.buoy.positioning.app.ui.fragments.BuoyFragment.pingListener; |
| 14 | +import com.sap.sailing.android.buoy.positioning.app.util.AboutHelper; |
|
| 14 | 15 | import com.sap.sailing.android.buoy.positioning.app.util.DatabaseHelper; |
| 15 | 16 | import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkInfo; |
| 16 | 17 | import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkPingInfo; |
| 17 | 18 | import com.sap.sailing.android.shared.data.LeaderboardInfo; |
| 18 | 19 | import com.sap.sailing.android.shared.ui.customviews.OpenSansToolbar; |
| 19 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 20 | 20 | |
| 21 | 21 | public class PositioningActivity extends BaseActivity implements pingListener { |
| 22 | 22 | |
| ... | ... | @@ -80,15 +80,14 @@ public class PositioningActivity extends BaseActivity implements pingListener { |
| 80 | 80 | @Override |
| 81 | 81 | public boolean onOptionsItemSelected(MenuItem item) { |
| 82 | 82 | switch (item.getItemId()) { |
| 83 | - case R.id.about: |
|
| 84 | - AboutDialog aboutDialog = new AboutDialog(this); |
|
| 85 | - aboutDialog.show(); |
|
| 86 | - return true; |
|
| 87 | - case R.id.settings: |
|
| 88 | - startActivity(new Intent(this, SettingActivity.class)); |
|
| 89 | - return true; |
|
| 90 | - default: |
|
| 91 | - return super.onOptionsItemSelected(item); |
|
| 83 | + case R.id.about: |
|
| 84 | + AboutHelper.showInfoActivity(this); |
|
| 85 | + return true; |
|
| 86 | + case R.id.settings: |
|
| 87 | + startActivity(new Intent(this, SettingActivity.class)); |
|
| 88 | + return true; |
|
| 89 | + default: |
|
| 90 | + return super.onOptionsItemSelected(item); |
|
| 92 | 91 | } |
| 93 | 92 | } |
| 94 | 93 |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/activities/RegattaActivity.java
| ... | ... | @@ -17,6 +17,7 @@ import com.sap.sailing.android.buoy.positioning.app.BuildConfig; |
| 17 | 17 | import com.sap.sailing.android.buoy.positioning.app.R; |
| 18 | 18 | import com.sap.sailing.android.buoy.positioning.app.service.MarkerService; |
| 19 | 19 | import com.sap.sailing.android.buoy.positioning.app.ui.fragments.RegattaFragment; |
| 20 | +import com.sap.sailing.android.buoy.positioning.app.util.AboutHelper; |
|
| 20 | 21 | import com.sap.sailing.android.buoy.positioning.app.util.AppPreferences; |
| 21 | 22 | import com.sap.sailing.android.buoy.positioning.app.util.CheckinManager; |
| 22 | 23 | import com.sap.sailing.android.buoy.positioning.app.util.DatabaseHelper; |
| ... | ... | @@ -27,7 +28,6 @@ import com.sap.sailing.android.shared.logging.ExLog; |
| 27 | 28 | import com.sap.sailing.android.shared.services.sending.MessageSendingService; |
| 28 | 29 | import com.sap.sailing.android.shared.ui.activities.AbstractRegattaActivity; |
| 29 | 30 | import com.sap.sailing.android.shared.ui.customviews.OpenSansToolbar; |
| 30 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 31 | 31 | |
| 32 | 32 | public class RegattaActivity extends AbstractRegattaActivity { |
| 33 | 33 | |
| ... | ... | @@ -126,21 +126,20 @@ public class RegattaActivity extends AbstractRegattaActivity { |
| 126 | 126 | @Override |
| 127 | 127 | public boolean onOptionsItemSelected(MenuItem item) { |
| 128 | 128 | switch (item.getItemId()) { |
| 129 | - case R.id.refresh: |
|
| 130 | - ExLog.i(this, TAG, "Clicked REFRESH."); |
|
| 131 | - CheckinManager manager = new CheckinManager(checkinUrl, this); |
|
| 132 | - manager.callServerAndGenerateCheckinData(); |
|
| 133 | - return true; |
|
| 134 | - case R.id.check_out: |
|
| 135 | - checkOut(); |
|
| 136 | - return true; |
|
| 137 | - case R.id.about: |
|
| 138 | - AboutDialog aboutDialog = new AboutDialog(this); |
|
| 139 | - aboutDialog.show(); |
|
| 140 | - return true; |
|
| 141 | - case R.id.settings: |
|
| 142 | - startActivity(new Intent(this, SettingActivity.class)); |
|
| 143 | - return true; |
|
| 129 | + case R.id.refresh: |
|
| 130 | + ExLog.i(this, TAG, "Clicked REFRESH."); |
|
| 131 | + CheckinManager manager = new CheckinManager(checkinUrl, this); |
|
| 132 | + manager.callServerAndGenerateCheckinData(); |
|
| 133 | + return true; |
|
| 134 | + case R.id.check_out: |
|
| 135 | + checkOut(); |
|
| 136 | + return true; |
|
| 137 | + case R.id.about: |
|
| 138 | + AboutHelper.showInfoActivity(this); |
|
| 139 | + return true; |
|
| 140 | + case R.id.settings: |
|
| 141 | + startActivity(new Intent(this, SettingActivity.class)); |
|
| 142 | + return true; |
|
| 144 | 143 | default: |
| 145 | 144 | return super.onOptionsItemSelected(item); |
| 146 | 145 | } |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/activities/StartActivity.java
| ... | ... | @@ -8,8 +8,10 @@ import android.view.MenuItem; |
| 8 | 8 | |
| 9 | 9 | import com.sap.sailing.android.buoy.positioning.app.R; |
| 10 | 10 | import com.sap.sailing.android.buoy.positioning.app.ui.fragments.HomeFragment; |
| 11 | +import com.sap.sailing.android.buoy.positioning.app.util.AboutHelper; |
|
| 12 | +import com.sap.sailing.android.shared.data.AbstractCheckinData; |
|
| 11 | 13 | import com.sap.sailing.android.shared.ui.activities.AbstractStartActivity; |
| 12 | -import com.sap.sailing.android.shared.ui.dialogs.AboutDialog; |
|
| 14 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 13 | 15 | import com.sap.sailing.android.ui.fragments.AbstractHomeFragment; |
| 14 | 16 | |
| 15 | 17 | public class StartActivity extends AbstractStartActivity { |
| ... | ... | @@ -25,6 +27,14 @@ public class StartActivity extends AbstractStartActivity { |
| 25 | 27 | } |
| 26 | 28 | |
| 27 | 29 | @Override |
| 30 | + protected void onResume() { |
|
| 31 | + super.onResume(); |
|
| 32 | + if (!EulaHelper.isEulaAccepted(this)) { |
|
| 33 | + EulaHelper.showEulaDialog(this); |
|
| 34 | + } |
|
| 35 | + } |
|
| 36 | + |
|
| 37 | + @Override |
|
| 28 | 38 | public boolean onCreateOptionsMenu(Menu menu) { |
| 29 | 39 | super.onCreateOptionsMenu(menu); |
| 30 | 40 | MenuInflater inflater = getMenuInflater(); |
| ... | ... | @@ -35,15 +45,14 @@ public class StartActivity extends AbstractStartActivity { |
| 35 | 45 | @Override |
| 36 | 46 | public boolean onOptionsItemSelected(MenuItem item) { |
| 37 | 47 | switch (item.getItemId()) { |
| 38 | - case R.id.about: |
|
| 39 | - AboutDialog aboutDialog = new AboutDialog(this); |
|
| 40 | - aboutDialog.show(); |
|
| 41 | - return true; |
|
| 42 | - case R.id.settings: |
|
| 43 | - startActivity(new Intent(this, SettingActivity.class)); |
|
| 44 | - return true; |
|
| 45 | - default: |
|
| 46 | - return super.onOptionsItemSelected(item); |
|
| 48 | + case R.id.about: |
|
| 49 | + AboutHelper.showInfoActivity(this); |
|
| 50 | + return true; |
|
| 51 | + case R.id.settings: |
|
| 52 | + startActivity(new Intent(this, SettingActivity.class)); |
|
| 53 | + return true; |
|
| 54 | + default: |
|
| 55 | + return super.onOptionsItemSelected(item); |
|
| 47 | 56 | } |
| 48 | 57 | } |
| 49 | 58 | |
| ... | ... | @@ -57,9 +66,11 @@ public class StartActivity extends AbstractStartActivity { |
| 57 | 66 | return homeFragment; |
| 58 | 67 | } |
| 59 | 68 | |
| 60 | - public void startRegatta(String leaderboardName) { |
|
| 61 | - Intent intent = new Intent(this, RegattaActivity.class); |
|
| 62 | - intent.putExtra(getString(R.string.leaderboard_name), leaderboardName); |
|
| 63 | - startActivity(intent); |
|
| 69 | + @Override |
|
| 70 | + public void onCheckinDataAvailable(AbstractCheckinData data) { |
|
| 71 | + if (data != null) { |
|
| 72 | + getHomeFragment().displayUserConfirmationScreen(data); |
|
| 73 | + } |
|
| 64 | 74 | } |
| 75 | + |
|
| 65 | 76 | } |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/AboutFragment.java
| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | +package com.sap.sailing.android.buoy.positioning.app.ui.fragments; |
|
| 2 | + |
|
| 3 | +import android.os.Bundle; |
|
| 4 | +import android.support.annotation.Nullable; |
|
| 5 | +import android.view.LayoutInflater; |
|
| 6 | +import android.view.View; |
|
| 7 | +import android.view.ViewGroup; |
|
| 8 | + |
|
| 9 | +import com.sap.sailing.android.buoy.positioning.app.R; |
|
| 10 | +import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView; |
|
| 11 | +import com.sap.sailing.android.shared.util.AppUtils; |
|
| 12 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 13 | +import com.sap.sailing.android.shared.util.LicenseHelper; |
|
| 14 | +import com.sap.sailing.android.ui.fragments.BaseFragment; |
|
| 15 | + |
|
| 16 | +import de.psdev.licensesdialog.LicensesDialog; |
|
| 17 | +import de.psdev.licensesdialog.model.Notices; |
|
| 18 | + |
|
| 19 | +public class AboutFragment extends BaseFragment { |
|
| 20 | + |
|
| 21 | + public static AboutFragment newInstance() { |
|
| 22 | + AboutFragment fragment = new AboutFragment(); |
|
| 23 | + Bundle args = new Bundle(); |
|
| 24 | + fragment.setArguments(args); |
|
| 25 | + return fragment; |
|
| 26 | + } |
|
| 27 | + |
|
| 28 | + @Nullable |
|
| 29 | + @Override |
|
| 30 | + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
|
| 31 | + View view = inflater.inflate(R.layout.fragment_about, container, false); |
|
| 32 | + view.findViewById(R.id.licence_button).setOnClickListener(new View.OnClickListener() { |
|
| 33 | + @Override |
|
| 34 | + public void onClick(View v) { |
|
| 35 | + showLicenceDialog(); |
|
| 36 | + } |
|
| 37 | + }); |
|
| 38 | + view.findViewById(R.id.eula_button).setOnClickListener(new View.OnClickListener() { |
|
| 39 | + @Override |
|
| 40 | + public void onClick(View v) { |
|
| 41 | + EulaHelper.openEulaPage(getActivity()); |
|
| 42 | + } |
|
| 43 | + }); |
|
| 44 | + OpenSansTextView versionTextView = (OpenSansTextView) view.findViewById(R.id.system_information_application_version); |
|
| 45 | + versionTextView.setText(AppUtils.with(getActivity()).getBuildInfo()); |
|
| 46 | + return view; |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + private void showLicenceDialog() { |
|
| 50 | + Notices notices = new Notices(); |
|
| 51 | + LicenseHelper licenseHelper = new LicenseHelper(); |
|
| 52 | + notices.addNotice(licenseHelper.getAndroidSupportNotice()); |
|
| 53 | + notices.addNotice(licenseHelper.getOpenSansNotice()); |
|
| 54 | + notices.addNotice(licenseHelper.getJsonSimpleNotice()); |
|
| 55 | + notices.addNotice(licenseHelper.getDialogNotice()); |
|
| 56 | + LicensesDialog.Builder builder = new LicensesDialog.Builder(getActivity()); |
|
| 57 | + builder.setTitle(getString(R.string.licence_information)); |
|
| 58 | + builder.setNotices(notices); |
|
| 59 | + builder.build().show(); |
|
| 60 | + } |
|
| 61 | +} |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java
| ... | ... | @@ -2,8 +2,10 @@ package com.sap.sailing.android.buoy.positioning.app.ui.fragments; |
| 2 | 2 | |
| 3 | 3 | import java.text.DecimalFormat; |
| 4 | 4 | |
| 5 | +import android.app.AlertDialog; |
|
| 5 | 6 | import android.content.BroadcastReceiver; |
| 6 | 7 | import android.content.Context; |
| 8 | +import android.content.DialogInterface; |
|
| 7 | 9 | import android.content.Intent; |
| 8 | 10 | import android.content.IntentFilter; |
| 9 | 11 | import android.location.Location; |
| ... | ... | @@ -34,6 +36,7 @@ import com.sap.sailing.android.shared.logging.ExLog; |
| 34 | 36 | import com.sap.sailing.android.shared.ui.customviews.OpenSansButton; |
| 35 | 37 | import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView; |
| 36 | 38 | import com.sap.sailing.android.shared.ui.customviews.SignalQualityIndicatorView; |
| 39 | +import com.sap.sailing.android.shared.util.LocationHelper; |
|
| 37 | 40 | import com.sap.sailing.android.shared.util.ViewHelper; |
| 38 | 41 | import com.sap.sailing.android.ui.fragments.BaseFragment; |
| 39 | 42 | |
| ... | ... | @@ -106,6 +109,24 @@ public class BuoyFragment extends BaseFragment implements LocationListener { |
| 106 | 109 | } |
| 107 | 110 | } |
| 108 | 111 | initMarkerReceiver(); |
| 112 | + checkGPS(); |
|
| 113 | + } |
|
| 114 | + |
|
| 115 | + private void checkGPS() { |
|
| 116 | + if (lastKnownLocation == null) { |
|
| 117 | + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) |
|
| 118 | + .setMessage(R.string.error_message_no_position) |
|
| 119 | + .setPositiveButton(android.R.string.ok, null); |
|
| 120 | + if (!LocationHelper.isGPSEnabled(getActivity())) { |
|
| 121 | + builder.setNegativeButton(R.string.settings, new DialogInterface.OnClickListener() { |
|
| 122 | + @Override |
|
| 123 | + public void onClick(DialogInterface dialog, int which) { |
|
| 124 | + LocationHelper.openLocationSettings(getActivity()); |
|
| 125 | + } |
|
| 126 | + }); |
|
| 127 | + } |
|
| 128 | + builder.show(); |
|
| 129 | + } |
|
| 109 | 130 | } |
| 110 | 131 | |
| 111 | 132 | private void initMarkerReceiver() { |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/AboutHelper.java
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +package com.sap.sailing.android.buoy.positioning.app.util; |
|
| 2 | + |
|
| 3 | +import android.content.Context; |
|
| 4 | +import android.content.Intent; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.android.buoy.positioning.app.ui.activities.AboutActivity; |
|
| 7 | + |
|
| 8 | +public class AboutHelper { |
|
| 9 | + |
|
| 10 | + public static void showInfoActivity(Context context) { |
|
| 11 | + Intent intent = new Intent(context, AboutActivity.class); |
|
| 12 | + context.startActivity(intent); |
|
| 13 | + } |
|
| 14 | +} |
mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/PingHelper.java
| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | package com.sap.sailing.android.buoy.positioning.app.util; |
| 2 | 2 | |
| 3 | +import java.util.Date; |
|
| 3 | 4 | import java.util.UUID; |
| 4 | 5 | |
| 5 | 6 | import org.json.JSONException; |
| ... | ... | @@ -24,7 +25,7 @@ public class PingHelper { |
| 24 | 25 | try { |
| 25 | 26 | JSONObject fixJson = new JSONObject(); |
| 26 | 27 | |
| 27 | - fixJson.put("timestamp", location.getTime()); |
|
| 28 | + fixJson.put("timestamp", new Date().getTime()); |
|
| 28 | 29 | fixJson.put("longitude", location.getLongitude()); |
| 29 | 30 | fixJson.put("latitude", location.getLatitude()); |
| 30 | 31 |
mobile/com.sap.sailing.racecommittee.app/build.gradle
| ... | ... | @@ -81,6 +81,9 @@ dependencies { |
| 81 | 81 | /* Google Play Services */ |
| 82 | 82 | compile "com.google.android.gms:play-services-location:${rootProject.ext.play_services}" |
| 83 | 83 | |
| 84 | + /* licence dialog */ |
|
| 85 | + compile('de.psdev.licensesdialog:licensesdialog:1.8.0') |
|
| 86 | + |
|
| 84 | 87 | /* local dependencies */ |
| 85 | 88 | compile project(":mobile:com.sap.sailing.android.shared") |
| 86 | 89 | compile project(":java:com.sap.sse.common") |
mobile/com.sap.sailing.racecommittee.app/pom.xml
| ... | ... | @@ -77,6 +77,13 @@ |
| 77 | 77 | <version>1.0.0-SNAPSHOT</version> |
| 78 | 78 | <type>apklib</type> |
| 79 | 79 | </dependency> |
| 80 | + |
|
| 81 | + <dependency> |
|
| 82 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 83 | + <artifactId>licensesdialog</artifactId> |
|
| 84 | + <version>1.8.0</version> |
|
| 85 | + <type>aar</type> |
|
| 86 | + </dependency> |
|
| 80 | 87 | </dependencies> |
| 81 | 88 | |
| 82 | 89 | <build> |
| ... | ... | @@ -120,7 +127,7 @@ |
| 120 | 127 | </executions> |
| 121 | 128 | </plugin> |
| 122 | 129 | |
| 123 | - <!-- plugins for generating version file and copying .apk --> |
|
| 130 | + <!-- plugins for generating version file and copying .apk --> |
|
| 124 | 131 | <plugin> |
| 125 | 132 | <groupId>org.apache.maven.plugins</groupId> |
| 126 | 133 | <artifactId>maven-dependency-plugin</artifactId> |
mobile/com.sap.sailing.racecommittee.app/project.properties
| ... | ... | @@ -16,3 +16,4 @@ android.library.reference.1=../google-play-services_lib |
| 16 | 16 | android.library.reference.2=../com.sap.sailing.android.shared |
| 17 | 17 | android.library.reference.3=../google-android-support-v7-recyclerview_lib |
| 18 | 18 | android.library.reference.4=../github-advrecyclerview_lib |
| 19 | +android.library.reference.5=../licensesdialog_lib/de.psdev.licensesdialog |
mobile/com.sap.sailing.racecommittee.app/res/layout/system_information_view.xml
| ... | ... | @@ -92,6 +92,31 @@ |
| 92 | 92 | android:text="@string/application_install_date" |
| 93 | 93 | android:textAppearance="?attr/textSmall"/> |
| 94 | 94 | |
| 95 | + <LinearLayout |
|
| 96 | + android:layout_width="match_parent" |
|
| 97 | + android:layout_height="wrap_content" |
|
| 98 | + android:orientation="horizontal"> |
|
| 99 | + |
|
| 100 | + <Button |
|
| 101 | + android:id="@+id/eula_button" |
|
| 102 | + style="?buttonSolidSmall" |
|
| 103 | + android:layout_width="wrap_content" |
|
| 104 | + android:layout_height="wrap_content" |
|
| 105 | + android:layout_marginTop="16dp" |
|
| 106 | + android:layout_marginBottom="16dp" |
|
| 107 | + android:layout_marginRight="16dp" |
|
| 108 | + android:text="@string/eula"/> |
|
| 109 | + |
|
| 110 | + <Button |
|
| 111 | + android:id="@+id/licence_button" |
|
| 112 | + style="?buttonSolidSmall" |
|
| 113 | + android:layout_width="wrap_content" |
|
| 114 | + android:layout_height="wrap_content" |
|
| 115 | + android:layout_marginTop="16dp" |
|
| 116 | + android:layout_marginBottom="16dp" |
|
| 117 | + android:text="@string/licence_information"/> |
|
| 118 | + </LinearLayout> |
|
| 119 | + |
|
| 95 | 120 | <TextView |
| 96 | 121 | android:id="@+id/system_information_application_install" |
| 97 | 122 | android:layout_width="match_parent" |
mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/LoginActivity.java
| ... | ... | @@ -32,6 +32,7 @@ import com.google.android.gms.common.GooglePlayServicesUtil; |
| 32 | 32 | import com.sap.sailing.android.shared.logging.ExLog; |
| 33 | 33 | import com.sap.sailing.android.shared.util.AppUtils; |
| 34 | 34 | import com.sap.sailing.android.shared.util.BroadcastManager; |
| 35 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 35 | 36 | import com.sap.sailing.android.shared.util.NetworkHelper; |
| 36 | 37 | import com.sap.sailing.android.shared.util.ViewHelper; |
| 37 | 38 | import com.sap.sailing.domain.base.CourseArea; |
| ... | ... | @@ -353,6 +354,10 @@ public class LoginActivity extends BaseActivity |
| 353 | 354 | GooglePlayServicesUtil.getErrorDialog(resultCode, this, 1).show(); |
| 354 | 355 | } |
| 355 | 356 | } |
| 357 | + |
|
| 358 | + if (!EulaHelper.isEulaAccepted(this)) { |
|
| 359 | + EulaHelper.showEulaDialog(this); |
|
| 360 | + } |
|
| 356 | 361 | } |
| 357 | 362 | |
| 358 | 363 | @Override |
mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/SystemInformationActivityHelper.java
| ... | ... | @@ -13,8 +13,13 @@ import android.widget.TextView; |
| 13 | 13 | import android.widget.Toast; |
| 14 | 14 | |
| 15 | 15 | import com.sap.sailing.android.shared.util.AppUtils; |
| 16 | +import com.sap.sailing.android.shared.util.EulaHelper; |
|
| 17 | +import com.sap.sailing.android.shared.util.LicenseHelper; |
|
| 16 | 18 | import com.sap.sailing.racecommittee.app.R; |
| 17 | 19 | |
| 20 | +import de.psdev.licensesdialog.LicensesDialog; |
|
| 21 | +import de.psdev.licensesdialog.model.Notices; |
|
| 22 | + |
|
| 18 | 23 | public class SystemInformationActivityHelper { |
| 19 | 24 | private final SendingServiceAwareActivity activity; |
| 20 | 25 | |
| ... | ... | @@ -25,6 +30,7 @@ public class SystemInformationActivityHelper { |
| 25 | 30 | setupCompileView(); |
| 26 | 31 | setupInstalledView(); |
| 27 | 32 | setupPersistenceView(); |
| 33 | + setupAboutButtons(); |
|
| 28 | 34 | } |
| 29 | 35 | |
| 30 | 36 | /** |
| ... | ... | @@ -89,8 +95,38 @@ public class SystemInformationActivityHelper { |
| 89 | 95 | installView.setText(activity.getString(R.string.generic_error)); |
| 90 | 96 | } else { |
| 91 | 97 | Date installDate = new Date(info.lastUpdateTime); |
| 92 | - installView.setText(String.format("%s - %s", DateFormat.getLongDateFormat(activity).format(installDate), |
|
| 93 | - DateFormat.getTimeFormat(activity).format(installDate))); |
|
| 98 | + installView.setText(String.format("%s - %s", DateFormat.getLongDateFormat(activity).format(installDate), DateFormat |
|
| 99 | + .getTimeFormat(activity).format(installDate))); |
|
| 94 | 100 | } |
| 95 | 101 | } |
| 102 | + |
|
| 103 | + private void setupAboutButtons() { |
|
| 104 | + Button eulaButton = (Button) activity.findViewById(R.id.eula_button); |
|
| 105 | + Button licenceButton = (Button) activity.findViewById(R.id.licence_button); |
|
| 106 | + eulaButton.setOnClickListener(new OnClickListener() { |
|
| 107 | + @Override |
|
| 108 | + public void onClick(View v) { |
|
| 109 | + EulaHelper.openEulaPage(activity); |
|
| 110 | + } |
|
| 111 | + }); |
|
| 112 | + licenceButton.setOnClickListener(new OnClickListener() { |
|
| 113 | + @Override |
|
| 114 | + public void onClick(View v) { |
|
| 115 | + showLicenceDialog(); |
|
| 116 | + } |
|
| 117 | + }); |
|
| 118 | + } |
|
| 119 | + |
|
| 120 | + private void showLicenceDialog() { |
|
| 121 | + Notices notices = new Notices(); |
|
| 122 | + LicenseHelper licenseHelper = new LicenseHelper(); |
|
| 123 | + notices.addNotice(licenseHelper.getAndroidSupportNotice()); |
|
| 124 | + notices.addNotice(licenseHelper.getAdvancedRecyclerViewNotice()); |
|
| 125 | + notices.addNotice(licenseHelper.getJsonSimpleNotice()); |
|
| 126 | + notices.addNotice(licenseHelper.getDialogNotice()); |
|
| 127 | + LicensesDialog.Builder builder = new LicensesDialog.Builder(activity); |
|
| 128 | + builder.setTitle(activity.getString(R.string.licence_information)); |
|
| 129 | + builder.setNotices(notices); |
|
| 130 | + builder.build().show(); |
|
| 131 | + } |
|
| 96 | 132 | } |
mobile/licensesdialog_lib/.gitignore
| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | +# Intellij # |
|
| 2 | +############ |
|
| 3 | +.idea/ |
|
| 4 | +*.iml |
|
| 5 | +*.ipr |
|
| 6 | +*.iws |
|
| 7 | + |
|
| 8 | +# Eclipse # |
|
| 9 | +########### |
|
| 10 | +.settings |
|
| 11 | +.project |
|
| 12 | +.classpath |
|
| 13 | + |
|
| 14 | +# Build Output # |
|
| 15 | +################ |
|
| 16 | +target/ |
|
| 17 | +bin |
|
| 18 | + |
|
| 19 | +# Android # |
|
| 20 | +########### |
|
| 21 | +gen/ |
|
| 22 | +gen-external-apklibs/ |
|
| 23 | + |
|
| 24 | +# MacOsX # |
|
| 25 | +########## |
|
| 26 | +.DS_Store |
|
| 27 | + |
|
| 28 | +# Other # |
|
| 29 | +######### |
|
| 30 | +.~lock* |
|
| 31 | +tmp |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/CHANGELOG.md
| ... | ... | @@ -0,0 +1,62 @@ |
| 1 | +Change Log |
|
| 2 | +========== |
|
| 3 | + |
|
| 4 | +Version 1.8.0 *(2015-07-26)* |
|
| 5 | +------------------------------ |
|
| 6 | + |
|
| 7 | +* added BSD 2-Clause License (#47) |
|
| 8 | +* added GNU LGPL 3 (#43) |
|
| 9 | +* Support Appcompat and alert dialogs in the support library (#42) |
|
| 10 | + |
|
| 11 | +Version 1.7.0 *(2015-02-21)* |
|
| 12 | +---------------------------- |
|
| 13 | + |
|
| 14 | +* Add Japanese translation (#38) |
|
| 15 | +* Adding pre-cached loading of licenses text from resources (#35) |
|
| 16 | +* **WARNING: The API for licenses has changed. Please review your code!** |
|
| 17 | + |
|
| 18 | +Version 1.6.0 *(2014-09-08)* |
|
| 19 | +---------------------------- |
|
| 20 | + |
|
| 21 | +* Added GNU GPLv2 / GPLv3 License (#28) |
|
| 22 | +* Improve NoticesHtmlBuilder speed (#29) |
|
| 23 | +* Added methods for customization (#30) |
|
| 24 | +* Replaced LicensesDialog constructors with builder, removed SingleLicenseDialog as it is now handled by the builder |
|
| 25 | +* **WARNING: The constructor arguments have changed. Please review your code!** |
|
| 26 | + |
|
| 27 | +Version 1.5.0 *(2014-06-01)* |
|
| 28 | +---------------------------- |
|
| 29 | + |
|
| 30 | +* Load notices into a List to allow programmatic modifications (#21) |
|
| 31 | + |
|
| 32 | +Version 1.4.0 *(2014-02-02)* |
|
| 33 | +---------------------------- |
|
| 34 | + |
|
| 35 | +* Switch to aar packaging (#10) |
|
| 36 | + |
|
| 37 | +Version 1.3.0 *(2013-11-24)* |
|
| 38 | +---------------------------- |
|
| 39 | + |
|
| 40 | +* Removed dependency to simple-xml and commons-io |
|
| 41 | + |
|
| 42 | +Version 1.2.1 *(2013-10-15)* |
|
| 43 | +---------------------------- |
|
| 44 | + |
|
| 45 | +* Fixed Typo in LicensesDialogFragment (#11) |
|
| 46 | +* Improve readability of license texts (#12) |
|
| 47 | + |
|
| 48 | +Version 1.2.0 *(2013-09-11)* |
|
| 49 | +---------------------------- |
|
| 50 | + |
|
| 51 | +* Support for MIT License (#7) |
|
| 52 | + |
|
| 53 | +Version 1.1.0 *(2013-05-09)* |
|
| 54 | +---------------------------- |
|
| 55 | + |
|
| 56 | +* Option to include license information of this library in shown Dialog |
|
| 57 | + |
|
| 58 | + |
|
| 59 | +Version 1.0.0 *(2013-04-01)* |
|
| 60 | +---------------------------- |
|
| 61 | + |
|
| 62 | +* Initial release. |
mobile/licensesdialog_lib/LICENSE.txt
| ... | ... | @@ -0,0 +1,202 @@ |
| 1 | + |
|
| 2 | + Apache License |
|
| 3 | + Version 2.0, January 2004 |
|
| 4 | + http://www.apache.org/licenses/ |
|
| 5 | + |
|
| 6 | + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
| 7 | + |
|
| 8 | + 1. Definitions. |
|
| 9 | + |
|
| 10 | + "License" shall mean the terms and conditions for use, reproduction, |
|
| 11 | + and distribution as defined by Sections 1 through 9 of this document. |
|
| 12 | + |
|
| 13 | + "Licensor" shall mean the copyright owner or entity authorized by |
|
| 14 | + the copyright owner that is granting the License. |
|
| 15 | + |
|
| 16 | + "Legal Entity" shall mean the union of the acting entity and all |
|
| 17 | + other entities that control, are controlled by, or are under common |
|
| 18 | + control with that entity. For the purposes of this definition, |
|
| 19 | + "control" means (i) the power, direct or indirect, to cause the |
|
| 20 | + direction or management of such entity, whether by contract or |
|
| 21 | + otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
| 22 | + outstanding shares, or (iii) beneficial ownership of such entity. |
|
| 23 | + |
|
| 24 | + "You" (or "Your") shall mean an individual or Legal Entity |
|
| 25 | + exercising permissions granted by this License. |
|
| 26 | + |
|
| 27 | + "Source" form shall mean the preferred form for making modifications, |
|
| 28 | + including but not limited to software source code, documentation |
|
| 29 | + source, and configuration files. |
|
| 30 | + |
|
| 31 | + "Object" form shall mean any form resulting from mechanical |
|
| 32 | + transformation or translation of a Source form, including but |
|
| 33 | + not limited to compiled object code, generated documentation, |
|
| 34 | + and conversions to other media types. |
|
| 35 | + |
|
| 36 | + "Work" shall mean the work of authorship, whether in Source or |
|
| 37 | + Object form, made available under the License, as indicated by a |
|
| 38 | + copyright notice that is included in or attached to the work |
|
| 39 | + (an example is provided in the Appendix below). |
|
| 40 | + |
|
| 41 | + "Derivative Works" shall mean any work, whether in Source or Object |
|
| 42 | + form, that is based on (or derived from) the Work and for which the |
|
| 43 | + editorial revisions, annotations, elaborations, or other modifications |
|
| 44 | + represent, as a whole, an original work of authorship. For the purposes |
|
| 45 | + of this License, Derivative Works shall not include works that remain |
|
| 46 | + separable from, or merely link (or bind by name) to the interfaces of, |
|
| 47 | + the Work and Derivative Works thereof. |
|
| 48 | + |
|
| 49 | + "Contribution" shall mean any work of authorship, including |
|
| 50 | + the original version of the Work and any modifications or additions |
|
| 51 | + to that Work or Derivative Works thereof, that is intentionally |
|
| 52 | + submitted to Licensor for inclusion in the Work by the copyright owner |
|
| 53 | + or by an individual or Legal Entity authorized to submit on behalf of |
|
| 54 | + the copyright owner. For the purposes of this definition, "submitted" |
|
| 55 | + means any form of electronic, verbal, or written communication sent |
|
| 56 | + to the Licensor or its representatives, including but not limited to |
|
| 57 | + communication on electronic mailing lists, source code control systems, |
|
| 58 | + and issue tracking systems that are managed by, or on behalf of, the |
|
| 59 | + Licensor for the purpose of discussing and improving the Work, but |
|
| 60 | + excluding communication that is conspicuously marked or otherwise |
|
| 61 | + designated in writing by the copyright owner as "Not a Contribution." |
|
| 62 | + |
|
| 63 | + "Contributor" shall mean Licensor and any individual or Legal Entity |
|
| 64 | + on behalf of whom a Contribution has been received by Licensor and |
|
| 65 | + subsequently incorporated within the Work. |
|
| 66 | + |
|
| 67 | + 2. Grant of Copyright License. Subject to the terms and conditions of |
|
| 68 | + this License, each Contributor hereby grants to You a perpetual, |
|
| 69 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 70 | + copyright license to reproduce, prepare Derivative Works of, |
|
| 71 | + publicly display, publicly perform, sublicense, and distribute the |
|
| 72 | + Work and such Derivative Works in Source or Object form. |
|
| 73 | + |
|
| 74 | + 3. Grant of Patent License. Subject to the terms and conditions of |
|
| 75 | + this License, each Contributor hereby grants to You a perpetual, |
|
| 76 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 77 | + (except as stated in this section) patent license to make, have made, |
|
| 78 | + use, offer to sell, sell, import, and otherwise transfer the Work, |
|
| 79 | + where such license applies only to those patent claims licensable |
|
| 80 | + by such Contributor that are necessarily infringed by their |
|
| 81 | + Contribution(s) alone or by combination of their Contribution(s) |
|
| 82 | + with the Work to which such Contribution(s) was submitted. If You |
|
| 83 | + institute patent litigation against any entity (including a |
|
| 84 | + cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
| 85 | + or a Contribution incorporated within the Work constitutes direct |
|
| 86 | + or contributory patent infringement, then any patent licenses |
|
| 87 | + granted to You under this License for that Work shall terminate |
|
| 88 | + as of the date such litigation is filed. |
|
| 89 | + |
|
| 90 | + 4. Redistribution. You may reproduce and distribute copies of the |
|
| 91 | + Work or Derivative Works thereof in any medium, with or without |
|
| 92 | + modifications, and in Source or Object form, provided that You |
|
| 93 | + meet the following conditions: |
|
| 94 | + |
|
| 95 | + (a) You must give any other recipients of the Work or |
|
| 96 | + Derivative Works a copy of this License; and |
|
| 97 | + |
|
| 98 | + (b) You must cause any modified files to carry prominent notices |
|
| 99 | + stating that You changed the files; and |
|
| 100 | + |
|
| 101 | + (c) You must retain, in the Source form of any Derivative Works |
|
| 102 | + that You distribute, all copyright, patent, trademark, and |
|
| 103 | + attribution notices from the Source form of the Work, |
|
| 104 | + excluding those notices that do not pertain to any part of |
|
| 105 | + the Derivative Works; and |
|
| 106 | + |
|
| 107 | + (d) If the Work includes a "NOTICE" text file as part of its |
|
| 108 | + distribution, then any Derivative Works that You distribute must |
|
| 109 | + include a readable copy of the attribution notices contained |
|
| 110 | + within such NOTICE file, excluding those notices that do not |
|
| 111 | + pertain to any part of the Derivative Works, in at least one |
|
| 112 | + of the following places: within a NOTICE text file distributed |
|
| 113 | + as part of the Derivative Works; within the Source form or |
|
| 114 | + documentation, if provided along with the Derivative Works; or, |
|
| 115 | + within a display generated by the Derivative Works, if and |
|
| 116 | + wherever such third-party notices normally appear. The contents |
|
| 117 | + of the NOTICE file are for informational purposes only and |
|
| 118 | + do not modify the License. You may add Your own attribution |
|
| 119 | + notices within Derivative Works that You distribute, alongside |
|
| 120 | + or as an addendum to the NOTICE text from the Work, provided |
|
| 121 | + that such additional attribution notices cannot be construed |
|
| 122 | + as modifying the License. |
|
| 123 | + |
|
| 124 | + You may add Your own copyright statement to Your modifications and |
|
| 125 | + may provide additional or different license terms and conditions |
|
| 126 | + for use, reproduction, or distribution of Your modifications, or |
|
| 127 | + for any such Derivative Works as a whole, provided Your use, |
|
| 128 | + reproduction, and distribution of the Work otherwise complies with |
|
| 129 | + the conditions stated in this License. |
|
| 130 | + |
|
| 131 | + 5. Submission of Contributions. Unless You explicitly state otherwise, |
|
| 132 | + any Contribution intentionally submitted for inclusion in the Work |
|
| 133 | + by You to the Licensor shall be under the terms and conditions of |
|
| 134 | + this License, without any additional terms or conditions. |
|
| 135 | + Notwithstanding the above, nothing herein shall supersede or modify |
|
| 136 | + the terms of any separate license agreement you may have executed |
|
| 137 | + with Licensor regarding such Contributions. |
|
| 138 | + |
|
| 139 | + 6. Trademarks. This License does not grant permission to use the trade |
|
| 140 | + names, trademarks, service marks, or product names of the Licensor, |
|
| 141 | + except as required for reasonable and customary use in describing the |
|
| 142 | + origin of the Work and reproducing the content of the NOTICE file. |
|
| 143 | + |
|
| 144 | + 7. Disclaimer of Warranty. Unless required by applicable law or |
|
| 145 | + agreed to in writing, Licensor provides the Work (and each |
|
| 146 | + Contributor provides its Contributions) on an "AS IS" BASIS, |
|
| 147 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
| 148 | + implied, including, without limitation, any warranties or conditions |
|
| 149 | + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
| 150 | + PARTICULAR PURPOSE. You are solely responsible for determining the |
|
| 151 | + appropriateness of using or redistributing the Work and assume any |
|
| 152 | + risks associated with Your exercise of permissions under this License. |
|
| 153 | + |
|
| 154 | + 8. Limitation of Liability. In no event and under no legal theory, |
|
| 155 | + whether in tort (including negligence), contract, or otherwise, |
|
| 156 | + unless required by applicable law (such as deliberate and grossly |
|
| 157 | + negligent acts) or agreed to in writing, shall any Contributor be |
|
| 158 | + liable to You for damages, including any direct, indirect, special, |
|
| 159 | + incidental, or consequential damages of any character arising as a |
|
| 160 | + result of this License or out of the use or inability to use the |
|
| 161 | + Work (including but not limited to damages for loss of goodwill, |
|
| 162 | + work stoppage, computer failure or malfunction, or any and all |
|
| 163 | + other commercial damages or losses), even if such Contributor |
|
| 164 | + has been advised of the possibility of such damages. |
|
| 165 | + |
|
| 166 | + 9. Accepting Warranty or Additional Liability. While redistributing |
|
| 167 | + the Work or Derivative Works thereof, You may choose to offer, |
|
| 168 | + and charge a fee for, acceptance of support, warranty, indemnity, |
|
| 169 | + or other liability obligations and/or rights consistent with this |
|
| 170 | + License. However, in accepting such obligations, You may act only |
|
| 171 | + on Your own behalf and on Your sole responsibility, not on behalf |
|
| 172 | + of any other Contributor, and only if You agree to indemnify, |
|
| 173 | + defend, and hold each Contributor harmless for any liability |
|
| 174 | + incurred by, or claims asserted against, such Contributor by reason |
|
| 175 | + of your accepting any such warranty or additional liability. |
|
| 176 | + |
|
| 177 | + END OF TERMS AND CONDITIONS |
|
| 178 | + |
|
| 179 | + APPENDIX: How to apply the Apache License to your work. |
|
| 180 | + |
|
| 181 | + To apply the Apache License to your work, attach the following |
|
| 182 | + boilerplate notice, with the fields enclosed by brackets "[]" |
|
| 183 | + replaced with your own identifying information. (Don't include |
|
| 184 | + the brackets!) The text should be enclosed in the appropriate |
|
| 185 | + comment syntax for the file format. We also recommend that a |
|
| 186 | + file or class name and description of purpose be included on the |
|
| 187 | + same "printed page" as the copyright notice for easier |
|
| 188 | + identification within third-party archives. |
|
| 189 | + |
|
| 190 | + Copyright [yyyy] [name of copyright owner] |
|
| 191 | + |
|
| 192 | + Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 193 | + you may not use this file except in compliance with the License. |
|
| 194 | + You may obtain a copy of the License at |
|
| 195 | + |
|
| 196 | + http://www.apache.org/licenses/LICENSE-2.0 |
|
| 197 | + |
|
| 198 | + Unless required by applicable law or agreed to in writing, software |
|
| 199 | + distributed under the License is distributed on an "AS IS" BASIS, |
|
| 200 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 201 | + See the License for the specific language governing permissions and |
|
| 202 | + limitations under the License. |
mobile/licensesdialog_lib/README.md
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +LicensesDialog [](https://ci.psdev.de/job/PSDevLicensesDialog/) [](https://maven-badges.herokuapp.com/maven-central/de.psdev.licensesdialog/licensesdialog) |
|
| 2 | +============== |
|
| 3 | + |
|
| 4 | +LicensesDialog is an open source library to display licenses of third-party libraries in an Android app. |
|
| 5 | + |
|
| 6 | + |
|
| 7 | +Download |
|
| 8 | +-------- |
|
| 9 | + |
|
| 10 | +Download [the latest Release][1] or grab via Maven: |
|
| 11 | + |
|
| 12 | +```xml |
|
| 13 | +<dependency> |
|
| 14 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 15 | + <artifactId>licensesdialog</artifactId> |
|
| 16 | + <version>1.7.0</version> |
|
| 17 | + <type>aar</type> |
|
| 18 | +</dependency> |
|
| 19 | +``` |
|
| 20 | +or Gradle: |
|
| 21 | +```groovy |
|
| 22 | +compile('de.psdev.licensesdialog:licensesdialog:1.7.0') |
|
| 23 | +``` |
|
| 24 | + |
|
| 25 | +Usage |
|
| 26 | +----- |
|
| 27 | + |
|
| 28 | +You can take a look at the [SampleActivity.java](sample/src/main/java/de/psdev/licensesdialog/sample/SampleActivity.java) |
|
| 29 | +from the sample module for examples on how to create the dialogs. |
|
| 30 | + |
|
| 31 | +Sample |
|
| 32 | +------ |
|
| 33 | + |
|
| 34 | +You can get the latest sample from [Jenkins][3] |
|
| 35 | + |
|
| 36 | +Credits |
|
| 37 | +------- |
|
| 38 | + |
|
| 39 | +This library is inspired by [Inscription][2]. |
|
| 40 | + |
|
| 41 | +Contributors |
|
| 42 | +------------ |
|
| 43 | + |
|
| 44 | +Thank you to all the contributors of this project, namely: |
|
| 45 | + |
|
| 46 | +- [Peter Heisig](https://github.com/PSDev/LicensesDialog/commits?author=phdd) |
|
| 47 | +- [Jesus Otero](https://github.com/PSDev/LicensesDialog/commits?author=TheWizKid95) |
|
| 48 | +- [Scott Alexander-Bown](https://github.com/PSDev/LicensesDialog/commits?author=scottyab) |
|
| 49 | +- [barondem](https://github.com/PSDev/LicensesDialog/commits?author=barondem) |
|
| 50 | +- [Shaleen Jain](https://github.com/PSDev/LicensesDialog/commits?author=Shalzz) |
|
| 51 | +- [Zhang Hai](https://github.com/PSDev/LicensesDialog/commits?author=DreaminginCodeZH) |
|
| 52 | +- [Heinrich Reimer](https://github.com/PSDev/LicensesDialog/commits?author=HeinrichReimer) |
|
| 53 | +- [Juan Ramón González](https://github.com/PSDev/LicensesDialog/commits?author=jrgonzalezg) |
|
| 54 | +- [Taeho Kim](https://github.com/PSDev/LicensesDialog/commits?author=kunny) |
|
| 55 | +- [Nacho G. del Amo](https://github.com/PSDev/LicensesDialog/commits?author=ngdelamo) |
|
| 56 | +- [Tatsuya Arai](https://github.com/PSDev/LicensesDialog/commits?author=cutmail) |
|
| 57 | +- [Jakob Schrettenbrunner](https://github.com/PSDev/LicensesDialog/commits?author=schr3j) |
|
| 58 | +- [Sam Duke](https://github.com/PSDev/LicensesDialog/commits?author=samskiter) |
|
| 59 | + |
|
| 60 | +License |
|
| 61 | +------- |
|
| 62 | + |
|
| 63 | + Copyright 2013 Philip Schiffer |
|
| 64 | + |
|
| 65 | + Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 66 | + you may not use this file except in compliance with the License. |
|
| 67 | + You may obtain a copy of the License at |
|
| 68 | + |
|
| 69 | + http://www.apache.org/licenses/LICENSE-2.0 |
|
| 70 | + |
|
| 71 | + Unless required by applicable law or agreed to in writing, software |
|
| 72 | + distributed under the License is distributed on an "AS IS" BASIS, |
|
| 73 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 74 | + See the License for the specific language governing permissions and |
|
| 75 | + limitations under the License. |
|
| 76 | + |
|
| 77 | +[1]: https://github.com/PSDev/LicensesDialog/releases |
|
| 78 | +[2]: https://github.com/MartinvanZ/Inscription |
|
| 79 | +[3]: https://ci.psdev.de/job/PSDevLicensesDialog/lastSuccessfulBuild/artifact/sample/target/ |
mobile/licensesdialog_lib/de.psdev.licensesdialog/AndroidManifest.xml
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
|
| 19 | + android:versionCode="1008000" |
|
| 20 | + android:versionName="1.8.0-SNAPSHOT" |
|
| 21 | + package="de.psdev.licensesdialog"> |
|
| 22 | + |
|
| 23 | + <uses-sdk |
|
| 24 | + android:minSdkVersion="8" |
|
| 25 | + android:targetSdkVersion="22" /> |
|
| 26 | + <application /> |
|
| 27 | +</manifest> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/lint.xml
| ... | ... | @@ -0,0 +1,92 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?><!-- |
|
| 2 | + ~ Copyright 2013 Philip Schiffer |
|
| 3 | + ~ |
|
| 4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + ~ you may not use this file except in compliance with the License. |
|
| 6 | + ~ You may obtain a copy of the License at |
|
| 7 | + ~ |
|
| 8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + ~ |
|
| 10 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + ~ See the License for the specific language governing permissions and |
|
| 14 | + ~ limitations under the License. |
|
| 15 | + --> |
|
| 16 | + |
|
| 17 | +<lint> |
|
| 18 | + <issue id="NewApi"> |
|
| 19 | + <ignore path="target/classes/com/actionbarsherlock/internal/ActionBarSherlockNative.class" /> |
|
| 20 | + <ignore path="target/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeWrapper.class" /> |
|
| 21 | + <ignore path="target/classes/com/actionbarsherlock/internal/app/ActionBarWrapper.class" /> |
|
| 22 | + <ignore path="target/classes/com/actionbarsherlock/internal/app/ActionBarWrapper$TabWrapper.class" /> |
|
| 23 | + <ignore path="target/classes/com/actionbarsherlock/internal/view/ActionProviderWrapper.class" /> |
|
| 24 | + <ignore path="target/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.class" /> |
|
| 25 | + <ignore path="target/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.class" /> |
|
| 26 | + <ignore path="target/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$HasPermanentMenuKey.class" /> |
|
| 27 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class" /> |
|
| 28 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsProgressBar.class" /> |
|
| 29 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/ActionBarView$HomeView.class" /> |
|
| 30 | + <ignore path="target/classes/com/actionbarsherlock/widget/SearchView.class" /> |
|
| 31 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/AbsActionBarView.class" /> |
|
| 32 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/ActionBarContextView.class" /> |
|
| 33 | + <ignore path="target/classes/com/actionbarsherlock/internal/app/ActionBarImpl$1.class" /> |
|
| 34 | + <ignore path="target/classes/com/actionbarsherlock/internal/app/ActionBarImpl.class" /> |
|
| 35 | + <ignore path="target/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeCallbackWrapper.class" /> |
|
| 36 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/ActionBarView.class" /> |
|
| 37 | + <ignore path="target/classes/com/actionbarsherlock/widget/ActivityChooserView$SetActivated.class" /> |
|
| 38 | + <ignore path="target/classes/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.class" /> |
|
| 39 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class" /> |
|
| 40 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class" /> |
|
| 41 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner.class" /> |
|
| 42 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsLinearLayout.class" /> |
|
| 43 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow.class" /> |
|
| 44 | + <ignore path="target/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.class" /> |
|
| 45 | + <ignore path="target/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.class" /> |
|
| 46 | + <ignore path="target/classes/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.class" /> |
|
| 47 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.class" /> |
|
| 48 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockActivity.class" /> |
|
| 49 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockExpandableListActivity.class" /> |
|
| 50 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockListActivity.class" /> |
|
| 51 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class" /> |
|
| 52 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockPreferenceActivity.class" /> |
|
| 53 | + <ignore path="target/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.class" /> |
|
| 54 | + <ignore path="target/classes/com/viewpagerindicator/IcsLinearLayout.class" /> |
|
| 55 | + <ignore path="target/classes/com/viewpagerindicator/CirclePageIndicator.class" /> |
|
| 56 | + </issue> |
|
| 57 | + |
|
| 58 | + <issue id="WrongCall"> |
|
| 59 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class" /> |
|
| 60 | + </issue> |
|
| 61 | + |
|
| 62 | + <issue id="Registered"> |
|
| 63 | + <ignore path="target/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class" /> |
|
| 64 | + </issue> |
|
| 65 | + |
|
| 66 | + <issue id="ViewConstructor"> |
|
| 67 | + <ignore path="target/classes/com/viewpagerindicator/IcsLinearLayout.class" /> |
|
| 68 | + </issue> |
|
| 69 | + |
|
| 70 | + <issue id="FloatMath"> |
|
| 71 | + <ignore path="target/classes/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.class" /> |
|
| 72 | + </issue> |
|
| 73 | + |
|
| 74 | + <issue id="FloatMath"> |
|
| 75 | + <ignore path="target/classes/com/viewpagerindicator/LinePageIndicator.class" /> |
|
| 76 | + </issue> |
|
| 77 | + |
|
| 78 | + <issue id="DefaultLocale"> |
|
| 79 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class" /> |
|
| 80 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class" /> |
|
| 81 | + </issue> |
|
| 82 | + |
|
| 83 | + <issue id="ViewConstructor"> |
|
| 84 | + <ignore path="target/classes/com/actionbarsherlock/internal/widget/CollapsibleActionViewWrapper.class" /> |
|
| 85 | + </issue> |
|
| 86 | + |
|
| 87 | + <issue id="OldTargetApi"> |
|
| 88 | + <ignore path="AndroidManifest.xml" /> |
|
| 89 | + </issue> |
|
| 90 | + |
|
| 91 | + <issue id="InvalidPackage" severity="ignore" /> |
|
| 92 | +</lint> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/pom.xml
| ... | ... | @@ -0,0 +1,140 @@ |
| 1 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|
| 2 | + <modelVersion>4.0.0</modelVersion> |
|
| 3 | + |
|
| 4 | + <parent> |
|
| 5 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 6 | + <artifactId>parent</artifactId> |
|
| 7 | + <version>1.8.0</version> |
|
| 8 | + </parent> |
|
| 9 | + |
|
| 10 | + <artifactId>licensesdialog</artifactId> |
|
| 11 | + <packaging>aar</packaging> |
|
| 12 | + |
|
| 13 | + <name>LicensesDialog (Library)</name> |
|
| 14 | + |
|
| 15 | + <dependencies> |
|
| 16 | + <!-- Testing --> |
|
| 17 | + <dependency> |
|
| 18 | + <groupId>junit</groupId> |
|
| 19 | + <artifactId>junit</artifactId> |
|
| 20 | + <scope>test</scope> |
|
| 21 | + </dependency> |
|
| 22 | + <dependency> |
|
| 23 | + <groupId>org.robolectric</groupId> |
|
| 24 | + <artifactId>robolectric</artifactId> |
|
| 25 | + <scope>test</scope> |
|
| 26 | + </dependency> |
|
| 27 | + |
|
| 28 | + <!-- Android --> |
|
| 29 | + <dependency> |
|
| 30 | + <groupId>com.google.android</groupId> |
|
| 31 | + <artifactId>android</artifactId> |
|
| 32 | + <scope>provided</scope> |
|
| 33 | + </dependency> |
|
| 34 | + <dependency> |
|
| 35 | + <groupId>com.android.support</groupId> |
|
| 36 | + <artifactId>support-v4</artifactId> |
|
| 37 | + <type>aar</type> |
|
| 38 | + </dependency> |
|
| 39 | + <dependency> |
|
| 40 | + <groupId>com.android.support</groupId> |
|
| 41 | + <artifactId>appcompat-v7</artifactId> |
|
| 42 | + <type>aar</type> |
|
| 43 | + </dependency> |
|
| 44 | + |
|
| 45 | + <!-- Nullable support --> |
|
| 46 | + <dependency> |
|
| 47 | + <groupId>com.google.code.findbugs</groupId> |
|
| 48 | + <artifactId>jsr305</artifactId> |
|
| 49 | + </dependency> |
|
| 50 | + </dependencies> |
|
| 51 | + |
|
| 52 | + <build> |
|
| 53 | + <plugins> |
|
| 54 | + <plugin> |
|
| 55 | + <groupId>com.jayway.maven.plugins.android.generation2</groupId> |
|
| 56 | + <artifactId>android-maven-plugin</artifactId> |
|
| 57 | + <extensions>true</extensions> |
|
| 58 | + <executions> |
|
| 59 | + <execution> |
|
| 60 | + <id>runLint</id> |
|
| 61 | + <phase>compile</phase> |
|
| 62 | + <goals> |
|
| 63 | + <goal>lint</goal> |
|
| 64 | + </goals> |
|
| 65 | + </execution> |
|
| 66 | + </executions> |
|
| 67 | + </plugin> |
|
| 68 | + |
|
| 69 | + <plugin> |
|
| 70 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 71 | + <artifactId>maven-source-plugin</artifactId> |
|
| 72 | + <executions> |
|
| 73 | + <execution> |
|
| 74 | + <id>attach-sources</id> |
|
| 75 | + <goals> |
|
| 76 | + <goal>jar</goal> |
|
| 77 | + </goals> |
|
| 78 | + </execution> |
|
| 79 | + </executions> |
|
| 80 | + </plugin> |
|
| 81 | + |
|
| 82 | + <plugin> |
|
| 83 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 84 | + <artifactId>maven-javadoc-plugin</artifactId> |
|
| 85 | + <executions> |
|
| 86 | + <execution> |
|
| 87 | + <id>attach-javadocs</id> |
|
| 88 | + <goals> |
|
| 89 | + <goal>jar</goal> |
|
| 90 | + </goals> |
|
| 91 | + <configuration> |
|
| 92 | + <quiet>true</quiet> |
|
| 93 | + </configuration> |
|
| 94 | + </execution> |
|
| 95 | + </executions> |
|
| 96 | + </plugin> |
|
| 97 | + |
|
| 98 | + <plugin> |
|
| 99 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 100 | + <artifactId>maven-release-plugin</artifactId> |
|
| 101 | + </plugin> |
|
| 102 | + |
|
| 103 | + <plugin> |
|
| 104 | + <groupId>org.jacoco</groupId> |
|
| 105 | + <artifactId>jacoco-maven-plugin</artifactId> |
|
| 106 | + </plugin> |
|
| 107 | + </plugins> |
|
| 108 | + </build> |
|
| 109 | + |
|
| 110 | + |
|
| 111 | + <profiles> |
|
| 112 | + <profile> |
|
| 113 | + <id>release</id> |
|
| 114 | + <activation> |
|
| 115 | + <property> |
|
| 116 | + <name>performRelease</name> |
|
| 117 | + <value>true</value> |
|
| 118 | + </property> |
|
| 119 | + </activation> |
|
| 120 | + <build> |
|
| 121 | + <plugins> |
|
| 122 | + <plugin> |
|
| 123 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 124 | + <artifactId>maven-gpg-plugin</artifactId> |
|
| 125 | + <version>${maven-gpg-plugin.version}</version> |
|
| 126 | + <executions> |
|
| 127 | + <execution> |
|
| 128 | + <id>sign-artifacts</id> |
|
| 129 | + <phase>verify</phase> |
|
| 130 | + <goals> |
|
| 131 | + <goal>sign</goal> |
|
| 132 | + </goals> |
|
| 133 | + </execution> |
|
| 134 | + </executions> |
|
| 135 | + </plugin> |
|
| 136 | + </plugins> |
|
| 137 | + </build> |
|
| 138 | + </profile> |
|
| 139 | + </profiles> |
|
| 140 | +</project> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/project.properties
| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | +# This file is automatically generated by Android Tools. |
|
| 2 | +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! |
|
| 3 | +# |
|
| 4 | +# This file must be checked in Version Control Systems. |
|
| 5 | +# |
|
| 6 | +# To customize properties used by the Ant build system edit |
|
| 7 | +# "ant.properties", and override values to adapt the script to your |
|
| 8 | +# project structure. |
|
| 9 | +# |
|
| 10 | +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): |
|
| 11 | +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt |
|
| 12 | + |
|
| 13 | +# Project target. |
|
| 14 | +target=android-14 |
|
| 15 | +android.library=true |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/asl_20_full.txt
| ... | ... | @@ -0,0 +1,202 @@ |
| 1 | + |
|
| 2 | + Apache License |
|
| 3 | + Version 2.0, January 2004 |
|
| 4 | + http://www.apache.org/licenses/ |
|
| 5 | + |
|
| 6 | + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
| 7 | + |
|
| 8 | + 1. Definitions. |
|
| 9 | + |
|
| 10 | + "License" shall mean the terms and conditions for use, reproduction, |
|
| 11 | + and distribution as defined by Sections 1 through 9 of this document. |
|
| 12 | + |
|
| 13 | + "Licensor" shall mean the copyright owner or entity authorized by |
|
| 14 | + the copyright owner that is granting the License. |
|
| 15 | + |
|
| 16 | + "Legal Entity" shall mean the union of the acting entity and all |
|
| 17 | + other entities that control, are controlled by, or are under common |
|
| 18 | + control with that entity. For the purposes of this definition, |
|
| 19 | + "control" means (i) the power, direct or indirect, to cause the |
|
| 20 | + direction or management of such entity, whether by contract or |
|
| 21 | + otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
| 22 | + outstanding shares, or (iii) beneficial ownership of such entity. |
|
| 23 | + |
|
| 24 | + "You" (or "Your") shall mean an individual or Legal Entity |
|
| 25 | + exercising permissions granted by this License. |
|
| 26 | + |
|
| 27 | + "Source" form shall mean the preferred form for making modifications, |
|
| 28 | + including but not limited to software source code, documentation |
|
| 29 | + source, and configuration files. |
|
| 30 | + |
|
| 31 | + "Object" form shall mean any form resulting from mechanical |
|
| 32 | + transformation or translation of a Source form, including but |
|
| 33 | + not limited to compiled object code, generated documentation, |
|
| 34 | + and conversions to other media types. |
|
| 35 | + |
|
| 36 | + "Work" shall mean the work of authorship, whether in Source or |
|
| 37 | + Object form, made available under the License, as indicated by a |
|
| 38 | + copyright notice that is included in or attached to the work |
|
| 39 | + (an example is provided in the Appendix below). |
|
| 40 | + |
|
| 41 | + "Derivative Works" shall mean any work, whether in Source or Object |
|
| 42 | + form, that is based on (or derived from) the Work and for which the |
|
| 43 | + editorial revisions, annotations, elaborations, or other modifications |
|
| 44 | + represent, as a whole, an original work of authorship. For the purposes |
|
| 45 | + of this License, Derivative Works shall not include works that remain |
|
| 46 | + separable from, or merely link (or bind by name) to the interfaces of, |
|
| 47 | + the Work and Derivative Works thereof. |
|
| 48 | + |
|
| 49 | + "Contribution" shall mean any work of authorship, including |
|
| 50 | + the original version of the Work and any modifications or additions |
|
| 51 | + to that Work or Derivative Works thereof, that is intentionally |
|
| 52 | + submitted to Licensor for inclusion in the Work by the copyright owner |
|
| 53 | + or by an individual or Legal Entity authorized to submit on behalf of |
|
| 54 | + the copyright owner. For the purposes of this definition, "submitted" |
|
| 55 | + means any form of electronic, verbal, or written communication sent |
|
| 56 | + to the Licensor or its representatives, including but not limited to |
|
| 57 | + communication on electronic mailing lists, source code control systems, |
|
| 58 | + and issue tracking systems that are managed by, or on behalf of, the |
|
| 59 | + Licensor for the purpose of discussing and improving the Work, but |
|
| 60 | + excluding communication that is conspicuously marked or otherwise |
|
| 61 | + designated in writing by the copyright owner as "Not a Contribution." |
|
| 62 | + |
|
| 63 | + "Contributor" shall mean Licensor and any individual or Legal Entity |
|
| 64 | + on behalf of whom a Contribution has been received by Licensor and |
|
| 65 | + subsequently incorporated within the Work. |
|
| 66 | + |
|
| 67 | + 2. Grant of Copyright License. Subject to the terms and conditions of |
|
| 68 | + this License, each Contributor hereby grants to You a perpetual, |
|
| 69 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 70 | + copyright license to reproduce, prepare Derivative Works of, |
|
| 71 | + publicly display, publicly perform, sublicense, and distribute the |
|
| 72 | + Work and such Derivative Works in Source or Object form. |
|
| 73 | + |
|
| 74 | + 3. Grant of Patent License. Subject to the terms and conditions of |
|
| 75 | + this License, each Contributor hereby grants to You a perpetual, |
|
| 76 | + worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 77 | + (except as stated in this section) patent license to make, have made, |
|
| 78 | + use, offer to sell, sell, import, and otherwise transfer the Work, |
|
| 79 | + where such license applies only to those patent claims licensable |
|
| 80 | + by such Contributor that are necessarily infringed by their |
|
| 81 | + Contribution(s) alone or by combination of their Contribution(s) |
|
| 82 | + with the Work to which such Contribution(s) was submitted. If You |
|
| 83 | + institute patent litigation against any entity (including a |
|
| 84 | + cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
| 85 | + or a Contribution incorporated within the Work constitutes direct |
|
| 86 | + or contributory patent infringement, then any patent licenses |
|
| 87 | + granted to You under this License for that Work shall terminate |
|
| 88 | + as of the date such litigation is filed. |
|
| 89 | + |
|
| 90 | + 4. Redistribution. You may reproduce and distribute copies of the |
|
| 91 | + Work or Derivative Works thereof in any medium, with or without |
|
| 92 | + modifications, and in Source or Object form, provided that You |
|
| 93 | + meet the following conditions: |
|
| 94 | + |
|
| 95 | + (a) You must give any other recipients of the Work or |
|
| 96 | + Derivative Works a copy of this License; and |
|
| 97 | + |
|
| 98 | + (b) You must cause any modified files to carry prominent notices |
|
| 99 | + stating that You changed the files; and |
|
| 100 | + |
|
| 101 | + (c) You must retain, in the Source form of any Derivative Works |
|
| 102 | + that You distribute, all copyright, patent, trademark, and |
|
| 103 | + attribution notices from the Source form of the Work, |
|
| 104 | + excluding those notices that do not pertain to any part of |
|
| 105 | + the Derivative Works; and |
|
| 106 | + |
|
| 107 | + (d) If the Work includes a "NOTICE" text file as part of its |
|
| 108 | + distribution, then any Derivative Works that You distribute must |
|
| 109 | + include a readable copy of the attribution notices contained |
|
| 110 | + within such NOTICE file, excluding those notices that do not |
|
| 111 | + pertain to any part of the Derivative Works, in at least one |
|
| 112 | + of the following places: within a NOTICE text file distributed |
|
| 113 | + as part of the Derivative Works; within the Source form or |
|
| 114 | + documentation, if provided along with the Derivative Works; or, |
|
| 115 | + within a display generated by the Derivative Works, if and |
|
| 116 | + wherever such third-party notices normally appear. The contents |
|
| 117 | + of the NOTICE file are for informational purposes only and |
|
| 118 | + do not modify the License. You may add Your own attribution |
|
| 119 | + notices within Derivative Works that You distribute, alongside |
|
| 120 | + or as an addendum to the NOTICE text from the Work, provided |
|
| 121 | + that such additional attribution notices cannot be construed |
|
| 122 | + as modifying the License. |
|
| 123 | + |
|
| 124 | + You may add Your own copyright statement to Your modifications and |
|
| 125 | + may provide additional or different license terms and conditions |
|
| 126 | + for use, reproduction, or distribution of Your modifications, or |
|
| 127 | + for any such Derivative Works as a whole, provided Your use, |
|
| 128 | + reproduction, and distribution of the Work otherwise complies with |
|
| 129 | + the conditions stated in this License. |
|
| 130 | + |
|
| 131 | + 5. Submission of Contributions. Unless You explicitly state otherwise, |
|
| 132 | + any Contribution intentionally submitted for inclusion in the Work |
|
| 133 | + by You to the Licensor shall be under the terms and conditions of |
|
| 134 | + this License, without any additional terms or conditions. |
|
| 135 | + Notwithstanding the above, nothing herein shall supersede or modify |
|
| 136 | + the terms of any separate license agreement you may have executed |
|
| 137 | + with Licensor regarding such Contributions. |
|
| 138 | + |
|
| 139 | + 6. Trademarks. This License does not grant permission to use the trade |
|
| 140 | + names, trademarks, service marks, or product names of the Licensor, |
|
| 141 | + except as required for reasonable and customary use in describing the |
|
| 142 | + origin of the Work and reproducing the content of the NOTICE file. |
|
| 143 | + |
|
| 144 | + 7. Disclaimer of Warranty. Unless required by applicable law or |
|
| 145 | + agreed to in writing, Licensor provides the Work (and each |
|
| 146 | + Contributor provides its Contributions) on an "AS IS" BASIS, |
|
| 147 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
| 148 | + implied, including, without limitation, any warranties or conditions |
|
| 149 | + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
| 150 | + PARTICULAR PURPOSE. You are solely responsible for determining the |
|
| 151 | + appropriateness of using or redistributing the Work and assume any |
|
| 152 | + risks associated with Your exercise of permissions under this License. |
|
| 153 | + |
|
| 154 | + 8. Limitation of Liability. In no event and under no legal theory, |
|
| 155 | + whether in tort (including negligence), contract, or otherwise, |
|
| 156 | + unless required by applicable law (such as deliberate and grossly |
|
| 157 | + negligent acts) or agreed to in writing, shall any Contributor be |
|
| 158 | + liable to You for damages, including any direct, indirect, special, |
|
| 159 | + incidental, or consequential damages of any character arising as a |
|
| 160 | + result of this License or out of the use or inability to use the |
|
| 161 | + Work (including but not limited to damages for loss of goodwill, |
|
| 162 | + work stoppage, computer failure or malfunction, or any and all |
|
| 163 | + other commercial damages or losses), even if such Contributor |
|
| 164 | + has been advised of the possibility of such damages. |
|
| 165 | + |
|
| 166 | + 9. Accepting Warranty or Additional Liability. While redistributing |
|
| 167 | + the Work or Derivative Works thereof, You may choose to offer, |
|
| 168 | + and charge a fee for, acceptance of support, warranty, indemnity, |
|
| 169 | + or other liability obligations and/or rights consistent with this |
|
| 170 | + License. However, in accepting such obligations, You may act only |
|
| 171 | + on Your own behalf and on Your sole responsibility, not on behalf |
|
| 172 | + of any other Contributor, and only if You agree to indemnify, |
|
| 173 | + defend, and hold each Contributor harmless for any liability |
|
| 174 | + incurred by, or claims asserted against, such Contributor by reason |
|
| 175 | + of your accepting any such warranty or additional liability. |
|
| 176 | + |
|
| 177 | + END OF TERMS AND CONDITIONS |
|
| 178 | + |
|
| 179 | + APPENDIX: How to apply the Apache License to your work. |
|
| 180 | + |
|
| 181 | + To apply the Apache License to your work, attach the following |
|
| 182 | + boilerplate notice, with the fields enclosed by brackets "[]" |
|
| 183 | + replaced with your own identifying information. (Don't include |
|
| 184 | + the brackets!) The text should be enclosed in the appropriate |
|
| 185 | + comment syntax for the file format. We also recommend that a |
|
| 186 | + file or class name and description of purpose be included on the |
|
| 187 | + same "printed page" as the copyright notice for easier |
|
| 188 | + identification within third-party archives. |
|
| 189 | + |
|
| 190 | + Copyright [yyyy] [name of copyright owner] |
|
| 191 | + |
|
| 192 | + Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 193 | + you may not use this file except in compliance with the License. |
|
| 194 | + You may obtain a copy of the License at |
|
| 195 | + |
|
| 196 | + http://www.apache.org/licenses/LICENSE-2.0 |
|
| 197 | + |
|
| 198 | + Unless required by applicable law or agreed to in writing, software |
|
| 199 | + distributed under the License is distributed on an "AS IS" BASIS, |
|
| 200 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 201 | + See the License for the specific language governing permissions and |
|
| 202 | + limitations under the License. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/asl_20_summary.txt
| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | +Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 2 | +you may not use this file except in compliance with the License. |
|
| 3 | +You may obtain a copy of the License at |
|
| 4 | + |
|
| 5 | + http://www.apache.org/licenses/LICENSE-2.0 |
|
| 6 | + |
|
| 7 | +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/bsd2_full.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
| 2 | + |
|
| 3 | +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
| 4 | +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
| 5 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/bsd2_summary.txt
| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
| 2 | + |
|
| 3 | +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
| 4 | +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/bsd3_full.txt
| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
| 2 | + |
|
| 3 | +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
| 4 | +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
| 5 | +Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
|
| 6 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/bsd3_summary.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
| 2 | + |
|
| 3 | +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
| 4 | +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
| 5 | +Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/ccand_30_full.txt
| ... | ... | @@ -0,0 +1,293 @@ |
| 1 | +Creative Commons Legal Code |
|
| 2 | + |
|
| 3 | +Attribution-NoDerivs 3.0 Unported |
|
| 4 | + |
|
| 5 | + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE |
|
| 6 | + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN |
|
| 7 | + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS |
|
| 8 | + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES |
|
| 9 | + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR |
|
| 10 | + DAMAGES RESULTING FROM ITS USE. |
|
| 11 | + |
|
| 12 | +License |
|
| 13 | + |
|
| 14 | +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE |
|
| 15 | +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY |
|
| 16 | +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS |
|
| 17 | +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. |
|
| 18 | + |
|
| 19 | +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE |
|
| 20 | +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY |
|
| 21 | +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS |
|
| 22 | +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND |
|
| 23 | +CONDITIONS. |
|
| 24 | + |
|
| 25 | +1. Definitions |
|
| 26 | + |
|
| 27 | + a. "Adaptation" means a work based upon the Work, or upon the Work and |
|
| 28 | + other pre-existing works, such as a translation, adaptation, |
|
| 29 | + derivative work, arrangement of music or other alterations of a |
|
| 30 | + literary or artistic work, or phonogram or performance and includes |
|
| 31 | + cinematographic adaptations or any other form in which the Work may be |
|
| 32 | + recast, transformed, or adapted including in any form recognizably |
|
| 33 | + derived from the original, except that a work that constitutes a |
|
| 34 | + Collection will not be considered an Adaptation for the purpose of |
|
| 35 | + this License. For the avoidance of doubt, where the Work is a musical |
|
| 36 | + work, performance or phonogram, the synchronization of the Work in |
|
| 37 | + timed-relation with a moving image ("synching") will be considered an |
|
| 38 | + Adaptation for the purpose of this License. |
|
| 39 | + b. "Collection" means a collection of literary or artistic works, such as |
|
| 40 | + encyclopedias and anthologies, or performances, phonograms or |
|
| 41 | + broadcasts, or other works or subject matter other than works listed |
|
| 42 | + in Section 1(f) below, which, by reason of the selection and |
|
| 43 | + arrangement of their contents, constitute intellectual creations, in |
|
| 44 | + which the Work is included in its entirety in unmodified form along |
|
| 45 | + with one or more other contributions, each constituting separate and |
|
| 46 | + independent works in themselves, which together are assembled into a |
|
| 47 | + collective whole. A work that constitutes a Collection will not be |
|
| 48 | + considered an Adaptation (as defined above) for the purposes of this |
|
| 49 | + License. |
|
| 50 | + c. "Distribute" means to make available to the public the original and |
|
| 51 | + copies of the Work through sale or other transfer of ownership. |
|
| 52 | + d. "Licensor" means the individual, individuals, entity or entities that |
|
| 53 | + offer(s) the Work under the terms of this License. |
|
| 54 | + e. "Original Author" means, in the case of a literary or artistic work, |
|
| 55 | + the individual, individuals, entity or entities who created the Work |
|
| 56 | + or if no individual or entity can be identified, the publisher; and in |
|
| 57 | + addition (i) in the case of a performance the actors, singers, |
|
| 58 | + musicians, dancers, and other persons who act, sing, deliver, declaim, |
|
| 59 | + play in, interpret or otherwise perform literary or artistic works or |
|
| 60 | + expressions of folklore; (ii) in the case of a phonogram the producer |
|
| 61 | + being the person or legal entity who first fixes the sounds of a |
|
| 62 | + performance or other sounds; and, (iii) in the case of broadcasts, the |
|
| 63 | + organization that transmits the broadcast. |
|
| 64 | + f. "Work" means the literary and/or artistic work offered under the terms |
|
| 65 | + of this License including without limitation any production in the |
|
| 66 | + literary, scientific and artistic domain, whatever may be the mode or |
|
| 67 | + form of its expression including digital form, such as a book, |
|
| 68 | + pamphlet and other writing; a lecture, address, sermon or other work |
|
| 69 | + of the same nature; a dramatic or dramatico-musical work; a |
|
| 70 | + choreographic work or entertainment in dumb show; a musical |
|
| 71 | + composition with or without words; a cinematographic work to which are |
|
| 72 | + assimilated works expressed by a process analogous to cinematography; |
|
| 73 | + a work of drawing, painting, architecture, sculpture, engraving or |
|
| 74 | + lithography; a photographic work to which are assimilated works |
|
| 75 | + expressed by a process analogous to photography; a work of applied |
|
| 76 | + art; an illustration, map, plan, sketch or three-dimensional work |
|
| 77 | + relative to geography, topography, architecture or science; a |
|
| 78 | + performance; a broadcast; a phonogram; a compilation of data to the |
|
| 79 | + extent it is protected as a copyrightable work; or a work performed by |
|
| 80 | + a variety or circus performer to the extent it is not otherwise |
|
| 81 | + considered a literary or artistic work. |
|
| 82 | + g. "You" means an individual or entity exercising rights under this |
|
| 83 | + License who has not previously violated the terms of this License with |
|
| 84 | + respect to the Work, or who has received express permission from the |
|
| 85 | + Licensor to exercise rights under this License despite a previous |
|
| 86 | + violation. |
|
| 87 | + h. "Publicly Perform" means to perform public recitations of the Work and |
|
| 88 | + to communicate to the public those public recitations, by any means or |
|
| 89 | + process, including by wire or wireless means or public digital |
|
| 90 | + performances; to make available to the public Works in such a way that |
|
| 91 | + members of the public may access these Works from a place and at a |
|
| 92 | + place individually chosen by them; to perform the Work to the public |
|
| 93 | + by any means or process and the communication to the public of the |
|
| 94 | + performances of the Work, including by public digital performance; to |
|
| 95 | + broadcast and rebroadcast the Work by any means including signs, |
|
| 96 | + sounds or images. |
|
| 97 | + i. "Reproduce" means to make copies of the Work by any means including |
|
| 98 | + without limitation by sound or visual recordings and the right of |
|
| 99 | + fixation and reproducing fixations of the Work, including storage of a |
|
| 100 | + protected performance or phonogram in digital form or other electronic |
|
| 101 | + medium. |
|
| 102 | + |
|
| 103 | +2. Fair Dealing Rights. Nothing in this License is intended to reduce, |
|
| 104 | +limit, or restrict any uses free from copyright or rights arising from |
|
| 105 | +limitations or exceptions that are provided for in connection with the |
|
| 106 | +copyright protection under copyright law or other applicable laws. |
|
| 107 | + |
|
| 108 | +3. License Grant. Subject to the terms and conditions of this License, |
|
| 109 | +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, |
|
| 110 | +perpetual (for the duration of the applicable copyright) license to |
|
| 111 | +exercise the rights in the Work as stated below: |
|
| 112 | + |
|
| 113 | + a. to Reproduce the Work, to incorporate the Work into one or more |
|
| 114 | + Collections, and to Reproduce the Work as incorporated in the |
|
| 115 | + Collections; and, |
|
| 116 | + b. to Distribute and Publicly Perform the Work including as incorporated |
|
| 117 | + in Collections. |
|
| 118 | + c. For the avoidance of doubt: |
|
| 119 | + |
|
| 120 | + i. Non-waivable Compulsory License Schemes. In those jurisdictions in |
|
| 121 | + which the right to collect royalties through any statutory or |
|
| 122 | + compulsory licensing scheme cannot be waived, the Licensor |
|
| 123 | + reserves the exclusive right to collect such royalties for any |
|
| 124 | + exercise by You of the rights granted under this License; |
|
| 125 | + ii. Waivable Compulsory License Schemes. In those jurisdictions in |
|
| 126 | + which the right to collect royalties through any statutory or |
|
| 127 | + compulsory licensing scheme can be waived, the Licensor waives the |
|
| 128 | + exclusive right to collect such royalties for any exercise by You |
|
| 129 | + of the rights granted under this License; and, |
|
| 130 | + iii. Voluntary License Schemes. The Licensor waives the right to |
|
| 131 | + collect royalties, whether individually or, in the event that the |
|
| 132 | + Licensor is a member of a collecting society that administers |
|
| 133 | + voluntary licensing schemes, via that society, from any exercise |
|
| 134 | + by You of the rights granted under this License. |
|
| 135 | + |
|
| 136 | +The above rights may be exercised in all media and formats whether now |
|
| 137 | +known or hereafter devised. The above rights include the right to make |
|
| 138 | +such modifications as are technically necessary to exercise the rights in |
|
| 139 | +other media and formats, but otherwise you have no rights to make |
|
| 140 | +Adaptations. Subject to Section 8(f), all rights not expressly granted by |
|
| 141 | +Licensor are hereby reserved. |
|
| 142 | + |
|
| 143 | +4. Restrictions. The license granted in Section 3 above is expressly made |
|
| 144 | +subject to and limited by the following restrictions: |
|
| 145 | + |
|
| 146 | + a. You may Distribute or Publicly Perform the Work only under the terms |
|
| 147 | + of this License. You must include a copy of, or the Uniform Resource |
|
| 148 | + Identifier (URI) for, this License with every copy of the Work You |
|
| 149 | + Distribute or Publicly Perform. You may not offer or impose any terms |
|
| 150 | + on the Work that restrict the terms of this License or the ability of |
|
| 151 | + the recipient of the Work to exercise the rights granted to that |
|
| 152 | + recipient under the terms of the License. You may not sublicense the |
|
| 153 | + Work. You must keep intact all notices that refer to this License and |
|
| 154 | + to the disclaimer of warranties with every copy of the Work You |
|
| 155 | + Distribute or Publicly Perform. When You Distribute or Publicly |
|
| 156 | + Perform the Work, You may not impose any effective technological |
|
| 157 | + measures on the Work that restrict the ability of a recipient of the |
|
| 158 | + Work from You to exercise the rights granted to that recipient under |
|
| 159 | + the terms of the License. This Section 4(a) applies to the Work as |
|
| 160 | + incorporated in a Collection, but this does not require the Collection |
|
| 161 | + apart from the Work itself to be made subject to the terms of this |
|
| 162 | + License. If You create a Collection, upon notice from any Licensor You |
|
| 163 | + must, to the extent practicable, remove from the Collection any credit |
|
| 164 | + as required by Section 4(b), as requested. |
|
| 165 | + b. If You Distribute, or Publicly Perform the Work or Collections, You |
|
| 166 | + must, unless a request has been made pursuant to Section 4(a), keep |
|
| 167 | + intact all copyright notices for the Work and provide, reasonable to |
|
| 168 | + the medium or means You are utilizing: (i) the name of the Original |
|
| 169 | + Author (or pseudonym, if applicable) if supplied, and/or if the |
|
| 170 | + Original Author and/or Licensor designate another party or parties |
|
| 171 | + (e.g., a sponsor institute, publishing entity, journal) for |
|
| 172 | + attribution ("Attribution Parties") in Licensor's copyright notice, |
|
| 173 | + terms of service or by other reasonable means, the name of such party |
|
| 174 | + or parties; (ii) the title of the Work if supplied; (iii) to the |
|
| 175 | + extent reasonably practicable, the URI, if any, that Licensor |
|
| 176 | + specifies to be associated with the Work, unless such URI does not |
|
| 177 | + refer to the copyright notice or licensing information for the Work. |
|
| 178 | + The credit required by this Section 4(b) may be implemented in any |
|
| 179 | + reasonable manner; provided, however, that in the case of a |
|
| 180 | + Collection, at a minimum such credit will appear, if a credit for all |
|
| 181 | + contributing authors of the Collection appears, then as part of these |
|
| 182 | + credits and in a manner at least as prominent as the credits for the |
|
| 183 | + other contributing authors. For the avoidance of doubt, You may only |
|
| 184 | + use the credit required by this Section for the purpose of attribution |
|
| 185 | + in the manner set out above and, by exercising Your rights under this |
|
| 186 | + License, You may not implicitly or explicitly assert or imply any |
|
| 187 | + connection with, sponsorship or endorsement by the Original Author, |
|
| 188 | + Licensor and/or Attribution Parties, as appropriate, of You or Your |
|
| 189 | + use of the Work, without the separate, express prior written |
|
| 190 | + permission of the Original Author, Licensor and/or Attribution |
|
| 191 | + Parties. |
|
| 192 | + c. Except as otherwise agreed in writing by the Licensor or as may be |
|
| 193 | + otherwise permitted by applicable law, if You Reproduce, Distribute or |
|
| 194 | + Publicly Perform the Work either by itself or as part of any |
|
| 195 | + Collections, You must not distort, mutilate, modify or take other |
|
| 196 | + derogatory action in relation to the Work which would be prejudicial |
|
| 197 | + to the Original Author's honor or reputation. |
|
| 198 | + |
|
| 199 | +5. Representations, Warranties and Disclaimer |
|
| 200 | + |
|
| 201 | +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR |
|
| 202 | +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY |
|
| 203 | +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, |
|
| 204 | +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, |
|
| 205 | +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF |
|
| 206 | +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, |
|
| 207 | +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION |
|
| 208 | +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. |
|
| 209 | + |
|
| 210 | +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE |
|
| 211 | +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR |
|
| 212 | +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES |
|
| 213 | +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS |
|
| 214 | +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
|
| 215 | + |
|
| 216 | +7. Termination |
|
| 217 | + |
|
| 218 | + a. This License and the rights granted hereunder will terminate |
|
| 219 | + automatically upon any breach by You of the terms of this License. |
|
| 220 | + Individuals or entities who have received Collections from You under |
|
| 221 | + this License, however, will not have their licenses terminated |
|
| 222 | + provided such individuals or entities remain in full compliance with |
|
| 223 | + those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any |
|
| 224 | + termination of this License. |
|
| 225 | + b. Subject to the above terms and conditions, the license granted here is |
|
| 226 | + perpetual (for the duration of the applicable copyright in the Work). |
|
| 227 | + Notwithstanding the above, Licensor reserves the right to release the |
|
| 228 | + Work under different license terms or to stop distributing the Work at |
|
| 229 | + any time; provided, however that any such election will not serve to |
|
| 230 | + withdraw this License (or any other license that has been, or is |
|
| 231 | + required to be, granted under the terms of this License), and this |
|
| 232 | + License will continue in full force and effect unless terminated as |
|
| 233 | + stated above. |
|
| 234 | + |
|
| 235 | +8. Miscellaneous |
|
| 236 | + |
|
| 237 | + a. Each time You Distribute or Publicly Perform the Work or a Collection, |
|
| 238 | + the Licensor offers to the recipient a license to the Work on the same |
|
| 239 | + terms and conditions as the license granted to You under this License. |
|
| 240 | + b. If any provision of this License is invalid or unenforceable under |
|
| 241 | + applicable law, it shall not affect the validity or enforceability of |
|
| 242 | + the remainder of the terms of this License, and without further action |
|
| 243 | + by the parties to this agreement, such provision shall be reformed to |
|
| 244 | + the minimum extent necessary to make such provision valid and |
|
| 245 | + enforceable. |
|
| 246 | + c. No term or provision of this License shall be deemed waived and no |
|
| 247 | + breach consented to unless such waiver or consent shall be in writing |
|
| 248 | + and signed by the party to be charged with such waiver or consent. |
|
| 249 | + d. This License constitutes the entire agreement between the parties with |
|
| 250 | + respect to the Work licensed here. There are no understandings, |
|
| 251 | + agreements or representations with respect to the Work not specified |
|
| 252 | + here. Licensor shall not be bound by any additional provisions that |
|
| 253 | + may appear in any communication from You. This License may not be |
|
| 254 | + modified without the mutual written agreement of the Licensor and You. |
|
| 255 | + e. The rights granted under, and the subject matter referenced, in this |
|
| 256 | + License were drafted utilizing the terminology of the Berne Convention |
|
| 257 | + for the Protection of Literary and Artistic Works (as amended on |
|
| 258 | + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright |
|
| 259 | + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 |
|
| 260 | + and the Universal Copyright Convention (as revised on July 24, 1971). |
|
| 261 | + These rights and subject matter take effect in the relevant |
|
| 262 | + jurisdiction in which the License terms are sought to be enforced |
|
| 263 | + according to the corresponding provisions of the implementation of |
|
| 264 | + those treaty provisions in the applicable national law. If the |
|
| 265 | + standard suite of rights granted under applicable copyright law |
|
| 266 | + includes additional rights not granted under this License, such |
|
| 267 | + additional rights are deemed to be included in the License; this |
|
| 268 | + License is not intended to restrict the license of any rights under |
|
| 269 | + applicable law. |
|
| 270 | + |
|
| 271 | + |
|
| 272 | +Creative Commons Notice |
|
| 273 | + |
|
| 274 | + Creative Commons is not a party to this License, and makes no warranty |
|
| 275 | + whatsoever in connection with the Work. Creative Commons will not be |
|
| 276 | + liable to You or any party on any legal theory for any damages |
|
| 277 | + whatsoever, including without limitation any general, special, |
|
| 278 | + incidental or consequential damages arising in connection to this |
|
| 279 | + license. Notwithstanding the foregoing two (2) sentences, if Creative |
|
| 280 | + Commons has expressly identified itself as the Licensor hereunder, it |
|
| 281 | + shall have all rights and obligations of Licensor. |
|
| 282 | + |
|
| 283 | + Except for the limited purpose of indicating to the public that the |
|
| 284 | + Work is licensed under the CCPL, Creative Commons does not authorize |
|
| 285 | + the use by either party of the trademark "Creative Commons" or any |
|
| 286 | + related trademark or logo of Creative Commons without the prior |
|
| 287 | + written consent of Creative Commons. Any permitted use will be in |
|
| 288 | + compliance with Creative Commons' then-current trademark usage |
|
| 289 | + guidelines, as may be published on its website or otherwise made |
|
| 290 | + available upon request from time to time. For the avoidance of doubt, |
|
| 291 | + this trademark restriction does not form part of this License. |
|
| 292 | + |
|
| 293 | + Creative Commons may be contacted at http://creativecommons.org/. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/ccand_30_summary.txt
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +You are free to: |
|
| 2 | + |
|
| 3 | + Share - copy and redistribute the material in any medium or format for any purpose, even commercially. |
|
| 4 | + The licensor cannot revoke these freedoms as long as you follow the license terms. |
|
| 5 | + |
|
| 6 | +Under the following terms: |
|
| 7 | + |
|
| 8 | + Attribution - You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. |
|
| 9 | + NoDerivatives - If you remix, transform, or build upon the material, you may not distribute the modified material. |
|
| 10 | + |
|
| 11 | + No additional restrictions - You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. |
|
| 12 | + |
|
| 13 | +Notices: |
|
| 14 | + |
|
| 15 | + You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. |
|
| 16 | + No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/gpl_20_full.txt
| ... | ... | @@ -0,0 +1,475 @@ |
| 1 | +<h3><a id="SEC1">GNU GENERAL PUBLIC LICENSE</a></h3> |
|
| 2 | +<p> |
|
| 3 | +Version 2, June 1991 |
|
| 4 | +</p> |
|
| 5 | + |
|
| 6 | +<pre> |
|
| 7 | +Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
|
| 8 | +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|
| 9 | + |
|
| 10 | +Everyone is permitted to copy and distribute verbatim copies |
|
| 11 | +of this license document, but changing it is not allowed. |
|
| 12 | +</pre> |
|
| 13 | + |
|
| 14 | +<h3><a id="preamble"></a><a id="SEC2">Preamble</a></h3> |
|
| 15 | + |
|
| 16 | +<p> |
|
| 17 | + The licenses for most software are designed to take away your |
|
| 18 | +freedom to share and change it. By contrast, the GNU General Public |
|
| 19 | +License is intended to guarantee your freedom to share and change free |
|
| 20 | +software--to make sure the software is free for all its users. This |
|
| 21 | +General Public License applies to most of the Free Software |
|
| 22 | +Foundation's software and to any other program whose authors commit to |
|
| 23 | +using it. (Some other Free Software Foundation software is covered by |
|
| 24 | +the GNU Lesser General Public License instead.) You can apply it to |
|
| 25 | +your programs, too. |
|
| 26 | +</p> |
|
| 27 | + |
|
| 28 | +<p> |
|
| 29 | + When we speak of free software, we are referring to freedom, not |
|
| 30 | +price. Our General Public Licenses are designed to make sure that you |
|
| 31 | +have the freedom to distribute copies of free software (and charge for |
|
| 32 | +this service if you wish), that you receive source code or can get it |
|
| 33 | +if you want it, that you can change the software or use pieces of it |
|
| 34 | +in new free programs; and that you know you can do these things. |
|
| 35 | +</p> |
|
| 36 | + |
|
| 37 | +<p> |
|
| 38 | + To protect your rights, we need to make restrictions that forbid |
|
| 39 | +anyone to deny you these rights or to ask you to surrender the rights. |
|
| 40 | +These restrictions translate to certain responsibilities for you if you |
|
| 41 | +distribute copies of the software, or if you modify it. |
|
| 42 | +</p> |
|
| 43 | + |
|
| 44 | +<p> |
|
| 45 | + For example, if you distribute copies of such a program, whether |
|
| 46 | +gratis or for a fee, you must give the recipients all the rights that |
|
| 47 | +you have. You must make sure that they, too, receive or can get the |
|
| 48 | +source code. And you must show them these terms so they know their |
|
| 49 | +rights. |
|
| 50 | +</p> |
|
| 51 | + |
|
| 52 | +<p> |
|
| 53 | + We protect your rights with two steps: (1) copyright the software, and |
|
| 54 | +(2) offer you this license which gives you legal permission to copy, |
|
| 55 | +distribute and/or modify the software. |
|
| 56 | +</p> |
|
| 57 | + |
|
| 58 | +<p> |
|
| 59 | + Also, for each author's protection and ours, we want to make certain |
|
| 60 | +that everyone understands that there is no warranty for this free |
|
| 61 | +software. If the software is modified by someone else and passed on, we |
|
| 62 | +want its recipients to know that what they have is not the original, so |
|
| 63 | +that any problems introduced by others will not reflect on the original |
|
| 64 | +authors' reputations. |
|
| 65 | +</p> |
|
| 66 | + |
|
| 67 | +<p> |
|
| 68 | + Finally, any free program is threatened constantly by software |
|
| 69 | +patents. We wish to avoid the danger that redistributors of a free |
|
| 70 | +program will individually obtain patent licenses, in effect making the |
|
| 71 | +program proprietary. To prevent this, we have made it clear that any |
|
| 72 | +patent must be licensed for everyone's free use or not licensed at all. |
|
| 73 | +</p> |
|
| 74 | + |
|
| 75 | +<p> |
|
| 76 | + The precise terms and conditions for copying, distribution and |
|
| 77 | +modification follow. |
|
| 78 | +</p> |
|
| 79 | + |
|
| 80 | + |
|
| 81 | +<h3><a id="terms"></a><a id="SEC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</a></h3> |
|
| 82 | + |
|
| 83 | + |
|
| 84 | +<a id="section0"></a><p> |
|
| 85 | +<strong>0.</strong> |
|
| 86 | + This License applies to any program or other work which contains |
|
| 87 | +a notice placed by the copyright holder saying it may be distributed |
|
| 88 | +under the terms of this General Public License. The "Program", below, |
|
| 89 | +refers to any such program or work, and a "work based on the Program" |
|
| 90 | +means either the Program or any derivative work under copyright law: |
|
| 91 | +that is to say, a work containing the Program or a portion of it, |
|
| 92 | +either verbatim or with modifications and/or translated into another |
|
| 93 | +language. (Hereinafter, translation is included without limitation in |
|
| 94 | +the term "modification".) Each licensee is addressed as "you". |
|
| 95 | +</p> |
|
| 96 | + |
|
| 97 | +<p> |
|
| 98 | +Activities other than copying, distribution and modification are not |
|
| 99 | +covered by this License; they are outside its scope. The act of |
|
| 100 | +running the Program is not restricted, and the output from the Program |
|
| 101 | +is covered only if its contents constitute a work based on the |
|
| 102 | +Program (independent of having been made by running the Program). |
|
| 103 | +Whether that is true depends on what the Program does. |
|
| 104 | +</p> |
|
| 105 | + |
|
| 106 | +<a id="section1"></a><p> |
|
| 107 | +<strong>1.</strong> |
|
| 108 | + You may copy and distribute verbatim copies of the Program's |
|
| 109 | +source code as you receive it, in any medium, provided that you |
|
| 110 | +conspicuously and appropriately publish on each copy an appropriate |
|
| 111 | +copyright notice and disclaimer of warranty; keep intact all the |
|
| 112 | +notices that refer to this License and to the absence of any warranty; |
|
| 113 | +and give any other recipients of the Program a copy of this License |
|
| 114 | +along with the Program. |
|
| 115 | +</p> |
|
| 116 | + |
|
| 117 | +<p> |
|
| 118 | +You may charge a fee for the physical act of transferring a copy, and |
|
| 119 | +you may at your option offer warranty protection in exchange for a fee. |
|
| 120 | +</p> |
|
| 121 | + |
|
| 122 | +<a id="section2"></a><p> |
|
| 123 | +<strong>2.</strong> |
|
| 124 | + You may modify your copy or copies of the Program or any portion |
|
| 125 | +of it, thus forming a work based on the Program, and copy and |
|
| 126 | +distribute such modifications or work under the terms of Section 1 |
|
| 127 | +above, provided that you also meet all of these conditions: |
|
| 128 | +</p> |
|
| 129 | + |
|
| 130 | +<dl> |
|
| 131 | + <dt></dt> |
|
| 132 | + <dd> |
|
| 133 | + <strong>a)</strong> |
|
| 134 | + You must cause the modified files to carry prominent notices |
|
| 135 | + stating that you changed the files and the date of any change. |
|
| 136 | + </dd> |
|
| 137 | + <dt></dt> |
|
| 138 | + <dd> |
|
| 139 | + <strong>b)</strong> |
|
| 140 | + You must cause any work that you distribute or publish, that in |
|
| 141 | + whole or in part contains or is derived from the Program or any |
|
| 142 | + part thereof, to be licensed as a whole at no charge to all third |
|
| 143 | + parties under the terms of this License. |
|
| 144 | + </dd> |
|
| 145 | + <dt></dt> |
|
| 146 | + <dd> |
|
| 147 | + <strong>c)</strong> |
|
| 148 | + If the modified program normally reads commands interactively |
|
| 149 | + when run, you must cause it, when started running for such |
|
| 150 | + interactive use in the most ordinary way, to print or display an |
|
| 151 | + announcement including an appropriate copyright notice and a |
|
| 152 | + notice that there is no warranty (or else, saying that you provide |
|
| 153 | + a warranty) and that users may redistribute the program under |
|
| 154 | + these conditions, and telling the user how to view a copy of this |
|
| 155 | + License. (Exception: if the Program itself is interactive but |
|
| 156 | + does not normally print such an announcement, your work based on |
|
| 157 | + the Program is not required to print an announcement.) |
|
| 158 | + </dd> |
|
| 159 | +</dl> |
|
| 160 | + |
|
| 161 | +<p> |
|
| 162 | +These requirements apply to the modified work as a whole. If |
|
| 163 | +identifiable sections of that work are not derived from the Program, |
|
| 164 | +and can be reasonably considered independent and separate works in |
|
| 165 | +themselves, then this License, and its terms, do not apply to those |
|
| 166 | +sections when you distribute them as separate works. But when you |
|
| 167 | +distribute the same sections as part of a whole which is a work based |
|
| 168 | +on the Program, the distribution of the whole must be on the terms of |
|
| 169 | +this License, whose permissions for other licensees extend to the |
|
| 170 | +entire whole, and thus to each and every part regardless of who wrote it. |
|
| 171 | +</p> |
|
| 172 | + |
|
| 173 | +<p> |
|
| 174 | +Thus, it is not the intent of this section to claim rights or contest |
|
| 175 | +your rights to work written entirely by you; rather, the intent is to |
|
| 176 | +exercise the right to control the distribution of derivative or |
|
| 177 | +collective works based on the Program. |
|
| 178 | +</p> |
|
| 179 | + |
|
| 180 | +<p> |
|
| 181 | +In addition, mere aggregation of another work not based on the Program |
|
| 182 | +with the Program (or with a work based on the Program) on a volume of |
|
| 183 | +a storage or distribution medium does not bring the other work under |
|
| 184 | +the scope of this License. |
|
| 185 | +</p> |
|
| 186 | + |
|
| 187 | +<a id="section3"></a><p> |
|
| 188 | +<strong>3.</strong> |
|
| 189 | + You may copy and distribute the Program (or a work based on it, |
|
| 190 | +under Section 2) in object code or executable form under the terms of |
|
| 191 | +Sections 1 and 2 above provided that you also do one of the following: |
|
| 192 | +</p> |
|
| 193 | + |
|
| 194 | +<!-- we use this doubled UL to get the sub-sections indented, --> |
|
| 195 | +<!-- while making the bullets as unobvious as possible. --> |
|
| 196 | + |
|
| 197 | +<dl> |
|
| 198 | + <dt></dt> |
|
| 199 | + <dd> |
|
| 200 | + <strong>a)</strong> |
|
| 201 | + Accompany it with the complete corresponding machine-readable |
|
| 202 | + source code, which must be distributed under the terms of Sections |
|
| 203 | + 1 and 2 above on a medium customarily used for software interchange; or, |
|
| 204 | + </dd> |
|
| 205 | + <dt></dt> |
|
| 206 | + <dd> |
|
| 207 | + <strong>b)</strong> |
|
| 208 | + Accompany it with a written offer, valid for at least three |
|
| 209 | + years, to give any third party, for a charge no more than your |
|
| 210 | + cost of physically performing source distribution, a complete |
|
| 211 | + machine-readable copy of the corresponding source code, to be |
|
| 212 | + distributed under the terms of Sections 1 and 2 above on a medium |
|
| 213 | + customarily used for software interchange; or, |
|
| 214 | + </dd> |
|
| 215 | + <dt></dt> |
|
| 216 | + <dd> |
|
| 217 | + <strong>c)</strong> |
|
| 218 | + Accompany it with the information you received as to the offer |
|
| 219 | + to distribute corresponding source code. (This alternative is |
|
| 220 | + allowed only for noncommercial distribution and only if you |
|
| 221 | + received the program in object code or executable form with such |
|
| 222 | + an offer, in accord with Subsection b above.) |
|
| 223 | + </dd> |
|
| 224 | +</dl> |
|
| 225 | + |
|
| 226 | +<p> |
|
| 227 | +The source code for a work means the preferred form of the work for |
|
| 228 | +making modifications to it. For an executable work, complete source |
|
| 229 | +code means all the source code for all modules it contains, plus any |
|
| 230 | +associated interface definition files, plus the scripts used to |
|
| 231 | +control compilation and installation of the executable. However, as a |
|
| 232 | +special exception, the source code distributed need not include |
|
| 233 | +anything that is normally distributed (in either source or binary |
|
| 234 | +form) with the major components (compiler, kernel, and so on) of the |
|
| 235 | +operating system on which the executable runs, unless that component |
|
| 236 | +itself accompanies the executable. |
|
| 237 | +</p> |
|
| 238 | + |
|
| 239 | +<p> |
|
| 240 | +If distribution of executable or object code is made by offering |
|
| 241 | +access to copy from a designated place, then offering equivalent |
|
| 242 | +access to copy the source code from the same place counts as |
|
| 243 | +distribution of the source code, even though third parties are not |
|
| 244 | +compelled to copy the source along with the object code. |
|
| 245 | +</p> |
|
| 246 | + |
|
| 247 | +<a id="section4"></a><p> |
|
| 248 | +<strong>4.</strong> |
|
| 249 | + You may not copy, modify, sublicense, or distribute the Program |
|
| 250 | +except as expressly provided under this License. Any attempt |
|
| 251 | +otherwise to copy, modify, sublicense or distribute the Program is |
|
| 252 | +void, and will automatically terminate your rights under this License. |
|
| 253 | +However, parties who have received copies, or rights, from you under |
|
| 254 | +this License will not have their licenses terminated so long as such |
|
| 255 | +parties remain in full compliance. |
|
| 256 | +</p> |
|
| 257 | + |
|
| 258 | +<a id="section5"></a><p> |
|
| 259 | +<strong>5.</strong> |
|
| 260 | + You are not required to accept this License, since you have not |
|
| 261 | +signed it. However, nothing else grants you permission to modify or |
|
| 262 | +distribute the Program or its derivative works. These actions are |
|
| 263 | +prohibited by law if you do not accept this License. Therefore, by |
|
| 264 | +modifying or distributing the Program (or any work based on the |
|
| 265 | +Program), you indicate your acceptance of this License to do so, and |
|
| 266 | +all its terms and conditions for copying, distributing or modifying |
|
| 267 | +the Program or works based on it. |
|
| 268 | +</p> |
|
| 269 | + |
|
| 270 | +<a id="section6"></a><p> |
|
| 271 | +<strong>6.</strong> |
|
| 272 | + Each time you redistribute the Program (or any work based on the |
|
| 273 | +Program), the recipient automatically receives a license from the |
|
| 274 | +original licensor to copy, distribute or modify the Program subject to |
|
| 275 | +these terms and conditions. You may not impose any further |
|
| 276 | +restrictions on the recipients' exercise of the rights granted herein. |
|
| 277 | +You are not responsible for enforcing compliance by third parties to |
|
| 278 | +this License. |
|
| 279 | +</p> |
|
| 280 | + |
|
| 281 | +<a id="section7"></a><p> |
|
| 282 | +<strong>7.</strong> |
|
| 283 | + If, as a consequence of a court judgment or allegation of patent |
|
| 284 | +infringement or for any other reason (not limited to patent issues), |
|
| 285 | +conditions are imposed on you (whether by court order, agreement or |
|
| 286 | +otherwise) that contradict the conditions of this License, they do not |
|
| 287 | +excuse you from the conditions of this License. If you cannot |
|
| 288 | +distribute so as to satisfy simultaneously your obligations under this |
|
| 289 | +License and any other pertinent obligations, then as a consequence you |
|
| 290 | +may not distribute the Program at all. For example, if a patent |
|
| 291 | +license would not permit royalty-free redistribution of the Program by |
|
| 292 | +all those who receive copies directly or indirectly through you, then |
|
| 293 | +the only way you could satisfy both it and this License would be to |
|
| 294 | +refrain entirely from distribution of the Program. |
|
| 295 | +</p> |
|
| 296 | + |
|
| 297 | +<p> |
|
| 298 | +If any portion of this section is held invalid or unenforceable under |
|
| 299 | +any particular circumstance, the balance of the section is intended to |
|
| 300 | +apply and the section as a whole is intended to apply in other |
|
| 301 | +circumstances. |
|
| 302 | +</p> |
|
| 303 | + |
|
| 304 | +<p> |
|
| 305 | +It is not the purpose of this section to induce you to infringe any |
|
| 306 | +patents or other property right claims or to contest validity of any |
|
| 307 | +such claims; this section has the sole purpose of protecting the |
|
| 308 | +integrity of the free software distribution system, which is |
|
| 309 | +implemented by public license practices. Many people have made |
|
| 310 | +generous contributions to the wide range of software distributed |
|
| 311 | +through that system in reliance on consistent application of that |
|
| 312 | +system; it is up to the author/donor to decide if he or she is willing |
|
| 313 | +to distribute software through any other system and a licensee cannot |
|
| 314 | +impose that choice. |
|
| 315 | +</p> |
|
| 316 | + |
|
| 317 | +<p> |
|
| 318 | +This section is intended to make thoroughly clear what is believed to |
|
| 319 | +be a consequence of the rest of this License. |
|
| 320 | +</p> |
|
| 321 | + |
|
| 322 | +<a id="section8"></a><p> |
|
| 323 | +<strong>8.</strong> |
|
| 324 | + If the distribution and/or use of the Program is restricted in |
|
| 325 | +certain countries either by patents or by copyrighted interfaces, the |
|
| 326 | +original copyright holder who places the Program under this License |
|
| 327 | +may add an explicit geographical distribution limitation excluding |
|
| 328 | +those countries, so that distribution is permitted only in or among |
|
| 329 | +countries not thus excluded. In such case, this License incorporates |
|
| 330 | +the limitation as if written in the body of this License. |
|
| 331 | +</p> |
|
| 332 | + |
|
| 333 | +<a id="section9"></a><p> |
|
| 334 | +<strong>9.</strong> |
|
| 335 | + The Free Software Foundation may publish revised and/or new versions |
|
| 336 | +of the General Public License from time to time. Such new versions will |
|
| 337 | +be similar in spirit to the present version, but may differ in detail to |
|
| 338 | +address new problems or concerns. |
|
| 339 | +</p> |
|
| 340 | + |
|
| 341 | +<p> |
|
| 342 | +Each version is given a distinguishing version number. If the Program |
|
| 343 | +specifies a version number of this License which applies to it and "any |
|
| 344 | +later version", you have the option of following the terms and conditions |
|
| 345 | +either of that version or of any later version published by the Free |
|
| 346 | +Software Foundation. If the Program does not specify a version number of |
|
| 347 | +this License, you may choose any version ever published by the Free Software |
|
| 348 | +Foundation. |
|
| 349 | +</p> |
|
| 350 | + |
|
| 351 | +<a id="section10"></a><p> |
|
| 352 | +<strong>10.</strong> |
|
| 353 | + If you wish to incorporate parts of the Program into other free |
|
| 354 | +programs whose distribution conditions are different, write to the author |
|
| 355 | +to ask for permission. For software which is copyrighted by the Free |
|
| 356 | +Software Foundation, write to the Free Software Foundation; we sometimes |
|
| 357 | +make exceptions for this. Our decision will be guided by the two goals |
|
| 358 | +of preserving the free status of all derivatives of our free software and |
|
| 359 | +of promoting the sharing and reuse of software generally. |
|
| 360 | +</p> |
|
| 361 | + |
|
| 362 | +<a id="section11"></a><p><strong>NO WARRANTY</strong></p> |
|
| 363 | + |
|
| 364 | +<p> |
|
| 365 | +<strong>11.</strong> |
|
| 366 | + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
|
| 367 | +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
|
| 368 | +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
|
| 369 | +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
|
| 370 | +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
| 371 | +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
|
| 372 | +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
|
| 373 | +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
|
| 374 | +REPAIR OR CORRECTION. |
|
| 375 | +</p> |
|
| 376 | + |
|
| 377 | +<a id="section12"></a><p> |
|
| 378 | +<strong>12.</strong> |
|
| 379 | + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|
| 380 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
|
| 381 | +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
|
| 382 | +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
|
| 383 | +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
|
| 384 | +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
|
| 385 | +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
|
| 386 | +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
|
| 387 | +POSSIBILITY OF SUCH DAMAGES. |
|
| 388 | +</p> |
|
| 389 | + |
|
| 390 | +<h3>END OF TERMS AND CONDITIONS</h3> |
|
| 391 | + |
|
| 392 | +<h3><a id="howto"></a><a id="SEC4">How to Apply These Terms to Your New Programs</a></h3> |
|
| 393 | + |
|
| 394 | +<p> |
|
| 395 | + If you develop a new program, and you want it to be of the greatest |
|
| 396 | +possible use to the public, the best way to achieve this is to make it |
|
| 397 | +free software which everyone can redistribute and change under these terms. |
|
| 398 | +</p> |
|
| 399 | + |
|
| 400 | +<p> |
|
| 401 | + To do so, attach the following notices to the program. It is safest |
|
| 402 | +to attach them to the start of each source file to most effectively |
|
| 403 | +convey the exclusion of warranty; and each file should have at least |
|
| 404 | +the "copyright" line and a pointer to where the full notice is found. |
|
| 405 | +</p> |
|
| 406 | + |
|
| 407 | +<pre> |
|
| 408 | +<var>one line to give the program's name and an idea of what it does.</var> |
|
| 409 | +Copyright (C) <var>yyyy</var> <var>name of author</var> |
|
| 410 | + |
|
| 411 | +This program is free software; you can redistribute it and/or |
|
| 412 | +modify it under the terms of the GNU General Public License |
|
| 413 | +as published by the Free Software Foundation; either version 2 |
|
| 414 | +of the License, or (at your option) any later version. |
|
| 415 | + |
|
| 416 | +This program is distributed in the hope that it will be useful, |
|
| 417 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 418 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 419 | +GNU General Public License for more details. |
|
| 420 | + |
|
| 421 | +You should have received a copy of the GNU General Public License |
|
| 422 | +along with this program; if not, write to the Free Software |
|
| 423 | +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 424 | +</pre> |
|
| 425 | + |
|
| 426 | +<p> |
|
| 427 | +Also add information on how to contact you by electronic and paper mail. |
|
| 428 | +</p> |
|
| 429 | + |
|
| 430 | +<p> |
|
| 431 | +If the program is interactive, make it output a short notice like this |
|
| 432 | +when it starts in an interactive mode: |
|
| 433 | +</p> |
|
| 434 | + |
|
| 435 | +<pre> |
|
| 436 | +Gnomovision version 69, Copyright (C) <var>year</var> <var>name of author</var> |
|
| 437 | +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details |
|
| 438 | +type `show w'. This is free software, and you are welcome |
|
| 439 | +to redistribute it under certain conditions; type `show c' |
|
| 440 | +for details. |
|
| 441 | +</pre> |
|
| 442 | + |
|
| 443 | +<p> |
|
| 444 | +The hypothetical commands <samp>`show w'</samp> and <samp>`show c'</samp> should show |
|
| 445 | +the appropriate parts of the General Public License. Of course, the |
|
| 446 | +commands you use may be called something other than <samp>`show w'</samp> and |
|
| 447 | +<samp>`show c'</samp>; they could even be mouse-clicks or menu items--whatever |
|
| 448 | +suits your program. |
|
| 449 | +</p> |
|
| 450 | + |
|
| 451 | +<p> |
|
| 452 | +You should also get your employer (if you work as a programmer) or your |
|
| 453 | +school, if any, to sign a "copyright disclaimer" for the program, if |
|
| 454 | +necessary. Here is a sample; alter the names: |
|
| 455 | +</p> |
|
| 456 | + |
|
| 457 | + |
|
| 458 | +<pre> |
|
| 459 | +Yoyodyne, Inc., hereby disclaims all copyright |
|
| 460 | +interest in the program `Gnomovision' |
|
| 461 | +(which makes passes at compilers) written |
|
| 462 | +by James Hacker. |
|
| 463 | + |
|
| 464 | +<var>signature of Ty Coon</var>, 1 April 1989 |
|
| 465 | +Ty Coon, President of Vice |
|
| 466 | +</pre> |
|
| 467 | + |
|
| 468 | +<p> |
|
| 469 | +This General Public License does not permit incorporating your program into |
|
| 470 | +proprietary programs. If your program is a subroutine library, you may |
|
| 471 | +consider it more useful to permit linking proprietary applications with the |
|
| 472 | +library. If this is what you want to do, use the |
|
| 473 | +<a href="http://www.gnu.org/licenses/lgpl.html">GNU Lesser General Public License</a> |
|
| 474 | +instead of this License. |
|
| 475 | +</p> |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/gpl_20_summary.txt
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +This program is free software; you can redistribute it and/or |
|
| 2 | +modify it under the terms of the GNU General Public License |
|
| 3 | +as published by the Free Software Foundation; either version 2 |
|
| 4 | +of the License, or (at your option) any later version. |
|
| 5 | + |
|
| 6 | +This program is distributed in the hope that it will be useful, |
|
| 7 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 8 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 9 | +GNU General Public License for more details. |
|
| 10 | + |
|
| 11 | +You should have received a copy of the GNU General Public License |
|
| 12 | +along with this program; if not, write to the Free Software |
|
| 13 | +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 14 | + |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/gpl_30_full.txt
| ... | ... | @@ -0,0 +1,683 @@ |
| 1 | +<h3 style="text-align: center;">GNU GENERAL PUBLIC LICENSE</h3> |
|
| 2 | +<p style="text-align: center;">Version 3, 29 June 2007</p> |
|
| 3 | + |
|
| 4 | +<p>Copyright © 2007 Free Software Foundation, Inc. |
|
| 5 | + <<a href="http://fsf.org/">http://fsf.org/</a>></p><p> |
|
| 6 | + Everyone is permitted to copy and distribute verbatim copies |
|
| 7 | + of this license document, but changing it is not allowed.</p> |
|
| 8 | + |
|
| 9 | +<h3><a name="preamble"></a>Preamble</h3> |
|
| 10 | + |
|
| 11 | +<p>The GNU General Public License is a free, copyleft license for |
|
| 12 | +software and other kinds of works.</p> |
|
| 13 | + |
|
| 14 | +<p>The licenses for most software and other practical works are designed |
|
| 15 | +to take away your freedom to share and change the works. By contrast, |
|
| 16 | +the GNU General Public License is intended to guarantee your freedom to |
|
| 17 | +share and change all versions of a program--to make sure it remains free |
|
| 18 | +software for all its users. We, the Free Software Foundation, use the |
|
| 19 | +GNU General Public License for most of our software; it applies also to |
|
| 20 | +any other work released this way by its authors. You can apply it to |
|
| 21 | +your programs, too.</p> |
|
| 22 | + |
|
| 23 | +<p>When we speak of free software, we are referring to freedom, not |
|
| 24 | +price. Our General Public Licenses are designed to make sure that you |
|
| 25 | +have the freedom to distribute copies of free software (and charge for |
|
| 26 | +them if you wish), that you receive source code or can get it if you |
|
| 27 | +want it, that you can change the software or use pieces of it in new |
|
| 28 | +free programs, and that you know you can do these things.</p> |
|
| 29 | + |
|
| 30 | +<p>To protect your rights, we need to prevent others from denying you |
|
| 31 | +these rights or asking you to surrender the rights. Therefore, you have |
|
| 32 | +certain responsibilities if you distribute copies of the software, or if |
|
| 33 | +you modify it: responsibilities to respect the freedom of others.</p> |
|
| 34 | + |
|
| 35 | +<p>For example, if you distribute copies of such a program, whether |
|
| 36 | +gratis or for a fee, you must pass on to the recipients the same |
|
| 37 | +freedoms that you received. You must make sure that they, too, receive |
|
| 38 | +or can get the source code. And you must show them these terms so they |
|
| 39 | +know their rights.</p> |
|
| 40 | + |
|
| 41 | +<p>Developers that use the GNU GPL protect your rights with two steps: |
|
| 42 | +(1) assert copyright on the software, and (2) offer you this License |
|
| 43 | +giving you legal permission to copy, distribute and/or modify it.</p> |
|
| 44 | + |
|
| 45 | +<p>For the developers' and authors' protection, the GPL clearly explains |
|
| 46 | +that there is no warranty for this free software. For both users' and |
|
| 47 | +authors' sake, the GPL requires that modified versions be marked as |
|
| 48 | +changed, so that their problems will not be attributed erroneously to |
|
| 49 | +authors of previous versions.</p> |
|
| 50 | + |
|
| 51 | +<p>Some devices are designed to deny users access to install or run |
|
| 52 | +modified versions of the software inside them, although the manufacturer |
|
| 53 | +can do so. This is fundamentally incompatible with the aim of |
|
| 54 | +protecting users' freedom to change the software. The systematic |
|
| 55 | +pattern of such abuse occurs in the area of products for individuals to |
|
| 56 | +use, which is precisely where it is most unacceptable. Therefore, we |
|
| 57 | +have designed this version of the GPL to prohibit the practice for those |
|
| 58 | +products. If such problems arise substantially in other domains, we |
|
| 59 | +stand ready to extend this provision to those domains in future versions |
|
| 60 | +of the GPL, as needed to protect the freedom of users.</p> |
|
| 61 | + |
|
| 62 | +<p>Finally, every program is threatened constantly by software patents. |
|
| 63 | +States should not allow patents to restrict development and use of |
|
| 64 | +software on general-purpose computers, but in those that do, we wish to |
|
| 65 | +avoid the special danger that patents applied to a free program could |
|
| 66 | +make it effectively proprietary. To prevent this, the GPL assures that |
|
| 67 | +patents cannot be used to render the program non-free.</p> |
|
| 68 | + |
|
| 69 | +<p>The precise terms and conditions for copying, distribution and |
|
| 70 | +modification follow.</p> |
|
| 71 | + |
|
| 72 | +<h3><a name="terms"></a>TERMS AND CONDITIONS</h3> |
|
| 73 | + |
|
| 74 | +<h4><a name="section0"></a>0. Definitions.</h4> |
|
| 75 | + |
|
| 76 | +<p>“This License” refers to version 3 of the GNU General Public License.</p> |
|
| 77 | + |
|
| 78 | +<p>“Copyright” also means copyright-like laws that apply to other kinds of |
|
| 79 | +works, such as semiconductor masks.</p> |
|
| 80 | + |
|
| 81 | +<p>“The Program” refers to any copyrightable work licensed under this |
|
| 82 | +License. Each licensee is addressed as “you”. “Licensees” and |
|
| 83 | +“recipients” may be individuals or organizations.</p> |
|
| 84 | + |
|
| 85 | +<p>To “modify” a work means to copy from or adapt all or part of the work |
|
| 86 | +in a fashion requiring copyright permission, other than the making of an |
|
| 87 | +exact copy. The resulting work is called a “modified version” of the |
|
| 88 | +earlier work or a work “based on” the earlier work.</p> |
|
| 89 | + |
|
| 90 | +<p>A “covered work” means either the unmodified Program or a work based |
|
| 91 | +on the Program.</p> |
|
| 92 | + |
|
| 93 | +<p>To “propagate” a work means to do anything with it that, without |
|
| 94 | +permission, would make you directly or secondarily liable for |
|
| 95 | +infringement under applicable copyright law, except executing it on a |
|
| 96 | +computer or modifying a private copy. Propagation includes copying, |
|
| 97 | +distribution (with or without modification), making available to the |
|
| 98 | +public, and in some countries other activities as well.</p> |
|
| 99 | + |
|
| 100 | +<p>To “convey” a work means any kind of propagation that enables other |
|
| 101 | +parties to make or receive copies. Mere interaction with a user through |
|
| 102 | +a computer network, with no transfer of a copy, is not conveying.</p> |
|
| 103 | + |
|
| 104 | +<p>An interactive user interface displays “Appropriate Legal Notices” |
|
| 105 | +to the extent that it includes a convenient and prominently visible |
|
| 106 | +feature that (1) displays an appropriate copyright notice, and (2) |
|
| 107 | +tells the user that there is no warranty for the work (except to the |
|
| 108 | +extent that warranties are provided), that licensees may convey the |
|
| 109 | +work under this License, and how to view a copy of this License. If |
|
| 110 | +the interface presents a list of user commands or options, such as a |
|
| 111 | +menu, a prominent item in the list meets this criterion.</p> |
|
| 112 | + |
|
| 113 | +<h4><a name="section1"></a>1. Source Code.</h4> |
|
| 114 | + |
|
| 115 | +<p>The “source code” for a work means the preferred form of the work |
|
| 116 | +for making modifications to it. “Object code” means any non-source |
|
| 117 | +form of a work.</p> |
|
| 118 | + |
|
| 119 | +<p>A “Standard Interface” means an interface that either is an official |
|
| 120 | +standard defined by a recognized standards body, or, in the case of |
|
| 121 | +interfaces specified for a particular programming language, one that |
|
| 122 | +is widely used among developers working in that language.</p> |
|
| 123 | + |
|
| 124 | +<p>The “System Libraries” of an executable work include anything, other |
|
| 125 | +than the work as a whole, that (a) is included in the normal form of |
|
| 126 | +packaging a Major Component, but which is not part of that Major |
|
| 127 | +Component, and (b) serves only to enable use of the work with that |
|
| 128 | +Major Component, or to implement a Standard Interface for which an |
|
| 129 | +implementation is available to the public in source code form. A |
|
| 130 | +“Major Component”, in this context, means a major essential component |
|
| 131 | +(kernel, window system, and so on) of the specific operating system |
|
| 132 | +(if any) on which the executable work runs, or a compiler used to |
|
| 133 | +produce the work, or an object code interpreter used to run it.</p> |
|
| 134 | + |
|
| 135 | +<p>The “Corresponding Source” for a work in object code form means all |
|
| 136 | +the source code needed to generate, install, and (for an executable |
|
| 137 | +work) run the object code and to modify the work, including scripts to |
|
| 138 | +control those activities. However, it does not include the work's |
|
| 139 | +System Libraries, or general-purpose tools or generally available free |
|
| 140 | +programs which are used unmodified in performing those activities but |
|
| 141 | +which are not part of the work. For example, Corresponding Source |
|
| 142 | +includes interface definition files associated with source files for |
|
| 143 | +the work, and the source code for shared libraries and dynamically |
|
| 144 | +linked subprograms that the work is specifically designed to require, |
|
| 145 | +such as by intimate data communication or control flow between those |
|
| 146 | +subprograms and other parts of the work.</p> |
|
| 147 | + |
|
| 148 | +<p>The Corresponding Source need not include anything that users |
|
| 149 | +can regenerate automatically from other parts of the Corresponding |
|
| 150 | +Source.</p> |
|
| 151 | + |
|
| 152 | +<p>The Corresponding Source for a work in source code form is that |
|
| 153 | +same work.</p> |
|
| 154 | + |
|
| 155 | +<h4><a name="section2"></a>2. Basic Permissions.</h4> |
|
| 156 | + |
|
| 157 | +<p>All rights granted under this License are granted for the term of |
|
| 158 | +copyright on the Program, and are irrevocable provided the stated |
|
| 159 | +conditions are met. This License explicitly affirms your unlimited |
|
| 160 | +permission to run the unmodified Program. The output from running a |
|
| 161 | +covered work is covered by this License only if the output, given its |
|
| 162 | +content, constitutes a covered work. This License acknowledges your |
|
| 163 | +rights of fair use or other equivalent, as provided by copyright law.</p> |
|
| 164 | + |
|
| 165 | +<p>You may make, run and propagate covered works that you do not |
|
| 166 | +convey, without conditions so long as your license otherwise remains |
|
| 167 | +in force. You may convey covered works to others for the sole purpose |
|
| 168 | +of having them make modifications exclusively for you, or provide you |
|
| 169 | +with facilities for running those works, provided that you comply with |
|
| 170 | +the terms of this License in conveying all material for which you do |
|
| 171 | +not control copyright. Those thus making or running the covered works |
|
| 172 | +for you must do so exclusively on your behalf, under your direction |
|
| 173 | +and control, on terms that prohibit them from making any copies of |
|
| 174 | +your copyrighted material outside their relationship with you.</p> |
|
| 175 | + |
|
| 176 | +<p>Conveying under any other circumstances is permitted solely under |
|
| 177 | +the conditions stated below. Sublicensing is not allowed; section 10 |
|
| 178 | +makes it unnecessary.</p> |
|
| 179 | + |
|
| 180 | +<h4><a name="section3"></a>3. Protecting Users' Legal Rights From Anti-Circumvention Law.</h4> |
|
| 181 | + |
|
| 182 | +<p>No covered work shall be deemed part of an effective technological |
|
| 183 | +measure under any applicable law fulfilling obligations under article |
|
| 184 | +11 of the WIPO copyright treaty adopted on 20 December 1996, or |
|
| 185 | +similar laws prohibiting or restricting circumvention of such |
|
| 186 | +measures.</p> |
|
| 187 | + |
|
| 188 | +<p>When you convey a covered work, you waive any legal power to forbid |
|
| 189 | +circumvention of technological measures to the extent such circumvention |
|
| 190 | +is effected by exercising rights under this License with respect to |
|
| 191 | +the covered work, and you disclaim any intention to limit operation or |
|
| 192 | +modification of the work as a means of enforcing, against the work's |
|
| 193 | +users, your or third parties' legal rights to forbid circumvention of |
|
| 194 | +technological measures.</p> |
|
| 195 | + |
|
| 196 | +<h4><a name="section4"></a>4. Conveying Verbatim Copies.</h4> |
|
| 197 | + |
|
| 198 | +<p>You may convey verbatim copies of the Program's source code as you |
|
| 199 | +receive it, in any medium, provided that you conspicuously and |
|
| 200 | +appropriately publish on each copy an appropriate copyright notice; |
|
| 201 | +keep intact all notices stating that this License and any |
|
| 202 | +non-permissive terms added in accord with section 7 apply to the code; |
|
| 203 | +keep intact all notices of the absence of any warranty; and give all |
|
| 204 | +recipients a copy of this License along with the Program.</p> |
|
| 205 | + |
|
| 206 | +<p>You may charge any price or no price for each copy that you convey, |
|
| 207 | +and you may offer support or warranty protection for a fee.</p> |
|
| 208 | + |
|
| 209 | +<h4><a name="section5"></a>5. Conveying Modified Source Versions.</h4> |
|
| 210 | + |
|
| 211 | +<p>You may convey a work based on the Program, or the modifications to |
|
| 212 | +produce it from the Program, in the form of source code under the |
|
| 213 | +terms of section 4, provided that you also meet all of these conditions:</p> |
|
| 214 | + |
|
| 215 | +<ul> |
|
| 216 | +<li>a) The work must carry prominent notices stating that you modified |
|
| 217 | + it, and giving a relevant date.</li> |
|
| 218 | + |
|
| 219 | +<li>b) The work must carry prominent notices stating that it is |
|
| 220 | + released under this License and any conditions added under section |
|
| 221 | + 7. This requirement modifies the requirement in section 4 to |
|
| 222 | + “keep intact all notices”.</li> |
|
| 223 | + |
|
| 224 | +<li>c) You must license the entire work, as a whole, under this |
|
| 225 | + License to anyone who comes into possession of a copy. This |
|
| 226 | + License will therefore apply, along with any applicable section 7 |
|
| 227 | + additional terms, to the whole of the work, and all its parts, |
|
| 228 | + regardless of how they are packaged. This License gives no |
|
| 229 | + permission to license the work in any other way, but it does not |
|
| 230 | + invalidate such permission if you have separately received it.</li> |
|
| 231 | + |
|
| 232 | +<li>d) If the work has interactive user interfaces, each must display |
|
| 233 | + Appropriate Legal Notices; however, if the Program has interactive |
|
| 234 | + interfaces that do not display Appropriate Legal Notices, your |
|
| 235 | + work need not make them do so.</li> |
|
| 236 | +</ul> |
|
| 237 | + |
|
| 238 | +<p>A compilation of a covered work with other separate and independent |
|
| 239 | +works, which are not by their nature extensions of the covered work, |
|
| 240 | +and which are not combined with it such as to form a larger program, |
|
| 241 | +in or on a volume of a storage or distribution medium, is called an |
|
| 242 | +“aggregate” if the compilation and its resulting copyright are not |
|
| 243 | +used to limit the access or legal rights of the compilation's users |
|
| 244 | +beyond what the individual works permit. Inclusion of a covered work |
|
| 245 | +in an aggregate does not cause this License to apply to the other |
|
| 246 | +parts of the aggregate.</p> |
|
| 247 | + |
|
| 248 | +<h4><a name="section6"></a>6. Conveying Non-Source Forms.</h4> |
|
| 249 | + |
|
| 250 | +<p>You may convey a covered work in object code form under the terms |
|
| 251 | +of sections 4 and 5, provided that you also convey the |
|
| 252 | +machine-readable Corresponding Source under the terms of this License, |
|
| 253 | +in one of these ways:</p> |
|
| 254 | + |
|
| 255 | +<ul> |
|
| 256 | +<li>a) Convey the object code in, or embodied in, a physical product |
|
| 257 | + (including a physical distribution medium), accompanied by the |
|
| 258 | + Corresponding Source fixed on a durable physical medium |
|
| 259 | + customarily used for software interchange.</li> |
|
| 260 | + |
|
| 261 | +<li>b) Convey the object code in, or embodied in, a physical product |
|
| 262 | + (including a physical distribution medium), accompanied by a |
|
| 263 | + written offer, valid for at least three years and valid for as |
|
| 264 | + long as you offer spare parts or customer support for that product |
|
| 265 | + model, to give anyone who possesses the object code either (1) a |
|
| 266 | + copy of the Corresponding Source for all the software in the |
|
| 267 | + product that is covered by this License, on a durable physical |
|
| 268 | + medium customarily used for software interchange, for a price no |
|
| 269 | + more than your reasonable cost of physically performing this |
|
| 270 | + conveying of source, or (2) access to copy the |
|
| 271 | + Corresponding Source from a network server at no charge.</li> |
|
| 272 | + |
|
| 273 | +<li>c) Convey individual copies of the object code with a copy of the |
|
| 274 | + written offer to provide the Corresponding Source. This |
|
| 275 | + alternative is allowed only occasionally and noncommercially, and |
|
| 276 | + only if you received the object code with such an offer, in accord |
|
| 277 | + with subsection 6b.</li> |
|
| 278 | + |
|
| 279 | +<li>d) Convey the object code by offering access from a designated |
|
| 280 | + place (gratis or for a charge), and offer equivalent access to the |
|
| 281 | + Corresponding Source in the same way through the same place at no |
|
| 282 | + further charge. You need not require recipients to copy the |
|
| 283 | + Corresponding Source along with the object code. If the place to |
|
| 284 | + copy the object code is a network server, the Corresponding Source |
|
| 285 | + may be on a different server (operated by you or a third party) |
|
| 286 | + that supports equivalent copying facilities, provided you maintain |
|
| 287 | + clear directions next to the object code saying where to find the |
|
| 288 | + Corresponding Source. Regardless of what server hosts the |
|
| 289 | + Corresponding Source, you remain obligated to ensure that it is |
|
| 290 | + available for as long as needed to satisfy these requirements.</li> |
|
| 291 | + |
|
| 292 | +<li>e) Convey the object code using peer-to-peer transmission, provided |
|
| 293 | + you inform other peers where the object code and Corresponding |
|
| 294 | + Source of the work are being offered to the general public at no |
|
| 295 | + charge under subsection 6d.</li> |
|
| 296 | +</ul> |
|
| 297 | + |
|
| 298 | +<p>A separable portion of the object code, whose source code is excluded |
|
| 299 | +from the Corresponding Source as a System Library, need not be |
|
| 300 | +included in conveying the object code work.</p> |
|
| 301 | + |
|
| 302 | +<p>A “User Product” is either (1) a “consumer product”, which means any |
|
| 303 | +tangible personal property which is normally used for personal, family, |
|
| 304 | +or household purposes, or (2) anything designed or sold for incorporation |
|
| 305 | +into a dwelling. In determining whether a product is a consumer product, |
|
| 306 | +doubtful cases shall be resolved in favor of coverage. For a particular |
|
| 307 | +product received by a particular user, “normally used” refers to a |
|
| 308 | +typical or common use of that class of product, regardless of the status |
|
| 309 | +of the particular user or of the way in which the particular user |
|
| 310 | +actually uses, or expects or is expected to use, the product. A product |
|
| 311 | +is a consumer product regardless of whether the product has substantial |
|
| 312 | +commercial, industrial or non-consumer uses, unless such uses represent |
|
| 313 | +the only significant mode of use of the product.</p> |
|
| 314 | + |
|
| 315 | +<p>“Installation Information” for a User Product means any methods, |
|
| 316 | +procedures, authorization keys, or other information required to install |
|
| 317 | +and execute modified versions of a covered work in that User Product from |
|
| 318 | +a modified version of its Corresponding Source. The information must |
|
| 319 | +suffice to ensure that the continued functioning of the modified object |
|
| 320 | +code is in no case prevented or interfered with solely because |
|
| 321 | +modification has been made.</p> |
|
| 322 | + |
|
| 323 | +<p>If you convey an object code work under this section in, or with, or |
|
| 324 | +specifically for use in, a User Product, and the conveying occurs as |
|
| 325 | +part of a transaction in which the right of possession and use of the |
|
| 326 | +User Product is transferred to the recipient in perpetuity or for a |
|
| 327 | +fixed term (regardless of how the transaction is characterized), the |
|
| 328 | +Corresponding Source conveyed under this section must be accompanied |
|
| 329 | +by the Installation Information. But this requirement does not apply |
|
| 330 | +if neither you nor any third party retains the ability to install |
|
| 331 | +modified object code on the User Product (for example, the work has |
|
| 332 | +been installed in ROM).</p> |
|
| 333 | + |
|
| 334 | +<p>The requirement to provide Installation Information does not include a |
|
| 335 | +requirement to continue to provide support service, warranty, or updates |
|
| 336 | +for a work that has been modified or installed by the recipient, or for |
|
| 337 | +the User Product in which it has been modified or installed. Access to a |
|
| 338 | +network may be denied when the modification itself materially and |
|
| 339 | +adversely affects the operation of the network or violates the rules and |
|
| 340 | +protocols for communication across the network.</p> |
|
| 341 | + |
|
| 342 | +<p>Corresponding Source conveyed, and Installation Information provided, |
|
| 343 | +in accord with this section must be in a format that is publicly |
|
| 344 | +documented (and with an implementation available to the public in |
|
| 345 | +source code form), and must require no special password or key for |
|
| 346 | +unpacking, reading or copying.</p> |
|
| 347 | + |
|
| 348 | +<h4><a name="section7"></a>7. Additional Terms.</h4> |
|
| 349 | + |
|
| 350 | +<p>“Additional permissions” are terms that supplement the terms of this |
|
| 351 | +License by making exceptions from one or more of its conditions. |
|
| 352 | +Additional permissions that are applicable to the entire Program shall |
|
| 353 | +be treated as though they were included in this License, to the extent |
|
| 354 | +that they are valid under applicable law. If additional permissions |
|
| 355 | +apply only to part of the Program, that part may be used separately |
|
| 356 | +under those permissions, but the entire Program remains governed by |
|
| 357 | +this License without regard to the additional permissions.</p> |
|
| 358 | + |
|
| 359 | +<p>When you convey a copy of a covered work, you may at your option |
|
| 360 | +remove any additional permissions from that copy, or from any part of |
|
| 361 | +it. (Additional permissions may be written to require their own |
|
| 362 | +removal in certain cases when you modify the work.) You may place |
|
| 363 | +additional permissions on material, added by you to a covered work, |
|
| 364 | +for which you have or can give appropriate copyright permission.</p> |
|
| 365 | + |
|
| 366 | +<p>Notwithstanding any other provision of this License, for material you |
|
| 367 | +add to a covered work, you may (if authorized by the copyright holders of |
|
| 368 | +that material) supplement the terms of this License with terms:</p> |
|
| 369 | + |
|
| 370 | +<ul> |
|
| 371 | +<li>a) Disclaiming warranty or limiting liability differently from the |
|
| 372 | + terms of sections 15 and 16 of this License; or</li> |
|
| 373 | + |
|
| 374 | +<li>b) Requiring preservation of specified reasonable legal notices or |
|
| 375 | + author attributions in that material or in the Appropriate Legal |
|
| 376 | + Notices displayed by works containing it; or</li> |
|
| 377 | + |
|
| 378 | +<li>c) Prohibiting misrepresentation of the origin of that material, or |
|
| 379 | + requiring that modified versions of such material be marked in |
|
| 380 | + reasonable ways as different from the original version; or</li> |
|
| 381 | + |
|
| 382 | +<li>d) Limiting the use for publicity purposes of names of licensors or |
|
| 383 | + authors of the material; or</li> |
|
| 384 | + |
|
| 385 | +<li>e) Declining to grant rights under trademark law for use of some |
|
| 386 | + trade names, trademarks, or service marks; or</li> |
|
| 387 | + |
|
| 388 | +<li>f) Requiring indemnification of licensors and authors of that |
|
| 389 | + material by anyone who conveys the material (or modified versions of |
|
| 390 | + it) with contractual assumptions of liability to the recipient, for |
|
| 391 | + any liability that these contractual assumptions directly impose on |
|
| 392 | + those licensors and authors.</li> |
|
| 393 | +</ul> |
|
| 394 | + |
|
| 395 | +<p>All other non-permissive additional terms are considered “further |
|
| 396 | +restrictions” within the meaning of section 10. If the Program as you |
|
| 397 | +received it, or any part of it, contains a notice stating that it is |
|
| 398 | +governed by this License along with a term that is a further |
|
| 399 | +restriction, you may remove that term. If a license document contains |
|
| 400 | +a further restriction but permits relicensing or conveying under this |
|
| 401 | +License, you may add to a covered work material governed by the terms |
|
| 402 | +of that license document, provided that the further restriction does |
|
| 403 | +not survive such relicensing or conveying.</p> |
|
| 404 | + |
|
| 405 | +<p>If you add terms to a covered work in accord with this section, you |
|
| 406 | +must place, in the relevant source files, a statement of the |
|
| 407 | +additional terms that apply to those files, or a notice indicating |
|
| 408 | +where to find the applicable terms.</p> |
|
| 409 | + |
|
| 410 | +<p>Additional terms, permissive or non-permissive, may be stated in the |
|
| 411 | +form of a separately written license, or stated as exceptions; |
|
| 412 | +the above requirements apply either way.</p> |
|
| 413 | + |
|
| 414 | +<h4><a name="section8"></a>8. Termination.</h4> |
|
| 415 | + |
|
| 416 | +<p>You may not propagate or modify a covered work except as expressly |
|
| 417 | +provided under this License. Any attempt otherwise to propagate or |
|
| 418 | +modify it is void, and will automatically terminate your rights under |
|
| 419 | +this License (including any patent licenses granted under the third |
|
| 420 | +paragraph of section 11).</p> |
|
| 421 | + |
|
| 422 | +<p>However, if you cease all violation of this License, then your |
|
| 423 | +license from a particular copyright holder is reinstated (a) |
|
| 424 | +provisionally, unless and until the copyright holder explicitly and |
|
| 425 | +finally terminates your license, and (b) permanently, if the copyright |
|
| 426 | +holder fails to notify you of the violation by some reasonable means |
|
| 427 | +prior to 60 days after the cessation.</p> |
|
| 428 | + |
|
| 429 | +<p>Moreover, your license from a particular copyright holder is |
|
| 430 | +reinstated permanently if the copyright holder notifies you of the |
|
| 431 | +violation by some reasonable means, this is the first time you have |
|
| 432 | +received notice of violation of this License (for any work) from that |
|
| 433 | +copyright holder, and you cure the violation prior to 30 days after |
|
| 434 | +your receipt of the notice.</p> |
|
| 435 | + |
|
| 436 | +<p>Termination of your rights under this section does not terminate the |
|
| 437 | +licenses of parties who have received copies or rights from you under |
|
| 438 | +this License. If your rights have been terminated and not permanently |
|
| 439 | +reinstated, you do not qualify to receive new licenses for the same |
|
| 440 | +material under section 10.</p> |
|
| 441 | + |
|
| 442 | +<h4><a name="section9"></a>9. Acceptance Not Required for Having Copies.</h4> |
|
| 443 | + |
|
| 444 | +<p>You are not required to accept this License in order to receive or |
|
| 445 | +run a copy of the Program. Ancillary propagation of a covered work |
|
| 446 | +occurring solely as a consequence of using peer-to-peer transmission |
|
| 447 | +to receive a copy likewise does not require acceptance. However, |
|
| 448 | +nothing other than this License grants you permission to propagate or |
|
| 449 | +modify any covered work. These actions infringe copyright if you do |
|
| 450 | +not accept this License. Therefore, by modifying or propagating a |
|
| 451 | +covered work, you indicate your acceptance of this License to do so.</p> |
|
| 452 | + |
|
| 453 | +<h4><a name="section10"></a>10. Automatic Licensing of Downstream Recipients.</h4> |
|
| 454 | + |
|
| 455 | +<p>Each time you convey a covered work, the recipient automatically |
|
| 456 | +receives a license from the original licensors, to run, modify and |
|
| 457 | +propagate that work, subject to this License. You are not responsible |
|
| 458 | +for enforcing compliance by third parties with this License.</p> |
|
| 459 | + |
|
| 460 | +<p>An “entity transaction” is a transaction transferring control of an |
|
| 461 | +organization, or substantially all assets of one, or subdividing an |
|
| 462 | +organization, or merging organizations. If propagation of a covered |
|
| 463 | +work results from an entity transaction, each party to that |
|
| 464 | +transaction who receives a copy of the work also receives whatever |
|
| 465 | +licenses to the work the party's predecessor in interest had or could |
|
| 466 | +give under the previous paragraph, plus a right to possession of the |
|
| 467 | +Corresponding Source of the work from the predecessor in interest, if |
|
| 468 | +the predecessor has it or can get it with reasonable efforts.</p> |
|
| 469 | + |
|
| 470 | +<p>You may not impose any further restrictions on the exercise of the |
|
| 471 | +rights granted or affirmed under this License. For example, you may |
|
| 472 | +not impose a license fee, royalty, or other charge for exercise of |
|
| 473 | +rights granted under this License, and you may not initiate litigation |
|
| 474 | +(including a cross-claim or counterclaim in a lawsuit) alleging that |
|
| 475 | +any patent claim is infringed by making, using, selling, offering for |
|
| 476 | +sale, or importing the Program or any portion of it.</p> |
|
| 477 | + |
|
| 478 | +<h4><a name="section11"></a>11. Patents.</h4> |
|
| 479 | + |
|
| 480 | +<p>A “contributor” is a copyright holder who authorizes use under this |
|
| 481 | +License of the Program or a work on which the Program is based. The |
|
| 482 | +work thus licensed is called the contributor's “contributor version”.</p> |
|
| 483 | + |
|
| 484 | +<p>A contributor's “essential patent claims” are all patent claims |
|
| 485 | +owned or controlled by the contributor, whether already acquired or |
|
| 486 | +hereafter acquired, that would be infringed by some manner, permitted |
|
| 487 | +by this License, of making, using, or selling its contributor version, |
|
| 488 | +but do not include claims that would be infringed only as a |
|
| 489 | +consequence of further modification of the contributor version. For |
|
| 490 | +purposes of this definition, “control” includes the right to grant |
|
| 491 | +patent sublicenses in a manner consistent with the requirements of |
|
| 492 | +this License.</p> |
|
| 493 | + |
|
| 494 | +<p>Each contributor grants you a non-exclusive, worldwide, royalty-free |
|
| 495 | +patent license under the contributor's essential patent claims, to |
|
| 496 | +make, use, sell, offer for sale, import and otherwise run, modify and |
|
| 497 | +propagate the contents of its contributor version.</p> |
|
| 498 | + |
|
| 499 | +<p>In the following three paragraphs, a “patent license” is any express |
|
| 500 | +agreement or commitment, however denominated, not to enforce a patent |
|
| 501 | +(such as an express permission to practice a patent or covenant not to |
|
| 502 | +sue for patent infringement). To “grant” such a patent license to a |
|
| 503 | +party means to make such an agreement or commitment not to enforce a |
|
| 504 | +patent against the party.</p> |
|
| 505 | + |
|
| 506 | +<p>If you convey a covered work, knowingly relying on a patent license, |
|
| 507 | +and the Corresponding Source of the work is not available for anyone |
|
| 508 | +to copy, free of charge and under the terms of this License, through a |
|
| 509 | +publicly available network server or other readily accessible means, |
|
| 510 | +then you must either (1) cause the Corresponding Source to be so |
|
| 511 | +available, or (2) arrange to deprive yourself of the benefit of the |
|
| 512 | +patent license for this particular work, or (3) arrange, in a manner |
|
| 513 | +consistent with the requirements of this License, to extend the patent |
|
| 514 | +license to downstream recipients. “Knowingly relying” means you have |
|
| 515 | +actual knowledge that, but for the patent license, your conveying the |
|
| 516 | +covered work in a country, or your recipient's use of the covered work |
|
| 517 | +in a country, would infringe one or more identifiable patents in that |
|
| 518 | +country that you have reason to believe are valid.</p> |
|
| 519 | + |
|
| 520 | +<p>If, pursuant to or in connection with a single transaction or |
|
| 521 | +arrangement, you convey, or propagate by procuring conveyance of, a |
|
| 522 | +covered work, and grant a patent license to some of the parties |
|
| 523 | +receiving the covered work authorizing them to use, propagate, modify |
|
| 524 | +or convey a specific copy of the covered work, then the patent license |
|
| 525 | +you grant is automatically extended to all recipients of the covered |
|
| 526 | +work and works based on it.</p> |
|
| 527 | + |
|
| 528 | +<p>A patent license is “discriminatory” if it does not include within |
|
| 529 | +the scope of its coverage, prohibits the exercise of, or is |
|
| 530 | +conditioned on the non-exercise of one or more of the rights that are |
|
| 531 | +specifically granted under this License. You may not convey a covered |
|
| 532 | +work if you are a party to an arrangement with a third party that is |
|
| 533 | +in the business of distributing software, under which you make payment |
|
| 534 | +to the third party based on the extent of your activity of conveying |
|
| 535 | +the work, and under which the third party grants, to any of the |
|
| 536 | +parties who would receive the covered work from you, a discriminatory |
|
| 537 | +patent license (a) in connection with copies of the covered work |
|
| 538 | +conveyed by you (or copies made from those copies), or (b) primarily |
|
| 539 | +for and in connection with specific products or compilations that |
|
| 540 | +contain the covered work, unless you entered into that arrangement, |
|
| 541 | +or that patent license was granted, prior to 28 March 2007.</p> |
|
| 542 | + |
|
| 543 | +<p>Nothing in this License shall be construed as excluding or limiting |
|
| 544 | +any implied license or other defenses to infringement that may |
|
| 545 | +otherwise be available to you under applicable patent law.</p> |
|
| 546 | + |
|
| 547 | +<h4><a name="section12"></a>12. No Surrender of Others' Freedom.</h4> |
|
| 548 | + |
|
| 549 | +<p>If conditions are imposed on you (whether by court order, agreement or |
|
| 550 | +otherwise) that contradict the conditions of this License, they do not |
|
| 551 | +excuse you from the conditions of this License. If you cannot convey a |
|
| 552 | +covered work so as to satisfy simultaneously your obligations under this |
|
| 553 | +License and any other pertinent obligations, then as a consequence you may |
|
| 554 | +not convey it at all. For example, if you agree to terms that obligate you |
|
| 555 | +to collect a royalty for further conveying from those to whom you convey |
|
| 556 | +the Program, the only way you could satisfy both those terms and this |
|
| 557 | +License would be to refrain entirely from conveying the Program.</p> |
|
| 558 | + |
|
| 559 | +<h4><a name="section13"></a>13. Use with the GNU Affero General Public License.</h4> |
|
| 560 | + |
|
| 561 | +<p>Notwithstanding any other provision of this License, you have |
|
| 562 | +permission to link or combine any covered work with a work licensed |
|
| 563 | +under version 3 of the GNU Affero General Public License into a single |
|
| 564 | +combined work, and to convey the resulting work. The terms of this |
|
| 565 | +License will continue to apply to the part which is the covered work, |
|
| 566 | +but the special requirements of the GNU Affero General Public License, |
|
| 567 | +section 13, concerning interaction through a network will apply to the |
|
| 568 | +combination as such.</p> |
|
| 569 | + |
|
| 570 | +<h4><a name="section14"></a>14. Revised Versions of this License.</h4> |
|
| 571 | + |
|
| 572 | +<p>The Free Software Foundation may publish revised and/or new versions of |
|
| 573 | +the GNU General Public License from time to time. Such new versions will |
|
| 574 | +be similar in spirit to the present version, but may differ in detail to |
|
| 575 | +address new problems or concerns.</p> |
|
| 576 | + |
|
| 577 | +<p>Each version is given a distinguishing version number. If the |
|
| 578 | +Program specifies that a certain numbered version of the GNU General |
|
| 579 | +Public License “or any later version” applies to it, you have the |
|
| 580 | +option of following the terms and conditions either of that numbered |
|
| 581 | +version or of any later version published by the Free Software |
|
| 582 | +Foundation. If the Program does not specify a version number of the |
|
| 583 | +GNU General Public License, you may choose any version ever published |
|
| 584 | +by the Free Software Foundation.</p> |
|
| 585 | + |
|
| 586 | +<p>If the Program specifies that a proxy can decide which future |
|
| 587 | +versions of the GNU General Public License can be used, that proxy's |
|
| 588 | +public statement of acceptance of a version permanently authorizes you |
|
| 589 | +to choose that version for the Program.</p> |
|
| 590 | + |
|
| 591 | +<p>Later license versions may give you additional or different |
|
| 592 | +permissions. However, no additional obligations are imposed on any |
|
| 593 | +author or copyright holder as a result of your choosing to follow a |
|
| 594 | +later version.</p> |
|
| 595 | + |
|
| 596 | +<h4><a name="section15"></a>15. Disclaimer of Warranty.</h4> |
|
| 597 | + |
|
| 598 | +<p>THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
|
| 599 | +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
|
| 600 | +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY |
|
| 601 | +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
|
| 602 | +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
| 603 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
|
| 604 | +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
|
| 605 | +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</p> |
|
| 606 | + |
|
| 607 | +<h4><a name="section16"></a>16. Limitation of Liability.</h4> |
|
| 608 | + |
|
| 609 | +<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|
| 610 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
|
| 611 | +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
|
| 612 | +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
|
| 613 | +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
|
| 614 | +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
|
| 615 | +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
|
| 616 | +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
|
| 617 | +SUCH DAMAGES.</p> |
|
| 618 | + |
|
| 619 | +<h4><a name="section17"></a>17. Interpretation of Sections 15 and 16.</h4> |
|
| 620 | + |
|
| 621 | +<p>If the disclaimer of warranty and limitation of liability provided |
|
| 622 | +above cannot be given local legal effect according to their terms, |
|
| 623 | +reviewing courts shall apply local law that most closely approximates |
|
| 624 | +an absolute waiver of all civil liability in connection with the |
|
| 625 | +Program, unless a warranty or assumption of liability accompanies a |
|
| 626 | +copy of the Program in return for a fee.</p> |
|
| 627 | + |
|
| 628 | +<p>END OF TERMS AND CONDITIONS</p> |
|
| 629 | + |
|
| 630 | +<h3><a name="howto"></a>How to Apply These Terms to Your New Programs</h3> |
|
| 631 | + |
|
| 632 | +<p>If you develop a new program, and you want it to be of the greatest |
|
| 633 | +possible use to the public, the best way to achieve this is to make it |
|
| 634 | +free software which everyone can redistribute and change under these terms.</p> |
|
| 635 | + |
|
| 636 | +<p>To do so, attach the following notices to the program. It is safest |
|
| 637 | +to attach them to the start of each source file to most effectively |
|
| 638 | +state the exclusion of warranty; and each file should have at least |
|
| 639 | +the “copyright” line and a pointer to where the full notice is found.</p> |
|
| 640 | + |
|
| 641 | +<pre> <one line to give the program's name and a brief idea of what it does.> |
|
| 642 | + Copyright (C) <year> <name of author> |
|
| 643 | + |
|
| 644 | + This program is free software: you can redistribute it and/or modify |
|
| 645 | + it under the terms of the GNU General Public License as published by |
|
| 646 | + the Free Software Foundation, either version 3 of the License, or |
|
| 647 | + (at your option) any later version. |
|
| 648 | + |
|
| 649 | + This program is distributed in the hope that it will be useful, |
|
| 650 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 651 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 652 | + GNU General Public License for more details. |
|
| 653 | + |
|
| 654 | + You should have received a copy of the GNU General Public License |
|
| 655 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 656 | +</pre> |
|
| 657 | + |
|
| 658 | +<p>Also add information on how to contact you by electronic and paper mail.</p> |
|
| 659 | + |
|
| 660 | +<p>If the program does terminal interaction, make it output a short |
|
| 661 | +notice like this when it starts in an interactive mode:</p> |
|
| 662 | + |
|
| 663 | +<pre> <program> Copyright (C) <year> <name of author> |
|
| 664 | + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
|
| 665 | + This is free software, and you are welcome to redistribute it |
|
| 666 | + under certain conditions; type `show c' for details. |
|
| 667 | +</pre> |
|
| 668 | + |
|
| 669 | +<p>The hypothetical commands `show w' and `show c' should show the appropriate |
|
| 670 | +parts of the General Public License. Of course, your program's commands |
|
| 671 | +might be different; for a GUI interface, you would use an “about box”.</p> |
|
| 672 | + |
|
| 673 | +<p>You should also get your employer (if you work as a programmer) or school, |
|
| 674 | +if any, to sign a “copyright disclaimer” for the program, if necessary. |
|
| 675 | +For more information on this, and how to apply and follow the GNU GPL, see |
|
| 676 | +<<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.</p> |
|
| 677 | + |
|
| 678 | +<p>The GNU General Public License does not permit incorporating your program |
|
| 679 | +into proprietary programs. If your program is a subroutine library, you |
|
| 680 | +may consider it more useful to permit linking proprietary applications with |
|
| 681 | +the library. If this is what you want to do, use the GNU Lesser General |
|
| 682 | +Public License instead of this License. But first, please read |
|
| 683 | +<<a href="http://www.gnu.org/philosophy/why-not-lgpl.html">http://www.gnu.org/philosophy/why-not-lgpl.html</a>>.</p> |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/gpl_30_summary.txt
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | + This program is free software: you can redistribute it and/or modify |
|
| 2 | + it under the terms of the GNU General Public License as published by |
|
| 3 | + the Free Software Foundation, either version 3 of the License, or |
|
| 4 | + (at your option) any later version. |
|
| 5 | + |
|
| 6 | + This program is distributed in the hope that it will be useful, |
|
| 7 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 8 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 9 | + GNU General Public License for more details. |
|
| 10 | + |
|
| 11 | + You should have received a copy of the GNU General Public License |
|
| 12 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 13 | + |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/isc_full.txt
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +Permission to use, copy, modify, and/or distribute this software for |
|
| 2 | +any purpose with or without fee is hereby granted, provided that this |
|
| 3 | +permission notice appear in all copies. |
|
| 4 | + |
|
| 5 | +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
| 6 | +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
| 7 | +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, |
|
| 8 | +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
|
| 9 | +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
| 10 | +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
| 11 | +PERFORMANCE OF THIS SOFTWARE. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/isc_summary.txt
| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that this permission notice appear in all copies. |
|
| 2 | + |
|
| 3 | +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/lgpl_21_full.txt
| ... | ... | @@ -0,0 +1,502 @@ |
| 1 | + GNU LESSER GENERAL PUBLIC LICENSE |
|
| 2 | + Version 2.1, February 1999 |
|
| 3 | + |
|
| 4 | + Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
|
| 5 | + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
| 6 | + Everyone is permitted to copy and distribute verbatim copies |
|
| 7 | + of this license document, but changing it is not allowed. |
|
| 8 | + |
|
| 9 | +[This is the first released version of the Lesser GPL. It also counts |
|
| 10 | + as the successor of the GNU Library Public License, version 2, hence |
|
| 11 | + the version number 2.1.] |
|
| 12 | + |
|
| 13 | + Preamble |
|
| 14 | + |
|
| 15 | + The licenses for most software are designed to take away your |
|
| 16 | +freedom to share and change it. By contrast, the GNU General Public |
|
| 17 | +Licenses are intended to guarantee your freedom to share and change |
|
| 18 | +free software--to make sure the software is free for all its users. |
|
| 19 | + |
|
| 20 | + This license, the Lesser General Public License, applies to some |
|
| 21 | +specially designated software packages--typically libraries--of the |
|
| 22 | +Free Software Foundation and other authors who decide to use it. You |
|
| 23 | +can use it too, but we suggest you first think carefully about whether |
|
| 24 | +this license or the ordinary General Public License is the better |
|
| 25 | +strategy to use in any particular case, based on the explanations below. |
|
| 26 | + |
|
| 27 | + When we speak of free software, we are referring to freedom of use, |
|
| 28 | +not price. Our General Public Licenses are designed to make sure that |
|
| 29 | +you have the freedom to distribute copies of free software (and charge |
|
| 30 | +for this service if you wish); that you receive source code or can get |
|
| 31 | +it if you want it; that you can change the software and use pieces of |
|
| 32 | +it in new free programs; and that you are informed that you can do |
|
| 33 | +these things. |
|
| 34 | + |
|
| 35 | + To protect your rights, we need to make restrictions that forbid |
|
| 36 | +distributors to deny you these rights or to ask you to surrender these |
|
| 37 | +rights. These restrictions translate to certain responsibilities for |
|
| 38 | +you if you distribute copies of the library or if you modify it. |
|
| 39 | + |
|
| 40 | + For example, if you distribute copies of the library, whether gratis |
|
| 41 | +or for a fee, you must give the recipients all the rights that we gave |
|
| 42 | +you. You must make sure that they, too, receive or can get the source |
|
| 43 | +code. If you link other code with the library, you must provide |
|
| 44 | +complete object files to the recipients, so that they can relink them |
|
| 45 | +with the library after making changes to the library and recompiling |
|
| 46 | +it. And you must show them these terms so they know their rights. |
|
| 47 | + |
|
| 48 | + We protect your rights with a two-step method: (1) we copyright the |
|
| 49 | +library, and (2) we offer you this license, which gives you legal |
|
| 50 | +permission to copy, distribute and/or modify the library. |
|
| 51 | + |
|
| 52 | + To protect each distributor, we want to make it very clear that |
|
| 53 | +there is no warranty for the free library. Also, if the library is |
|
| 54 | +modified by someone else and passed on, the recipients should know |
|
| 55 | +that what they have is not the original version, so that the original |
|
| 56 | +author's reputation will not be affected by problems that might be |
|
| 57 | +introduced by others. |
|
| 58 | + |
|
| 59 | + Finally, software patents pose a constant threat to the existence of |
|
| 60 | +any free program. We wish to make sure that a company cannot |
|
| 61 | +effectively restrict the users of a free program by obtaining a |
|
| 62 | +restrictive license from a patent holder. Therefore, we insist that |
|
| 63 | +any patent license obtained for a version of the library must be |
|
| 64 | +consistent with the full freedom of use specified in this license. |
|
| 65 | + |
|
| 66 | + Most GNU software, including some libraries, is covered by the |
|
| 67 | +ordinary GNU General Public License. This license, the GNU Lesser |
|
| 68 | +General Public License, applies to certain designated libraries, and |
|
| 69 | +is quite different from the ordinary General Public License. We use |
|
| 70 | +this license for certain libraries in order to permit linking those |
|
| 71 | +libraries into non-free programs. |
|
| 72 | + |
|
| 73 | + When a program is linked with a library, whether statically or using |
|
| 74 | +a shared library, the combination of the two is legally speaking a |
|
| 75 | +combined work, a derivative of the original library. The ordinary |
|
| 76 | +General Public License therefore permits such linking only if the |
|
| 77 | +entire combination fits its criteria of freedom. The Lesser General |
|
| 78 | +Public License permits more lax criteria for linking other code with |
|
| 79 | +the library. |
|
| 80 | + |
|
| 81 | + We call this license the "Lesser" General Public License because it |
|
| 82 | +does Less to protect the user's freedom than the ordinary General |
|
| 83 | +Public License. It also provides other free software developers Less |
|
| 84 | +of an advantage over competing non-free programs. These disadvantages |
|
| 85 | +are the reason we use the ordinary General Public License for many |
|
| 86 | +libraries. However, the Lesser license provides advantages in certain |
|
| 87 | +special circumstances. |
|
| 88 | + |
|
| 89 | + For example, on rare occasions, there may be a special need to |
|
| 90 | +encourage the widest possible use of a certain library, so that it becomes |
|
| 91 | +a de-facto standard. To achieve this, non-free programs must be |
|
| 92 | +allowed to use the library. A more frequent case is that a free |
|
| 93 | +library does the same job as widely used non-free libraries. In this |
|
| 94 | +case, there is little to gain by limiting the free library to free |
|
| 95 | +software only, so we use the Lesser General Public License. |
|
| 96 | + |
|
| 97 | + In other cases, permission to use a particular library in non-free |
|
| 98 | +programs enables a greater number of people to use a large body of |
|
| 99 | +free software. For example, permission to use the GNU C Library in |
|
| 100 | +non-free programs enables many more people to use the whole GNU |
|
| 101 | +operating system, as well as its variant, the GNU/Linux operating |
|
| 102 | +system. |
|
| 103 | + |
|
| 104 | + Although the Lesser General Public License is Less protective of the |
|
| 105 | +users' freedom, it does ensure that the user of a program that is |
|
| 106 | +linked with the Library has the freedom and the wherewithal to run |
|
| 107 | +that program using a modified version of the Library. |
|
| 108 | + |
|
| 109 | + The precise terms and conditions for copying, distribution and |
|
| 110 | +modification follow. Pay close attention to the difference between a |
|
| 111 | +"work based on the library" and a "work that uses the library". The |
|
| 112 | +former contains code derived from the library, whereas the latter must |
|
| 113 | +be combined with the library in order to run. |
|
| 114 | + |
|
| 115 | + GNU LESSER GENERAL PUBLIC LICENSE |
|
| 116 | + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
|
| 117 | + |
|
| 118 | + 0. This License Agreement applies to any software library or other |
|
| 119 | +program which contains a notice placed by the copyright holder or |
|
| 120 | +other authorized party saying it may be distributed under the terms of |
|
| 121 | +this Lesser General Public License (also called "this License"). |
|
| 122 | +Each licensee is addressed as "you". |
|
| 123 | + |
|
| 124 | + A "library" means a collection of software functions and/or data |
|
| 125 | +prepared so as to be conveniently linked with application programs |
|
| 126 | +(which use some of those functions and data) to form executables. |
|
| 127 | + |
|
| 128 | + The "Library", below, refers to any such software library or work |
|
| 129 | +which has been distributed under these terms. A "work based on the |
|
| 130 | +Library" means either the Library or any derivative work under |
|
| 131 | +copyright law: that is to say, a work containing the Library or a |
|
| 132 | +portion of it, either verbatim or with modifications and/or translated |
|
| 133 | +straightforwardly into another language. (Hereinafter, translation is |
|
| 134 | +included without limitation in the term "modification".) |
|
| 135 | + |
|
| 136 | + "Source code" for a work means the preferred form of the work for |
|
| 137 | +making modifications to it. For a library, complete source code means |
|
| 138 | +all the source code for all modules it contains, plus any associated |
|
| 139 | +interface definition files, plus the scripts used to control compilation |
|
| 140 | +and installation of the library. |
|
| 141 | + |
|
| 142 | + Activities other than copying, distribution and modification are not |
|
| 143 | +covered by this License; they are outside its scope. The act of |
|
| 144 | +running a program using the Library is not restricted, and output from |
|
| 145 | +such a program is covered only if its contents constitute a work based |
|
| 146 | +on the Library (independent of the use of the Library in a tool for |
|
| 147 | +writing it). Whether that is true depends on what the Library does |
|
| 148 | +and what the program that uses the Library does. |
|
| 149 | + |
|
| 150 | + 1. You may copy and distribute verbatim copies of the Library's |
|
| 151 | +complete source code as you receive it, in any medium, provided that |
|
| 152 | +you conspicuously and appropriately publish on each copy an |
|
| 153 | +appropriate copyright notice and disclaimer of warranty; keep intact |
|
| 154 | +all the notices that refer to this License and to the absence of any |
|
| 155 | +warranty; and distribute a copy of this License along with the |
|
| 156 | +Library. |
|
| 157 | + |
|
| 158 | + You may charge a fee for the physical act of transferring a copy, |
|
| 159 | +and you may at your option offer warranty protection in exchange for a |
|
| 160 | +fee. |
|
| 161 | + |
|
| 162 | + 2. You may modify your copy or copies of the Library or any portion |
|
| 163 | +of it, thus forming a work based on the Library, and copy and |
|
| 164 | +distribute such modifications or work under the terms of Section 1 |
|
| 165 | +above, provided that you also meet all of these conditions: |
|
| 166 | + |
|
| 167 | + a) The modified work must itself be a software library. |
|
| 168 | + |
|
| 169 | + b) You must cause the files modified to carry prominent notices |
|
| 170 | + stating that you changed the files and the date of any change. |
|
| 171 | + |
|
| 172 | + c) You must cause the whole of the work to be licensed at no |
|
| 173 | + charge to all third parties under the terms of this License. |
|
| 174 | + |
|
| 175 | + d) If a facility in the modified Library refers to a function or a |
|
| 176 | + table of data to be supplied by an application program that uses |
|
| 177 | + the facility, other than as an argument passed when the facility |
|
| 178 | + is invoked, then you must make a good faith effort to ensure that, |
|
| 179 | + in the event an application does not supply such function or |
|
| 180 | + table, the facility still operates, and performs whatever part of |
|
| 181 | + its purpose remains meaningful. |
|
| 182 | + |
|
| 183 | + (For example, a function in a library to compute square roots has |
|
| 184 | + a purpose that is entirely well-defined independent of the |
|
| 185 | + application. Therefore, Subsection 2d requires that any |
|
| 186 | + application-supplied function or table used by this function must |
|
| 187 | + be optional: if the application does not supply it, the square |
|
| 188 | + root function must still compute square roots.) |
|
| 189 | + |
|
| 190 | +These requirements apply to the modified work as a whole. If |
|
| 191 | +identifiable sections of that work are not derived from the Library, |
|
| 192 | +and can be reasonably considered independent and separate works in |
|
| 193 | +themselves, then this License, and its terms, do not apply to those |
|
| 194 | +sections when you distribute them as separate works. But when you |
|
| 195 | +distribute the same sections as part of a whole which is a work based |
|
| 196 | +on the Library, the distribution of the whole must be on the terms of |
|
| 197 | +this License, whose permissions for other licensees extend to the |
|
| 198 | +entire whole, and thus to each and every part regardless of who wrote |
|
| 199 | +it. |
|
| 200 | + |
|
| 201 | +Thus, it is not the intent of this section to claim rights or contest |
|
| 202 | +your rights to work written entirely by you; rather, the intent is to |
|
| 203 | +exercise the right to control the distribution of derivative or |
|
| 204 | +collective works based on the Library. |
|
| 205 | + |
|
| 206 | +In addition, mere aggregation of another work not based on the Library |
|
| 207 | +with the Library (or with a work based on the Library) on a volume of |
|
| 208 | +a storage or distribution medium does not bring the other work under |
|
| 209 | +the scope of this License. |
|
| 210 | + |
|
| 211 | + 3. You may opt to apply the terms of the ordinary GNU General Public |
|
| 212 | +License instead of this License to a given copy of the Library. To do |
|
| 213 | +this, you must alter all the notices that refer to this License, so |
|
| 214 | +that they refer to the ordinary GNU General Public License, version 2, |
|
| 215 | +instead of to this License. (If a newer version than version 2 of the |
|
| 216 | +ordinary GNU General Public License has appeared, then you can specify |
|
| 217 | +that version instead if you wish.) Do not make any other change in |
|
| 218 | +these notices. |
|
| 219 | + |
|
| 220 | + Once this change is made in a given copy, it is irreversible for |
|
| 221 | +that copy, so the ordinary GNU General Public License applies to all |
|
| 222 | +subsequent copies and derivative works made from that copy. |
|
| 223 | + |
|
| 224 | + This option is useful when you wish to copy part of the code of |
|
| 225 | +the Library into a program that is not a library. |
|
| 226 | + |
|
| 227 | + 4. You may copy and distribute the Library (or a portion or |
|
| 228 | +derivative of it, under Section 2) in object code or executable form |
|
| 229 | +under the terms of Sections 1 and 2 above provided that you accompany |
|
| 230 | +it with the complete corresponding machine-readable source code, which |
|
| 231 | +must be distributed under the terms of Sections 1 and 2 above on a |
|
| 232 | +medium customarily used for software interchange. |
|
| 233 | + |
|
| 234 | + If distribution of object code is made by offering access to copy |
|
| 235 | +from a designated place, then offering equivalent access to copy the |
|
| 236 | +source code from the same place satisfies the requirement to |
|
| 237 | +distribute the source code, even though third parties are not |
|
| 238 | +compelled to copy the source along with the object code. |
|
| 239 | + |
|
| 240 | + 5. A program that contains no derivative of any portion of the |
|
| 241 | +Library, but is designed to work with the Library by being compiled or |
|
| 242 | +linked with it, is called a "work that uses the Library". Such a |
|
| 243 | +work, in isolation, is not a derivative work of the Library, and |
|
| 244 | +therefore falls outside the scope of this License. |
|
| 245 | + |
|
| 246 | + However, linking a "work that uses the Library" with the Library |
|
| 247 | +creates an executable that is a derivative of the Library (because it |
|
| 248 | +contains portions of the Library), rather than a "work that uses the |
|
| 249 | +library". The executable is therefore covered by this License. |
|
| 250 | +Section 6 states terms for distribution of such executables. |
|
| 251 | + |
|
| 252 | + When a "work that uses the Library" uses material from a header file |
|
| 253 | +that is part of the Library, the object code for the work may be a |
|
| 254 | +derivative work of the Library even though the source code is not. |
|
| 255 | +Whether this is true is especially significant if the work can be |
|
| 256 | +linked without the Library, or if the work is itself a library. The |
|
| 257 | +threshold for this to be true is not precisely defined by law. |
|
| 258 | + |
|
| 259 | + If such an object file uses only numerical parameters, data |
|
| 260 | +structure layouts and accessors, and small macros and small inline |
|
| 261 | +functions (ten lines or less in length), then the use of the object |
|
| 262 | +file is unrestricted, regardless of whether it is legally a derivative |
|
| 263 | +work. (Executables containing this object code plus portions of the |
|
| 264 | +Library will still fall under Section 6.) |
|
| 265 | + |
|
| 266 | + Otherwise, if the work is a derivative of the Library, you may |
|
| 267 | +distribute the object code for the work under the terms of Section 6. |
|
| 268 | +Any executables containing that work also fall under Section 6, |
|
| 269 | +whether or not they are linked directly with the Library itself. |
|
| 270 | + |
|
| 271 | + 6. As an exception to the Sections above, you may also combine or |
|
| 272 | +link a "work that uses the Library" with the Library to produce a |
|
| 273 | +work containing portions of the Library, and distribute that work |
|
| 274 | +under terms of your choice, provided that the terms permit |
|
| 275 | +modification of the work for the customer's own use and reverse |
|
| 276 | +engineering for debugging such modifications. |
|
| 277 | + |
|
| 278 | + You must give prominent notice with each copy of the work that the |
|
| 279 | +Library is used in it and that the Library and its use are covered by |
|
| 280 | +this License. You must supply a copy of this License. If the work |
|
| 281 | +during execution displays copyright notices, you must include the |
|
| 282 | +copyright notice for the Library among them, as well as a reference |
|
| 283 | +directing the user to the copy of this License. Also, you must do one |
|
| 284 | +of these things: |
|
| 285 | + |
|
| 286 | + a) Accompany the work with the complete corresponding |
|
| 287 | + machine-readable source code for the Library including whatever |
|
| 288 | + changes were used in the work (which must be distributed under |
|
| 289 | + Sections 1 and 2 above); and, if the work is an executable linked |
|
| 290 | + with the Library, with the complete machine-readable "work that |
|
| 291 | + uses the Library", as object code and/or source code, so that the |
|
| 292 | + user can modify the Library and then relink to produce a modified |
|
| 293 | + executable containing the modified Library. (It is understood |
|
| 294 | + that the user who changes the contents of definitions files in the |
|
| 295 | + Library will not necessarily be able to recompile the application |
|
| 296 | + to use the modified definitions.) |
|
| 297 | + |
|
| 298 | + b) Use a suitable shared library mechanism for linking with the |
|
| 299 | + Library. A suitable mechanism is one that (1) uses at run time a |
|
| 300 | + copy of the library already present on the user's computer system, |
|
| 301 | + rather than copying library functions into the executable, and (2) |
|
| 302 | + will operate properly with a modified version of the library, if |
|
| 303 | + the user installs one, as long as the modified version is |
|
| 304 | + interface-compatible with the version that the work was made with. |
|
| 305 | + |
|
| 306 | + c) Accompany the work with a written offer, valid for at |
|
| 307 | + least three years, to give the same user the materials |
|
| 308 | + specified in Subsection 6a, above, for a charge no more |
|
| 309 | + than the cost of performing this distribution. |
|
| 310 | + |
|
| 311 | + d) If distribution of the work is made by offering access to copy |
|
| 312 | + from a designated place, offer equivalent access to copy the above |
|
| 313 | + specified materials from the same place. |
|
| 314 | + |
|
| 315 | + e) Verify that the user has already received a copy of these |
|
| 316 | + materials or that you have already sent this user a copy. |
|
| 317 | + |
|
| 318 | + For an executable, the required form of the "work that uses the |
|
| 319 | +Library" must include any data and utility programs needed for |
|
| 320 | +reproducing the executable from it. However, as a special exception, |
|
| 321 | +the materials to be distributed need not include anything that is |
|
| 322 | +normally distributed (in either source or binary form) with the major |
|
| 323 | +components (compiler, kernel, and so on) of the operating system on |
|
| 324 | +which the executable runs, unless that component itself accompanies |
|
| 325 | +the executable. |
|
| 326 | + |
|
| 327 | + It may happen that this requirement contradicts the license |
|
| 328 | +restrictions of other proprietary libraries that do not normally |
|
| 329 | +accompany the operating system. Such a contradiction means you cannot |
|
| 330 | +use both them and the Library together in an executable that you |
|
| 331 | +distribute. |
|
| 332 | + |
|
| 333 | + 7. You may place library facilities that are a work based on the |
|
| 334 | +Library side-by-side in a single library together with other library |
|
| 335 | +facilities not covered by this License, and distribute such a combined |
|
| 336 | +library, provided that the separate distribution of the work based on |
|
| 337 | +the Library and of the other library facilities is otherwise |
|
| 338 | +permitted, and provided that you do these two things: |
|
| 339 | + |
|
| 340 | + a) Accompany the combined library with a copy of the same work |
|
| 341 | + based on the Library, uncombined with any other library |
|
| 342 | + facilities. This must be distributed under the terms of the |
|
| 343 | + Sections above. |
|
| 344 | + |
|
| 345 | + b) Give prominent notice with the combined library of the fact |
|
| 346 | + that part of it is a work based on the Library, and explaining |
|
| 347 | + where to find the accompanying uncombined form of the same work. |
|
| 348 | + |
|
| 349 | + 8. You may not copy, modify, sublicense, link with, or distribute |
|
| 350 | +the Library except as expressly provided under this License. Any |
|
| 351 | +attempt otherwise to copy, modify, sublicense, link with, or |
|
| 352 | +distribute the Library is void, and will automatically terminate your |
|
| 353 | +rights under this License. However, parties who have received copies, |
|
| 354 | +or rights, from you under this License will not have their licenses |
|
| 355 | +terminated so long as such parties remain in full compliance. |
|
| 356 | + |
|
| 357 | + 9. You are not required to accept this License, since you have not |
|
| 358 | +signed it. However, nothing else grants you permission to modify or |
|
| 359 | +distribute the Library or its derivative works. These actions are |
|
| 360 | +prohibited by law if you do not accept this License. Therefore, by |
|
| 361 | +modifying or distributing the Library (or any work based on the |
|
| 362 | +Library), you indicate your acceptance of this License to do so, and |
|
| 363 | +all its terms and conditions for copying, distributing or modifying |
|
| 364 | +the Library or works based on it. |
|
| 365 | + |
|
| 366 | + 10. Each time you redistribute the Library (or any work based on the |
|
| 367 | +Library), the recipient automatically receives a license from the |
|
| 368 | +original licensor to copy, distribute, link with or modify the Library |
|
| 369 | +subject to these terms and conditions. You may not impose any further |
|
| 370 | +restrictions on the recipients' exercise of the rights granted herein. |
|
| 371 | +You are not responsible for enforcing compliance by third parties with |
|
| 372 | +this License. |
|
| 373 | + |
|
| 374 | + 11. If, as a consequence of a court judgment or allegation of patent |
|
| 375 | +infringement or for any other reason (not limited to patent issues), |
|
| 376 | +conditions are imposed on you (whether by court order, agreement or |
|
| 377 | +otherwise) that contradict the conditions of this License, they do not |
|
| 378 | +excuse you from the conditions of this License. If you cannot |
|
| 379 | +distribute so as to satisfy simultaneously your obligations under this |
|
| 380 | +License and any other pertinent obligations, then as a consequence you |
|
| 381 | +may not distribute the Library at all. For example, if a patent |
|
| 382 | +license would not permit royalty-free redistribution of the Library by |
|
| 383 | +all those who receive copies directly or indirectly through you, then |
|
| 384 | +the only way you could satisfy both it and this License would be to |
|
| 385 | +refrain entirely from distribution of the Library. |
|
| 386 | + |
|
| 387 | +If any portion of this section is held invalid or unenforceable under any |
|
| 388 | +particular circumstance, the balance of the section is intended to apply, |
|
| 389 | +and the section as a whole is intended to apply in other circumstances. |
|
| 390 | + |
|
| 391 | +It is not the purpose of this section to induce you to infringe any |
|
| 392 | +patents or other property right claims or to contest validity of any |
|
| 393 | +such claims; this section has the sole purpose of protecting the |
|
| 394 | +integrity of the free software distribution system which is |
|
| 395 | +implemented by public license practices. Many people have made |
|
| 396 | +generous contributions to the wide range of software distributed |
|
| 397 | +through that system in reliance on consistent application of that |
|
| 398 | +system; it is up to the author/donor to decide if he or she is willing |
|
| 399 | +to distribute software through any other system and a licensee cannot |
|
| 400 | +impose that choice. |
|
| 401 | + |
|
| 402 | +This section is intended to make thoroughly clear what is believed to |
|
| 403 | +be a consequence of the rest of this License. |
|
| 404 | + |
|
| 405 | + 12. If the distribution and/or use of the Library is restricted in |
|
| 406 | +certain countries either by patents or by copyrighted interfaces, the |
|
| 407 | +original copyright holder who places the Library under this License may add |
|
| 408 | +an explicit geographical distribution limitation excluding those countries, |
|
| 409 | +so that distribution is permitted only in or among countries not thus |
|
| 410 | +excluded. In such case, this License incorporates the limitation as if |
|
| 411 | +written in the body of this License. |
|
| 412 | + |
|
| 413 | + 13. The Free Software Foundation may publish revised and/or new |
|
| 414 | +versions of the Lesser General Public License from time to time. |
|
| 415 | +Such new versions will be similar in spirit to the present version, |
|
| 416 | +but may differ in detail to address new problems or concerns. |
|
| 417 | + |
|
| 418 | +Each version is given a distinguishing version number. If the Library |
|
| 419 | +specifies a version number of this License which applies to it and |
|
| 420 | +"any later version", you have the option of following the terms and |
|
| 421 | +conditions either of that version or of any later version published by |
|
| 422 | +the Free Software Foundation. If the Library does not specify a |
|
| 423 | +license version number, you may choose any version ever published by |
|
| 424 | +the Free Software Foundation. |
|
| 425 | + |
|
| 426 | + 14. If you wish to incorporate parts of the Library into other free |
|
| 427 | +programs whose distribution conditions are incompatible with these, |
|
| 428 | +write to the author to ask for permission. For software which is |
|
| 429 | +copyrighted by the Free Software Foundation, write to the Free |
|
| 430 | +Software Foundation; we sometimes make exceptions for this. Our |
|
| 431 | +decision will be guided by the two goals of preserving the free status |
|
| 432 | +of all derivatives of our free software and of promoting the sharing |
|
| 433 | +and reuse of software generally. |
|
| 434 | + |
|
| 435 | + NO WARRANTY |
|
| 436 | + |
|
| 437 | + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
|
| 438 | +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
|
| 439 | +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
|
| 440 | +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
|
| 441 | +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
|
| 442 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
| 443 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
|
| 444 | +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
|
| 445 | +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
|
| 446 | + |
|
| 447 | + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
|
| 448 | +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
|
| 449 | +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
|
| 450 | +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
|
| 451 | +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
|
| 452 | +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
|
| 453 | +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
|
| 454 | +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
|
| 455 | +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
|
| 456 | +DAMAGES. |
|
| 457 | + |
|
| 458 | + END OF TERMS AND CONDITIONS |
|
| 459 | + |
|
| 460 | + How to Apply These Terms to Your New Libraries |
|
| 461 | + |
|
| 462 | + If you develop a new library, and you want it to be of the greatest |
|
| 463 | +possible use to the public, we recommend making it free software that |
|
| 464 | +everyone can redistribute and change. You can do so by permitting |
|
| 465 | +redistribution under these terms (or, alternatively, under the terms of the |
|
| 466 | +ordinary General Public License). |
|
| 467 | + |
|
| 468 | + To apply these terms, attach the following notices to the library. It is |
|
| 469 | +safest to attach them to the start of each source file to most effectively |
|
| 470 | +convey the exclusion of warranty; and each file should have at least the |
|
| 471 | +"copyright" line and a pointer to where the full notice is found. |
|
| 472 | + |
|
| 473 | + <one line to give the library's name and a brief idea of what it does.> |
|
| 474 | + Copyright (C) <year> <name of author> |
|
| 475 | + |
|
| 476 | + This library is free software; you can redistribute it and/or |
|
| 477 | + modify it under the terms of the GNU Lesser General Public |
|
| 478 | + License as published by the Free Software Foundation; either |
|
| 479 | + version 2.1 of the License, or (at your option) any later version. |
|
| 480 | + |
|
| 481 | + This library is distributed in the hope that it will be useful, |
|
| 482 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 483 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 484 | + Lesser General Public License for more details. |
|
| 485 | + |
|
| 486 | + You should have received a copy of the GNU Lesser General Public |
|
| 487 | + License along with this library; if not, write to the Free Software |
|
| 488 | + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
| 489 | + |
|
| 490 | +Also add information on how to contact you by electronic and paper mail. |
|
| 491 | + |
|
| 492 | +You should also get your employer (if you work as a programmer) or your |
|
| 493 | +school, if any, to sign a "copyright disclaimer" for the library, if |
|
| 494 | +necessary. Here is a sample; alter the names: |
|
| 495 | + |
|
| 496 | + Yoyodyne, Inc., hereby disclaims all copyright interest in the |
|
| 497 | + library `Frob' (a library for tweaking knobs) written by James Random Hacker. |
|
| 498 | + |
|
| 499 | + <signature of Ty Coon>, 1 April 1990 |
|
| 500 | + Ty Coon, President of Vice |
|
| 501 | + |
|
| 502 | +That's all there is to it! |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/lgpl_21_summary.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. |
|
| 2 | + |
|
| 3 | +This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
|
| 4 | + |
|
| 5 | +You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/lgpl_3_full.txt
| ... | ... | @@ -0,0 +1,165 @@ |
| 1 | + GNU LESSER GENERAL PUBLIC LICENSE |
|
| 2 | + Version 3, 29 June 2007 |
|
| 3 | + |
|
| 4 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
|
| 5 | + Everyone is permitted to copy and distribute verbatim copies |
|
| 6 | + of this license document, but changing it is not allowed. |
|
| 7 | + |
|
| 8 | + |
|
| 9 | + This version of the GNU Lesser General Public License incorporates |
|
| 10 | +the terms and conditions of version 3 of the GNU General Public |
|
| 11 | +License, supplemented by the additional permissions listed below. |
|
| 12 | + |
|
| 13 | + 0. Additional Definitions. |
|
| 14 | + |
|
| 15 | + As used herein, "this License" refers to version 3 of the GNU Lesser |
|
| 16 | +General Public License, and the "GNU GPL" refers to version 3 of the GNU |
|
| 17 | +General Public License. |
|
| 18 | + |
|
| 19 | + "The Library" refers to a covered work governed by this License, |
|
| 20 | +other than an Application or a Combined Work as defined below. |
|
| 21 | + |
|
| 22 | + An "Application" is any work that makes use of an interface provided |
|
| 23 | +by the Library, but which is not otherwise based on the Library. |
|
| 24 | +Defining a subclass of a class defined by the Library is deemed a mode |
|
| 25 | +of using an interface provided by the Library. |
|
| 26 | + |
|
| 27 | + A "Combined Work" is a work produced by combining or linking an |
|
| 28 | +Application with the Library. The particular version of the Library |
|
| 29 | +with which the Combined Work was made is also called the "Linked |
|
| 30 | +Version". |
|
| 31 | + |
|
| 32 | + The "Minimal Corresponding Source" for a Combined Work means the |
|
| 33 | +Corresponding Source for the Combined Work, excluding any source code |
|
| 34 | +for portions of the Combined Work that, considered in isolation, are |
|
| 35 | +based on the Application, and not on the Linked Version. |
|
| 36 | + |
|
| 37 | + The "Corresponding Application Code" for a Combined Work means the |
|
| 38 | +object code and/or source code for the Application, including any data |
|
| 39 | +and utility programs needed for reproducing the Combined Work from the |
|
| 40 | +Application, but excluding the System Libraries of the Combined Work. |
|
| 41 | + |
|
| 42 | + 1. Exception to Section 3 of the GNU GPL. |
|
| 43 | + |
|
| 44 | + You may convey a covered work under sections 3 and 4 of this License |
|
| 45 | +without being bound by section 3 of the GNU GPL. |
|
| 46 | + |
|
| 47 | + 2. Conveying Modified Versions. |
|
| 48 | + |
|
| 49 | + If you modify a copy of the Library, and, in your modifications, a |
|
| 50 | +facility refers to a function or data to be supplied by an Application |
|
| 51 | +that uses the facility (other than as an argument passed when the |
|
| 52 | +facility is invoked), then you may convey a copy of the modified |
|
| 53 | +version: |
|
| 54 | + |
|
| 55 | + a) under this License, provided that you make a good faith effort to |
|
| 56 | + ensure that, in the event an Application does not supply the |
|
| 57 | + function or data, the facility still operates, and performs |
|
| 58 | + whatever part of its purpose remains meaningful, or |
|
| 59 | + |
|
| 60 | + b) under the GNU GPL, with none of the additional permissions of |
|
| 61 | + this License applicable to that copy. |
|
| 62 | + |
|
| 63 | + 3. Object Code Incorporating Material from Library Header Files. |
|
| 64 | + |
|
| 65 | + The object code form of an Application may incorporate material from |
|
| 66 | +a header file that is part of the Library. You may convey such object |
|
| 67 | +code under terms of your choice, provided that, if the incorporated |
|
| 68 | +material is not limited to numerical parameters, data structure |
|
| 69 | +layouts and accessors, or small macros, inline functions and templates |
|
| 70 | +(ten or fewer lines in length), you do both of the following: |
|
| 71 | + |
|
| 72 | + a) Give prominent notice with each copy of the object code that the |
|
| 73 | + Library is used in it and that the Library and its use are |
|
| 74 | + covered by this License. |
|
| 75 | + |
|
| 76 | + b) Accompany the object code with a copy of the GNU GPL and this license |
|
| 77 | + document. |
|
| 78 | + |
|
| 79 | + 4. Combined Works. |
|
| 80 | + |
|
| 81 | + You may convey a Combined Work under terms of your choice that, |
|
| 82 | +taken together, effectively do not restrict modification of the |
|
| 83 | +portions of the Library contained in the Combined Work and reverse |
|
| 84 | +engineering for debugging such modifications, if you also do each of |
|
| 85 | +the following: |
|
| 86 | + |
|
| 87 | + a) Give prominent notice with each copy of the Combined Work that |
|
| 88 | + the Library is used in it and that the Library and its use are |
|
| 89 | + covered by this License. |
|
| 90 | + |
|
| 91 | + b) Accompany the Combined Work with a copy of the GNU GPL and this license |
|
| 92 | + document. |
|
| 93 | + |
|
| 94 | + c) For a Combined Work that displays copyright notices during |
|
| 95 | + execution, include the copyright notice for the Library among |
|
| 96 | + these notices, as well as a reference directing the user to the |
|
| 97 | + copies of the GNU GPL and this license document. |
|
| 98 | + |
|
| 99 | + d) Do one of the following: |
|
| 100 | + |
|
| 101 | + 0) Convey the Minimal Corresponding Source under the terms of this |
|
| 102 | + License, and the Corresponding Application Code in a form |
|
| 103 | + suitable for, and under terms that permit, the user to |
|
| 104 | + recombine or relink the Application with a modified version of |
|
| 105 | + the Linked Version to produce a modified Combined Work, in the |
|
| 106 | + manner specified by section 6 of the GNU GPL for conveying |
|
| 107 | + Corresponding Source. |
|
| 108 | + |
|
| 109 | + 1) Use a suitable shared library mechanism for linking with the |
|
| 110 | + Library. A suitable mechanism is one that (a) uses at run time |
|
| 111 | + a copy of the Library already present on the user's computer |
|
| 112 | + system, and (b) will operate properly with a modified version |
|
| 113 | + of the Library that is interface-compatible with the Linked |
|
| 114 | + Version. |
|
| 115 | + |
|
| 116 | + e) Provide Installation Information, but only if you would otherwise |
|
| 117 | + be required to provide such information under section 6 of the |
|
| 118 | + GNU GPL, and only to the extent that such information is |
|
| 119 | + necessary to install and execute a modified version of the |
|
| 120 | + Combined Work produced by recombining or relinking the |
|
| 121 | + Application with a modified version of the Linked Version. (If |
|
| 122 | + you use option 4d0, the Installation Information must accompany |
|
| 123 | + the Minimal Corresponding Source and Corresponding Application |
|
| 124 | + Code. If you use option 4d1, you must provide the Installation |
|
| 125 | + Information in the manner specified by section 6 of the GNU GPL |
|
| 126 | + for conveying Corresponding Source.) |
|
| 127 | + |
|
| 128 | + 5. Combined Libraries. |
|
| 129 | + |
|
| 130 | + You may place library facilities that are a work based on the |
|
| 131 | +Library side by side in a single library together with other library |
|
| 132 | +facilities that are not Applications and are not covered by this |
|
| 133 | +License, and convey such a combined library under terms of your |
|
| 134 | +choice, if you do both of the following: |
|
| 135 | + |
|
| 136 | + a) Accompany the combined library with a copy of the same work based |
|
| 137 | + on the Library, uncombined with any other library facilities, |
|
| 138 | + conveyed under the terms of this License. |
|
| 139 | + |
|
| 140 | + b) Give prominent notice with the combined library that part of it |
|
| 141 | + is a work based on the Library, and explaining where to find the |
|
| 142 | + accompanying uncombined form of the same work. |
|
| 143 | + |
|
| 144 | + 6. Revised Versions of the GNU Lesser General Public License. |
|
| 145 | + |
|
| 146 | + The Free Software Foundation may publish revised and/or new versions |
|
| 147 | +of the GNU Lesser General Public License from time to time. Such new |
|
| 148 | +versions will be similar in spirit to the present version, but may |
|
| 149 | +differ in detail to address new problems or concerns. |
|
| 150 | + |
|
| 151 | + Each version is given a distinguishing version number. If the |
|
| 152 | +Library as you received it specifies that a certain numbered version |
|
| 153 | +of the GNU Lesser General Public License "or any later version" |
|
| 154 | +applies to it, you have the option of following the terms and |
|
| 155 | +conditions either of that published version or of any later version |
|
| 156 | +published by the Free Software Foundation. If the Library as you |
|
| 157 | +received it does not specify a version number of the GNU Lesser |
|
| 158 | +General Public License, you may choose any version of the GNU Lesser |
|
| 159 | +General Public License ever published by the Free Software Foundation. |
|
| 160 | + |
|
| 161 | + If the Library as you received it specifies that a proxy can decide |
|
| 162 | +whether future versions of the GNU Lesser General Public License shall |
|
| 163 | +apply, that proxy's public statement of acceptance of any version is |
|
| 164 | +permanent authorization for you to choose that version for the |
|
| 165 | +Library. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/lgpl_3_summary.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. |
|
| 2 | + |
|
| 3 | +This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
|
| 4 | + |
|
| 5 | +You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/mit_full.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|
| 2 | + |
|
| 3 | +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|
| 4 | + |
|
| 5 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/mit_summary.txt
| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|
| 2 | + |
|
| 3 | +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|
| 4 | + |
|
| 5 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/raw/notices.xml
| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<notices> |
|
| 19 | + <notice> |
|
| 20 | + <name>Apache Commons IO</name> |
|
| 21 | + <url>http://commons.apache.org/io/</url> |
|
| 22 | + <copyright>Copyright 2002-2012 The Apache Software Foundation</copyright> |
|
| 23 | + <license>Apache Software License 2.0</license> |
|
| 24 | + </notice> |
|
| 25 | +</notices> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values-de/strings.xml
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_title">Anmerkungen</string> |
|
| 20 | + <string name="notices_close">Schließen</string> |
|
| 21 | +</resources> |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values-ja/strings.xml
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_title">オープンソースライセンス</string> |
|
| 20 | + <string name="notices_close">閉じる</string> |
|
| 21 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values-ko/strings.xml
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_title">오픈소스 라이선스</string> |
|
| 20 | + <string name="notices_close">닫기</string> |
|
| 21 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values-zh-rCN/strings.xml
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_title">开放源代码许可</string> |
|
| 20 | + <string name="notices_close">关闭</string> |
|
| 21 | +</resources> |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values/base_html.xml
| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_default_style" translatable="false"> |
|
| 20 | + p.license { |
|
| 21 | + background:grey; |
|
| 22 | + } |
|
| 23 | + body { |
|
| 24 | + font-family: sans-serif; |
|
| 25 | + overflow-wrap: break-word; |
|
| 26 | + } |
|
| 27 | + pre { |
|
| 28 | + background-color: #eeeeee; |
|
| 29 | + padding: 1em; |
|
| 30 | + white-space: pre-wrap; |
|
| 31 | + } |
|
| 32 | + </string> |
|
| 33 | +</resources> |
mobile/licensesdialog_lib/de.psdev.licensesdialog/res/values/strings.xml
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
|
| 2 | +<!-- |
|
| 3 | + ~ Copyright 2013 Philip Schiffer |
|
| 4 | + ~ |
|
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 6 | + ~ you may not use this file except in compliance with the License. |
|
| 7 | + ~ You may obtain a copy of the License at |
|
| 8 | + ~ |
|
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 10 | + ~ |
|
| 11 | + ~ Unless required by applicable law or agreed to in writing, software |
|
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 14 | + ~ See the License for the specific language governing permissions and |
|
| 15 | + ~ limitations under the License. |
|
| 16 | + --> |
|
| 17 | + |
|
| 18 | +<resources> |
|
| 19 | + <string name="notices_title">Notices</string> |
|
| 20 | + <string name="notices_close">Close</string> |
|
| 21 | +</resources> |
|
| ... | ... | \ No newline at end of file |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/LicenseResolver.java
| ... | ... | @@ -0,0 +1,84 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog; |
|
| 18 | + |
|
| 19 | +import java.util.HashMap; |
|
| 20 | +import java.util.Map; |
|
| 21 | + |
|
| 22 | +import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20; |
|
| 23 | +import de.psdev.licensesdialog.licenses.BSD2ClauseLicense; |
|
| 24 | +import de.psdev.licensesdialog.licenses.BSD3ClauseLicense; |
|
| 25 | +import de.psdev.licensesdialog.licenses.CreativeCommonsAttributionNoDerivs30Unported; |
|
| 26 | +import de.psdev.licensesdialog.licenses.GnuGeneralPublicLicense20; |
|
| 27 | +import de.psdev.licensesdialog.licenses.GnuGeneralPublicLicense30; |
|
| 28 | +import de.psdev.licensesdialog.licenses.GnuLesserGeneralPublicLicense21; |
|
| 29 | +import de.psdev.licensesdialog.licenses.GnuLesserGeneralPublicLicense3; |
|
| 30 | +import de.psdev.licensesdialog.licenses.ISCLicense; |
|
| 31 | +import de.psdev.licensesdialog.licenses.License; |
|
| 32 | +import de.psdev.licensesdialog.licenses.MITLicense; |
|
| 33 | + |
|
| 34 | +public final class LicenseResolver { |
|
| 35 | + |
|
| 36 | + private static final int INITIAL_LICENSES_COUNT = 4; |
|
| 37 | + private static final Map<String, License> sLicenses = new HashMap<String, License>(INITIAL_LICENSES_COUNT); |
|
| 38 | + |
|
| 39 | + static { |
|
| 40 | + registerDefaultLicenses(); |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + static void registerDefaultLicenses() { |
|
| 44 | + sLicenses.clear(); |
|
| 45 | + registerLicense(new ApacheSoftwareLicense20()); |
|
| 46 | + registerLicense(new BSD2ClauseLicense()); |
|
| 47 | + registerLicense(new BSD3ClauseLicense()); |
|
| 48 | + registerLicense(new ISCLicense()); |
|
| 49 | + registerLicense(new MITLicense()); |
|
| 50 | + registerLicense(new GnuLesserGeneralPublicLicense21()); |
|
| 51 | + registerLicense(new GnuLesserGeneralPublicLicense3()); |
|
| 52 | + registerLicense(new CreativeCommonsAttributionNoDerivs30Unported()); |
|
| 53 | + registerLicense(new GnuGeneralPublicLicense30()); |
|
| 54 | + registerLicense(new GnuGeneralPublicLicense20()); |
|
| 55 | + } |
|
| 56 | + |
|
| 57 | + /** |
|
| 58 | + * Register an additional license. |
|
| 59 | + * |
|
| 60 | + * @param license the license to register |
|
| 61 | + */ |
|
| 62 | + public static void registerLicense(final License license) { |
|
| 63 | + sLicenses.put(license.getName(), license); |
|
| 64 | + } |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * Get a license by name |
|
| 68 | + * |
|
| 69 | + * @param license license name |
|
| 70 | + * @return License |
|
| 71 | + * @throws java.lang.IllegalStateException when unknown license is requested |
|
| 72 | + */ |
|
| 73 | + public static License read(final String license) { |
|
| 74 | + final String trimmedLicense = license.trim(); |
|
| 75 | + if (sLicenses.containsKey(trimmedLicense)) { |
|
| 76 | + return sLicenses.get(trimmedLicense); |
|
| 77 | + } else { |
|
| 78 | + throw new IllegalStateException(String.format("no such license available: %s, did you forget to register it?", trimmedLicense)); |
|
| 79 | + } |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + private LicenseResolver() { |
|
| 83 | + } |
|
| 84 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/LicensesDialog.java
| ... | ... | @@ -0,0 +1,328 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog; |
|
| 18 | + |
|
| 19 | +import android.app.AlertDialog; |
|
| 20 | +import android.app.Dialog; |
|
| 21 | +import android.content.Context; |
|
| 22 | +import android.content.DialogInterface; |
|
| 23 | +import android.content.res.Resources; |
|
| 24 | +import android.view.ContextThemeWrapper; |
|
| 25 | +import android.view.View; |
|
| 26 | +import android.webkit.WebView; |
|
| 27 | +import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20; |
|
| 28 | +import de.psdev.licensesdialog.model.Notice; |
|
| 29 | +import de.psdev.licensesdialog.model.Notices; |
|
| 30 | + |
|
| 31 | +import java.util.List; |
|
| 32 | + |
|
| 33 | +public class LicensesDialog { |
|
| 34 | + public static final Notice LICENSES_DIALOG_NOTICE = new Notice("LicensesDialog", "http://psdev.de/LicensesDialog", |
|
| 35 | + "Copyright 2013 Philip Schiffer", |
|
| 36 | + new ApacheSoftwareLicense20()); |
|
| 37 | + |
|
| 38 | + private final Context mContext; |
|
| 39 | + private final String mTitleText; |
|
| 40 | + private final String mLicensesText; |
|
| 41 | + private final String mCloseText; |
|
| 42 | + private final int mThemeResourceId; |
|
| 43 | + private final int mDividerColor; |
|
| 44 | + |
|
| 45 | + private DialogInterface.OnDismissListener mOnDismissListener; |
|
| 46 | + |
|
| 47 | + // ========================================================================================================================== |
|
| 48 | + // Constructor |
|
| 49 | + // ========================================================================================================================== |
|
| 50 | + |
|
| 51 | + private LicensesDialog(final Context context, final String licensesText, final String titleText, final String closeText, final int themeResourceId, |
|
| 52 | + final int dividerColor) { |
|
| 53 | + mContext = context; |
|
| 54 | + mTitleText = titleText; |
|
| 55 | + mLicensesText = licensesText; |
|
| 56 | + mCloseText = closeText; |
|
| 57 | + mThemeResourceId = themeResourceId; |
|
| 58 | + mDividerColor = dividerColor; |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + // ========================================================================================================================== |
|
| 62 | + // Public API |
|
| 63 | + // ========================================================================================================================== |
|
| 64 | + |
|
| 65 | + public LicensesDialog setOnDismissListener(final DialogInterface.OnDismissListener onDismissListener) { |
|
| 66 | + mOnDismissListener = onDismissListener; |
|
| 67 | + return this; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + public Dialog create() { |
|
| 71 | + //Get resources |
|
| 72 | + final WebView webView = new WebView(mContext); |
|
| 73 | + webView.loadDataWithBaseURL(null, mLicensesText, "text/html", "utf-8", null); |
|
| 74 | + final AlertDialog.Builder builder; |
|
| 75 | + if (mThemeResourceId != 0) { |
|
| 76 | + builder = new AlertDialog.Builder(new ContextThemeWrapper(mContext, mThemeResourceId)); |
|
| 77 | + } else { |
|
| 78 | + builder = new AlertDialog.Builder(mContext); |
|
| 79 | + } |
|
| 80 | + builder.setTitle(mTitleText) |
|
| 81 | + .setView(webView) |
|
| 82 | + .setPositiveButton(mCloseText, new Dialog.OnClickListener() { |
|
| 83 | + public void onClick(final DialogInterface dialogInterface, final int i) { |
|
| 84 | + dialogInterface.dismiss(); |
|
| 85 | + } |
|
| 86 | + }); |
|
| 87 | + final AlertDialog dialog = builder.create(); |
|
| 88 | + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
|
| 89 | + @Override |
|
| 90 | + public void onDismiss(final DialogInterface dialog) { |
|
| 91 | + if (mOnDismissListener != null) { |
|
| 92 | + mOnDismissListener.onDismiss(dialog); |
|
| 93 | + } |
|
| 94 | + } |
|
| 95 | + }); |
|
| 96 | + dialog.setOnShowListener(new DialogInterface.OnShowListener() { |
|
| 97 | + @Override |
|
| 98 | + public void onShow(final DialogInterface dialogInterface) { |
|
| 99 | + if (mDividerColor != 0) { |
|
| 100 | + // Set title divider color |
|
| 101 | + final int titleDividerId = mContext.getResources().getIdentifier("titleDivider", "id", "android"); |
|
| 102 | + final View titleDivider = dialog.findViewById(titleDividerId); |
|
| 103 | + if (titleDivider != null) { |
|
| 104 | + titleDivider.setBackgroundColor(mDividerColor); |
|
| 105 | + } |
|
| 106 | + } |
|
| 107 | + } |
|
| 108 | + }); |
|
| 109 | + return dialog; |
|
| 110 | + } |
|
| 111 | + |
|
| 112 | + public Dialog createAppCompat() { |
|
| 113 | + //Get resources |
|
| 114 | + final WebView webView = new WebView(mContext); |
|
| 115 | + webView.loadDataWithBaseURL(null, mLicensesText, "text/html", "utf-8", null); |
|
| 116 | + final AlertDialog.Builder builder; |
|
| 117 | + if (mThemeResourceId != 0) { |
|
| 118 | + builder = new AlertDialog.Builder(new ContextThemeWrapper(mContext, mThemeResourceId)); |
|
| 119 | + } else { |
|
| 120 | + builder = new AlertDialog.Builder(mContext); |
|
| 121 | + } |
|
| 122 | + builder.setTitle(mTitleText) |
|
| 123 | + .setView(webView) |
|
| 124 | + .setPositiveButton(mCloseText, new Dialog.OnClickListener() { |
|
| 125 | + public void onClick(final DialogInterface dialogInterface, final int i) { |
|
| 126 | + dialogInterface.dismiss(); |
|
| 127 | + } |
|
| 128 | + }); |
|
| 129 | + final AlertDialog dialog = builder.create(); |
|
| 130 | + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
|
| 131 | + @Override |
|
| 132 | + public void onDismiss(final DialogInterface dialog) { |
|
| 133 | + if (mOnDismissListener != null) { |
|
| 134 | + mOnDismissListener.onDismiss(dialog); |
|
| 135 | + } |
|
| 136 | + } |
|
| 137 | + }); |
|
| 138 | + dialog.setOnShowListener(new DialogInterface.OnShowListener() { |
|
| 139 | + @Override |
|
| 140 | + public void onShow(final DialogInterface dialogInterface) { |
|
| 141 | + if (mDividerColor != 0) { |
|
| 142 | + // Set title divider color |
|
| 143 | + final int titleDividerId = mContext.getResources().getIdentifier("titleDivider", "id", "android"); |
|
| 144 | + final View titleDivider = dialog.findViewById(titleDividerId); |
|
| 145 | + if (titleDivider != null) { |
|
| 146 | + titleDivider.setBackgroundColor(mDividerColor); |
|
| 147 | + } |
|
| 148 | + } |
|
| 149 | + } |
|
| 150 | + }); |
|
| 151 | + return dialog; |
|
| 152 | + } |
|
| 153 | + |
|
| 154 | + public Dialog show() { |
|
| 155 | + final Dialog dialog = create(); |
|
| 156 | + dialog.show(); |
|
| 157 | + return dialog; |
|
| 158 | + } |
|
| 159 | + |
|
| 160 | + public Dialog showAppCompat() { |
|
| 161 | + final Dialog dialog = createAppCompat(); |
|
| 162 | + dialog.show(); |
|
| 163 | + return dialog; |
|
| 164 | + } |
|
| 165 | + |
|
| 166 | + // ========================================================================================================================== |
|
| 167 | + // Private API |
|
| 168 | + // ========================================================================================================================== |
|
| 169 | + |
|
| 170 | + private static Notices getNotices(final Context context, final int rawNoticesResourceId) { |
|
| 171 | + try { |
|
| 172 | + final Resources resources = context.getResources(); |
|
| 173 | + if ("raw".equals(resources.getResourceTypeName(rawNoticesResourceId))) { |
|
| 174 | + final Notices notices = NoticesXmlParser.parse(resources.openRawResource(rawNoticesResourceId)); |
|
| 175 | + return notices; |
|
| 176 | + } else { |
|
| 177 | + throw new IllegalStateException("not a raw resource"); |
|
| 178 | + } |
|
| 179 | + } catch (final Exception e) { |
|
| 180 | + throw new IllegalStateException(e); |
|
| 181 | + } |
|
| 182 | + } |
|
| 183 | + |
|
| 184 | + private static String getLicensesText(final Context context, final Notices notices, final boolean showFullLicenseText, |
|
| 185 | + final boolean includeOwnLicense, final String style) { |
|
| 186 | + try { |
|
| 187 | + if (includeOwnLicense) { |
|
| 188 | + final List<Notice> noticeList = notices.getNotices(); |
|
| 189 | + noticeList.add(LICENSES_DIALOG_NOTICE); |
|
| 190 | + } |
|
| 191 | + return NoticesHtmlBuilder.create(context).setShowFullLicenseText(showFullLicenseText).setNotices(notices).setStyle(style).build(); |
|
| 192 | + } catch (final Exception e) { |
|
| 193 | + throw new IllegalStateException(e); |
|
| 194 | + } |
|
| 195 | + } |
|
| 196 | + |
|
| 197 | + private static Notices getSingleNoticeNotices(final Notice notice) { |
|
| 198 | + final Notices notices = new Notices(); |
|
| 199 | + notices.addNotice(notice); |
|
| 200 | + return notices; |
|
| 201 | + } |
|
| 202 | + |
|
| 203 | + // ========================================================================================================================== |
|
| 204 | + // Inner classes |
|
| 205 | + // ========================================================================================================================== |
|
| 206 | + |
|
| 207 | + public static final class Builder { |
|
| 208 | + |
|
| 209 | + private final Context mContext; |
|
| 210 | + |
|
| 211 | + // Default values |
|
| 212 | + private String mTitleText; |
|
| 213 | + private String mCloseText; |
|
| 214 | + private Integer mRawNoticesId; |
|
| 215 | + private Notices mNotices; |
|
| 216 | + private String mNoticesText; |
|
| 217 | + private String mNoticesStyle; |
|
| 218 | + private boolean mShowFullLicenseText; |
|
| 219 | + private boolean mIncludeOwnLicense; |
|
| 220 | + private int mThemeResourceId; |
|
| 221 | + private int mDividerColor; |
|
| 222 | + |
|
| 223 | + public Builder(final Context context) { |
|
| 224 | + mContext = context; |
|
| 225 | + mTitleText = context.getString(R.string.notices_title); |
|
| 226 | + mCloseText = context.getString(R.string.notices_close); |
|
| 227 | + mNoticesStyle = context.getString(R.string.notices_default_style); |
|
| 228 | + mShowFullLicenseText = false; |
|
| 229 | + mIncludeOwnLicense = false; |
|
| 230 | + mThemeResourceId = 0; |
|
| 231 | + mDividerColor = 0; |
|
| 232 | + } |
|
| 233 | + |
|
| 234 | + public Builder setTitle(final int titleId) { |
|
| 235 | + mTitleText = mContext.getString(titleId); |
|
| 236 | + return this; |
|
| 237 | + } |
|
| 238 | + |
|
| 239 | + public Builder setTitle(final String title) { |
|
| 240 | + mTitleText = title; |
|
| 241 | + return this; |
|
| 242 | + } |
|
| 243 | + |
|
| 244 | + public Builder setCloseText(final int closeId) { |
|
| 245 | + mCloseText = mContext.getString(closeId); |
|
| 246 | + return this; |
|
| 247 | + } |
|
| 248 | + |
|
| 249 | + public Builder setCloseText(final String closeText) { |
|
| 250 | + mCloseText = closeText; |
|
| 251 | + return this; |
|
| 252 | + } |
|
| 253 | + |
|
| 254 | + public Builder setNotices(final int rawNoticesId) { |
|
| 255 | + mRawNoticesId = rawNoticesId; |
|
| 256 | + mNotices = null; |
|
| 257 | + return this; |
|
| 258 | + } |
|
| 259 | + |
|
| 260 | + public Builder setNotices(final Notices notices) { |
|
| 261 | + mNotices = notices; |
|
| 262 | + mRawNoticesId = null; |
|
| 263 | + return this; |
|
| 264 | + } |
|
| 265 | + |
|
| 266 | + public Builder setNotices(final Notice notice) { |
|
| 267 | + return setNotices(getSingleNoticeNotices(notice)); |
|
| 268 | + } |
|
| 269 | + |
|
| 270 | + Builder setNotices(final String notices) { |
|
| 271 | + mNotices = null; |
|
| 272 | + mRawNoticesId = null; |
|
| 273 | + mNoticesText = notices; |
|
| 274 | + return this; |
|
| 275 | + } |
|
| 276 | + |
|
| 277 | + public Builder setNoticesCssStyle(final int cssStyleTextId) { |
|
| 278 | + mNoticesStyle = mContext.getString(cssStyleTextId); |
|
| 279 | + return this; |
|
| 280 | + } |
|
| 281 | + |
|
| 282 | + public Builder setNoticesCssStyle(final String cssStyleText) { |
|
| 283 | + mNoticesStyle = cssStyleText; |
|
| 284 | + return this; |
|
| 285 | + } |
|
| 286 | + |
|
| 287 | + public Builder setShowFullLicenseText(final boolean showFullLicenseText) { |
|
| 288 | + mShowFullLicenseText = showFullLicenseText; |
|
| 289 | + return this; |
|
| 290 | + } |
|
| 291 | + |
|
| 292 | + public Builder setIncludeOwnLicense(final boolean includeOwnLicense) { |
|
| 293 | + mIncludeOwnLicense = includeOwnLicense; |
|
| 294 | + return this; |
|
| 295 | + } |
|
| 296 | + |
|
| 297 | + public Builder setThemeResourceId(final int themeResourceId) { |
|
| 298 | + mThemeResourceId = themeResourceId; |
|
| 299 | + return this; |
|
| 300 | + } |
|
| 301 | + |
|
| 302 | + public Builder setDividerColor(final int dividerColor) { |
|
| 303 | + mDividerColor = dividerColor; |
|
| 304 | + return this; |
|
| 305 | + } |
|
| 306 | + |
|
| 307 | + public Builder setDividerColorId(final int dividerColorId) { |
|
| 308 | + mDividerColor = mContext.getResources().getColor(dividerColorId); |
|
| 309 | + return this; |
|
| 310 | + } |
|
| 311 | + |
|
| 312 | + public LicensesDialog build() { |
|
| 313 | + final String licensesText; |
|
| 314 | + if (mNotices != null) { |
|
| 315 | + licensesText = getLicensesText(mContext, mNotices, mShowFullLicenseText, mIncludeOwnLicense, mNoticesStyle); |
|
| 316 | + } else if (mRawNoticesId != null) { |
|
| 317 | + licensesText = getLicensesText(mContext, getNotices(mContext, mRawNoticesId), mShowFullLicenseText, mIncludeOwnLicense, mNoticesStyle); |
|
| 318 | + } else if (mNoticesText != null) { |
|
| 319 | + licensesText = mNoticesText; |
|
| 320 | + } else { |
|
| 321 | + throw new IllegalStateException("Notices have to be provided, see setNotices"); |
|
| 322 | + } |
|
| 323 | + |
|
| 324 | + return new LicensesDialog(mContext, licensesText, mTitleText, mCloseText, mThemeResourceId, mDividerColor); |
|
| 325 | + } |
|
| 326 | + |
|
| 327 | + } |
|
| 328 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/LicensesDialogFragment.java
| ... | ... | @@ -0,0 +1,321 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog; |
|
| 18 | + |
|
| 19 | +import android.app.Dialog; |
|
| 20 | +import android.content.Context; |
|
| 21 | +import android.content.DialogInterface; |
|
| 22 | +import android.content.res.Resources; |
|
| 23 | +import android.os.Build; |
|
| 24 | +import android.os.Bundle; |
|
| 25 | +import android.support.annotation.ColorRes; |
|
| 26 | +import android.support.annotation.NonNull; |
|
| 27 | +import android.support.annotation.RawRes; |
|
| 28 | +import android.support.annotation.StyleRes; |
|
| 29 | +import android.support.v4.app.DialogFragment; |
|
| 30 | +import de.psdev.licensesdialog.model.Notice; |
|
| 31 | +import de.psdev.licensesdialog.model.Notices; |
|
| 32 | + |
|
| 33 | +public class LicensesDialogFragment extends DialogFragment { |
|
| 34 | + |
|
| 35 | + private static final String ARGUMENT_NOTICES = "ARGUMENT_NOTICES"; |
|
| 36 | + private static final String ARGUMENT_NOTICES_XML_ID = "ARGUMENT_NOTICES_XML_ID"; |
|
| 37 | + private static final String ARGUMENT_INCLUDE_OWN_LICENSE = "ARGUMENT_INCLUDE_OWN_LICENSE"; |
|
| 38 | + private static final String ARGUMENT_FULL_LICENSE_TEXT = "ARGUMENT_FULL_LICENSE_TEXT"; |
|
| 39 | + private static final String ARGUMENT_THEME_XML_ID = "ARGUMENT_THEME_XML_ID"; |
|
| 40 | + private static final String ARGUMENT_DIVIDER_COLOR = "ARGUMENT_DIVIDER_COLOR"; |
|
| 41 | + private static final String ARGUMENT_USE_APPCOMPAT = "ARGUMENT_USE_APPCOMPAT"; |
|
| 42 | + private static final String STATE_TITLE_TEXT = "title_text"; |
|
| 43 | + private static final String STATE_LICENSES_TEXT = "licenses_text"; |
|
| 44 | + private static final String STATE_CLOSE_TEXT = "close_text"; |
|
| 45 | + private static final String STATE_THEME_XML_ID = "theme_xml_id"; |
|
| 46 | + private static final String STATE_DIVIDER_COLOR = "divider_color"; |
|
| 47 | + |
|
| 48 | + // |
|
| 49 | + private String mTitleText; |
|
| 50 | + private String mCloseButtonText; |
|
| 51 | + private String mLicensesText; |
|
| 52 | + private int mThemeResourceId; |
|
| 53 | + private int mDividerColor; |
|
| 54 | + |
|
| 55 | + private DialogInterface.OnDismissListener mOnDismissListener; |
|
| 56 | + |
|
| 57 | + // ========================================================================================================================== |
|
| 58 | + // Factory |
|
| 59 | + // ========================================================================================================================== |
|
| 60 | + |
|
| 61 | + private static LicensesDialogFragment newInstance(final Notices notices, |
|
| 62 | + final boolean showFullLicenseText, |
|
| 63 | + final boolean includeOwnLicense, |
|
| 64 | + final int themeResourceId, |
|
| 65 | + final int dividerColor, |
|
| 66 | + final boolean useAppCompat) { |
|
| 67 | + final LicensesDialogFragment licensesDialogFragment = new LicensesDialogFragment(); |
|
| 68 | + final Bundle args = new Bundle(); |
|
| 69 | + args.putParcelable(ARGUMENT_NOTICES, notices); |
|
| 70 | + args.putBoolean(ARGUMENT_FULL_LICENSE_TEXT, showFullLicenseText); |
|
| 71 | + args.putBoolean(ARGUMENT_INCLUDE_OWN_LICENSE, includeOwnLicense); |
|
| 72 | + args.putInt(ARGUMENT_THEME_XML_ID, themeResourceId); |
|
| 73 | + args.putInt(ARGUMENT_DIVIDER_COLOR, dividerColor); |
|
| 74 | + args.putBoolean(ARGUMENT_USE_APPCOMPAT, useAppCompat); |
|
| 75 | + licensesDialogFragment.setArguments(args); |
|
| 76 | + return licensesDialogFragment; |
|
| 77 | + } |
|
| 78 | + |
|
| 79 | + private static LicensesDialogFragment newInstance(final int rawNoticesResourceId, |
|
| 80 | + final boolean showFullLicenseText, |
|
| 81 | + final boolean includeOwnLicense, |
|
| 82 | + final int themeResourceId, |
|
| 83 | + final int dividerColor, |
|
| 84 | + final boolean useAppCompat) { |
|
| 85 | + final LicensesDialogFragment licensesDialogFragment = new LicensesDialogFragment(); |
|
| 86 | + final Bundle args = new Bundle(); |
|
| 87 | + args.putInt(ARGUMENT_NOTICES_XML_ID, rawNoticesResourceId); |
|
| 88 | + args.putBoolean(ARGUMENT_FULL_LICENSE_TEXT, showFullLicenseText); |
|
| 89 | + args.putBoolean(ARGUMENT_INCLUDE_OWN_LICENSE, includeOwnLicense); |
|
| 90 | + args.putInt(ARGUMENT_THEME_XML_ID, themeResourceId); |
|
| 91 | + args.putInt(ARGUMENT_DIVIDER_COLOR, dividerColor); |
|
| 92 | + args.putBoolean(ARGUMENT_USE_APPCOMPAT, useAppCompat); |
|
| 93 | + licensesDialogFragment.setArguments(args); |
|
| 94 | + return licensesDialogFragment; |
|
| 95 | + } |
|
| 96 | + |
|
| 97 | + // ========================================================================================================================== |
|
| 98 | + // Constructor |
|
| 99 | + // ========================================================================================================================== |
|
| 100 | + |
|
| 101 | + public LicensesDialogFragment() { |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + // ========================================================================================================================== |
|
| 105 | + // Android Lifecycle |
|
| 106 | + // ========================================================================================================================== |
|
| 107 | + |
|
| 108 | + @Override |
|
| 109 | + public void onCreate(final Bundle savedInstanceState) { |
|
| 110 | + super.onCreate(savedInstanceState); |
|
| 111 | + final Resources resources = getResources(); |
|
| 112 | + |
|
| 113 | + if (savedInstanceState != null) { |
|
| 114 | + mTitleText = savedInstanceState.getString(STATE_TITLE_TEXT); |
|
| 115 | + mLicensesText = savedInstanceState.getString(STATE_LICENSES_TEXT); |
|
| 116 | + mCloseButtonText = savedInstanceState.getString(STATE_CLOSE_TEXT); |
|
| 117 | + if (savedInstanceState.containsKey(STATE_THEME_XML_ID)) { |
|
| 118 | + mThemeResourceId = savedInstanceState.getInt(STATE_THEME_XML_ID); |
|
| 119 | + } |
|
| 120 | + if (savedInstanceState.containsKey(STATE_DIVIDER_COLOR)) { |
|
| 121 | + mDividerColor = savedInstanceState.getInt(STATE_DIVIDER_COLOR); |
|
| 122 | + } |
|
| 123 | + } else { |
|
| 124 | + mTitleText = resources.getString(R.string.notices_title); |
|
| 125 | + mCloseButtonText = resources.getString(R.string.notices_close); |
|
| 126 | + try { |
|
| 127 | + final Notices notices; |
|
| 128 | + final Bundle arguments = getArguments(); |
|
| 129 | + if (arguments != null) { |
|
| 130 | + if (arguments.containsKey(ARGUMENT_NOTICES_XML_ID)) { |
|
| 131 | + notices = NoticesXmlParser.parse(resources.openRawResource(getNoticesXmlResourceId())); |
|
| 132 | + } else if (arguments.containsKey(ARGUMENT_NOTICES)) { |
|
| 133 | + notices = arguments.getParcelable(ARGUMENT_NOTICES); |
|
| 134 | + } else { |
|
| 135 | + throw new IllegalStateException("Missing ARGUMENT_NOTICES_XML_ID / ARGUMENT_NOTICES"); |
|
| 136 | + } |
|
| 137 | + if (arguments.getBoolean(ARGUMENT_INCLUDE_OWN_LICENSE, false)) { |
|
| 138 | + notices.getNotices().add(LicensesDialog.LICENSES_DIALOG_NOTICE); |
|
| 139 | + } |
|
| 140 | + final boolean showFullLicenseText = arguments.getBoolean(ARGUMENT_FULL_LICENSE_TEXT, false); |
|
| 141 | + if (arguments.containsKey(ARGUMENT_THEME_XML_ID)) { |
|
| 142 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
| 143 | + mThemeResourceId = arguments.getInt(ARGUMENT_THEME_XML_ID, android.R.style.Theme_DeviceDefault_Light_Dialog); |
|
| 144 | + } else { |
|
| 145 | + mThemeResourceId = arguments.getInt(ARGUMENT_THEME_XML_ID); |
|
| 146 | + } |
|
| 147 | + } |
|
| 148 | + if (arguments.containsKey(ARGUMENT_DIVIDER_COLOR)) { |
|
| 149 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
| 150 | + mDividerColor = arguments.getInt(ARGUMENT_DIVIDER_COLOR, android.R.color.holo_blue_light); |
|
| 151 | + } else { |
|
| 152 | + mDividerColor = arguments.getInt(ARGUMENT_DIVIDER_COLOR); |
|
| 153 | + } |
|
| 154 | + } |
|
| 155 | + mLicensesText = NoticesHtmlBuilder.create(getActivity()).setNotices(notices).setShowFullLicenseText(showFullLicenseText).build(); |
|
| 156 | + } else { |
|
| 157 | + throw new IllegalStateException("Missing arguments"); |
|
| 158 | + } |
|
| 159 | + } catch (final Exception e) { |
|
| 160 | + throw new IllegalStateException(e); |
|
| 161 | + } |
|
| 162 | + } |
|
| 163 | + } |
|
| 164 | + |
|
| 165 | + @Override |
|
| 166 | + public void onSaveInstanceState(final Bundle outState) { |
|
| 167 | + super.onSaveInstanceState(outState); |
|
| 168 | + outState.putString(STATE_TITLE_TEXT, mTitleText); |
|
| 169 | + outState.putString(STATE_LICENSES_TEXT, mLicensesText); |
|
| 170 | + outState.putString(STATE_CLOSE_TEXT, mCloseButtonText); |
|
| 171 | + if (mThemeResourceId != 0) { |
|
| 172 | + outState.putInt(STATE_THEME_XML_ID, mThemeResourceId); |
|
| 173 | + } |
|
| 174 | + if (mDividerColor != 0) { |
|
| 175 | + outState.putInt(STATE_DIVIDER_COLOR, mDividerColor); |
|
| 176 | + } |
|
| 177 | + } |
|
| 178 | + |
|
| 179 | + @Override |
|
| 180 | + public Dialog onCreateDialog(final Bundle savedInstanceState) { |
|
| 181 | + final LicensesDialog.Builder builder = new LicensesDialog.Builder(getActivity()) |
|
| 182 | + .setNotices(mLicensesText) |
|
| 183 | + .setTitle(mTitleText).setCloseText(mCloseButtonText) |
|
| 184 | + .setThemeResourceId(mThemeResourceId).setDividerColor(mDividerColor); |
|
| 185 | + final LicensesDialog licensesDialog = builder.build(); |
|
| 186 | + if (getArguments().getBoolean(ARGUMENT_USE_APPCOMPAT, false)) { |
|
| 187 | + return licensesDialog.createAppCompat(); |
|
| 188 | + } else { |
|
| 189 | + return licensesDialog.create(); |
|
| 190 | + } |
|
| 191 | + } |
|
| 192 | + |
|
| 193 | + @Override |
|
| 194 | + public void onDismiss(final DialogInterface dialog) { |
|
| 195 | + super.onDismiss(dialog); |
|
| 196 | + if (mOnDismissListener != null) { |
|
| 197 | + mOnDismissListener.onDismiss(dialog); |
|
| 198 | + } |
|
| 199 | + } |
|
| 200 | + |
|
| 201 | + // ========================================================================================================================== |
|
| 202 | + // Public API |
|
| 203 | + // ========================================================================================================================== |
|
| 204 | + |
|
| 205 | + public DialogInterface.OnDismissListener getOnDismissListener() { |
|
| 206 | + return mOnDismissListener; |
|
| 207 | + } |
|
| 208 | + |
|
| 209 | + public void setOnDismissListener(final DialogInterface.OnDismissListener onDismissListener) { |
|
| 210 | + mOnDismissListener = onDismissListener; |
|
| 211 | + } |
|
| 212 | + |
|
| 213 | + // ========================================================================================================================== |
|
| 214 | + // Private API |
|
| 215 | + // ========================================================================================================================== |
|
| 216 | + |
|
| 217 | + private int getNoticesXmlResourceId() { |
|
| 218 | + int resourceId = R.raw.notices; |
|
| 219 | + final Bundle arguments = getArguments(); |
|
| 220 | + if (arguments != null && arguments.containsKey(ARGUMENT_NOTICES_XML_ID)) { |
|
| 221 | + resourceId = arguments.getInt(ARGUMENT_NOTICES_XML_ID); |
|
| 222 | + if (!"raw".equalsIgnoreCase(getResources().getResourceTypeName(resourceId))) { |
|
| 223 | + throw new IllegalStateException("not a raw resource"); |
|
| 224 | + } |
|
| 225 | + } |
|
| 226 | + |
|
| 227 | + return resourceId; |
|
| 228 | + } |
|
| 229 | + |
|
| 230 | + // ========================================================================================================================== |
|
| 231 | + // Inner classes |
|
| 232 | + // ========================================================================================================================== |
|
| 233 | + |
|
| 234 | + public static class Builder { |
|
| 235 | + |
|
| 236 | + private final Context mContext; |
|
| 237 | + private Notices mNotices; |
|
| 238 | + private Integer mRawNoticesResourceId; |
|
| 239 | + private boolean mShowFullLicenseText; |
|
| 240 | + private boolean mIncludeOwnLicense; |
|
| 241 | + private int mThemeResourceId; |
|
| 242 | + private int mDividerColor; |
|
| 243 | + private boolean mUseAppCompat; |
|
| 244 | + |
|
| 245 | + // ========================================================================================================================== |
|
| 246 | + // Constructor |
|
| 247 | + // ========================================================================================================================== |
|
| 248 | + |
|
| 249 | + public Builder(@NonNull final Context context) { |
|
| 250 | + mContext = context; |
|
| 251 | + // Set default values |
|
| 252 | + mShowFullLicenseText = false; |
|
| 253 | + mIncludeOwnLicense = true; |
|
| 254 | + mThemeResourceId = 0; |
|
| 255 | + mDividerColor = 0; |
|
| 256 | + mUseAppCompat = false; |
|
| 257 | + } |
|
| 258 | + |
|
| 259 | + // ========================================================================================================================== |
|
| 260 | + // Public API |
|
| 261 | + // ========================================================================================================================== |
|
| 262 | + |
|
| 263 | + public Builder setNotice(final Notice notice) { |
|
| 264 | + mNotices = new Notices(); |
|
| 265 | + mNotices.addNotice(notice); |
|
| 266 | + return this; |
|
| 267 | + } |
|
| 268 | + |
|
| 269 | + public Builder setNotices(final Notices notices) { |
|
| 270 | + mNotices = notices; |
|
| 271 | + return this; |
|
| 272 | + } |
|
| 273 | + |
|
| 274 | + public Builder setNotices(@RawRes final int rawNoticesResourceId) throws Exception { |
|
| 275 | + mRawNoticesResourceId = rawNoticesResourceId; |
|
| 276 | + return this; |
|
| 277 | + } |
|
| 278 | + |
|
| 279 | + public Builder setShowFullLicenseText(final boolean showFullLicenseText) { |
|
| 280 | + mShowFullLicenseText = showFullLicenseText; |
|
| 281 | + return this; |
|
| 282 | + } |
|
| 283 | + |
|
| 284 | + public Builder setIncludeOwnLicense(final boolean includeOwnLicense) { |
|
| 285 | + mIncludeOwnLicense = includeOwnLicense; |
|
| 286 | + return this; |
|
| 287 | + } |
|
| 288 | + |
|
| 289 | + public Builder setThemeResourceId(@StyleRes final int themeResourceId) { |
|
| 290 | + mThemeResourceId = themeResourceId; |
|
| 291 | + return this; |
|
| 292 | + } |
|
| 293 | + |
|
| 294 | + public Builder setDividerColorRes(@ColorRes final int dividerColor) { |
|
| 295 | + mDividerColor = mContext.getResources().getColor(dividerColor); |
|
| 296 | + return this; |
|
| 297 | + } |
|
| 298 | + |
|
| 299 | + public Builder setDividerColor(final int dividerColor) { |
|
| 300 | + mDividerColor = dividerColor; |
|
| 301 | + return this; |
|
| 302 | + } |
|
| 303 | + |
|
| 304 | + public Builder setUseAppCompat(final boolean useAppCompat) { |
|
| 305 | + mUseAppCompat = useAppCompat; |
|
| 306 | + return this; |
|
| 307 | + } |
|
| 308 | + |
|
| 309 | + public LicensesDialogFragment build() { |
|
| 310 | + if (mNotices != null) { |
|
| 311 | + return newInstance(mNotices, mShowFullLicenseText, mIncludeOwnLicense, mThemeResourceId, mDividerColor, mUseAppCompat); |
|
| 312 | + } else if (mRawNoticesResourceId != null) { |
|
| 313 | + return newInstance(mRawNoticesResourceId, mShowFullLicenseText, mIncludeOwnLicense, mThemeResourceId, mDividerColor, mUseAppCompat); |
|
| 314 | + } else { |
|
| 315 | + throw new IllegalStateException("Required parameter not set. You need to call setNotices."); |
|
| 316 | + } |
|
| 317 | + } |
|
| 318 | + |
|
| 319 | + } |
|
| 320 | + |
|
| 321 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/NoticesHtmlBuilder.java
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog; |
|
| 18 | + |
|
| 19 | +import java.util.HashMap; |
|
| 20 | +import java.util.Map; |
|
| 21 | + |
|
| 22 | +import android.content.Context; |
|
| 23 | +import de.psdev.licensesdialog.licenses.License; |
|
| 24 | +import de.psdev.licensesdialog.model.Notice; |
|
| 25 | +import de.psdev.licensesdialog.model.Notices; |
|
| 26 | + |
|
| 27 | +public final class NoticesHtmlBuilder { |
|
| 28 | + |
|
| 29 | + private final Context mContext; |
|
| 30 | + private final Map<License, String> mLicenseTextCache = new HashMap<License, String>(); |
|
| 31 | + private Notices mNotices; |
|
| 32 | + private Notice mNotice; |
|
| 33 | + private String mStyle; |
|
| 34 | + private boolean mShowFullLicenseText; |
|
| 35 | + |
|
| 36 | + public static NoticesHtmlBuilder create(final Context context) { |
|
| 37 | + return new NoticesHtmlBuilder(context); |
|
| 38 | + } |
|
| 39 | + |
|
| 40 | + private NoticesHtmlBuilder(final Context context) { |
|
| 41 | + mContext = context; |
|
| 42 | + mStyle = context.getResources().getString(R.string.notices_default_style); |
|
| 43 | + mShowFullLicenseText = false; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + public NoticesHtmlBuilder setNotices(final Notices notices) { |
|
| 47 | + mNotices = notices; |
|
| 48 | + mNotice = null; |
|
| 49 | + return this; |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | + public NoticesHtmlBuilder setNotice(final Notice notice) { |
|
| 53 | + mNotice = notice; |
|
| 54 | + mNotices = null; |
|
| 55 | + return this; |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + public NoticesHtmlBuilder setStyle(final String style) { |
|
| 59 | + mStyle = style; |
|
| 60 | + return this; |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + public NoticesHtmlBuilder setShowFullLicenseText(final boolean showFullLicenseText) { |
|
| 64 | + mShowFullLicenseText = showFullLicenseText; |
|
| 65 | + return this; |
|
| 66 | + } |
|
| 67 | + |
|
| 68 | + public String build() { |
|
| 69 | + final StringBuilder noticesHtmlBuilder = new StringBuilder(500); |
|
| 70 | + appendNoticesContainerStart(noticesHtmlBuilder); |
|
| 71 | + if (mNotice != null) { |
|
| 72 | + appendNoticeBlock(noticesHtmlBuilder, mNotice); |
|
| 73 | + } else if (mNotices != null) { |
|
| 74 | + for (final Notice notice : mNotices.getNotices()) { |
|
| 75 | + appendNoticeBlock(noticesHtmlBuilder, notice); |
|
| 76 | + } |
|
| 77 | + } else { |
|
| 78 | + throw new IllegalStateException("no notice(s) set"); |
|
| 79 | + } |
|
| 80 | + appendNoticesContainerEnd(noticesHtmlBuilder); |
|
| 81 | + return noticesHtmlBuilder.toString(); |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + // |
|
| 85 | + |
|
| 86 | + private void appendNoticesContainerStart(final StringBuilder noticesHtmlBuilder) { |
|
| 87 | + noticesHtmlBuilder.append("<!DOCTYPE html><html><head>") |
|
| 88 | + .append("<style type=\"text/css\">").append(mStyle).append("</style>") |
|
| 89 | + .append("</head><body>"); |
|
| 90 | + } |
|
| 91 | + |
|
| 92 | + private void appendNoticeBlock(final StringBuilder noticesHtmlBuilder, final Notice notice) { |
|
| 93 | + noticesHtmlBuilder.append("<ul><li>").append(notice.getName()); |
|
| 94 | + final String currentNoticeUrl = notice.getUrl(); |
|
| 95 | + if (currentNoticeUrl != null && currentNoticeUrl.length() > 0) { |
|
| 96 | + noticesHtmlBuilder.append(" (<a href=\"").append(currentNoticeUrl).append("\">").append(currentNoticeUrl).append("</a>)"); |
|
| 97 | + } |
|
| 98 | + noticesHtmlBuilder.append("</li></ul>"); |
|
| 99 | + noticesHtmlBuilder.append("<pre>"); |
|
| 100 | + final String copyright = notice.getCopyright(); |
|
| 101 | + if (copyright != null) { |
|
| 102 | + noticesHtmlBuilder.append(copyright).append("<br/><br/>"); |
|
| 103 | + } |
|
| 104 | + noticesHtmlBuilder.append(getLicenseText(notice.getLicense())).append("</pre>"); |
|
| 105 | + } |
|
| 106 | + |
|
| 107 | + private void appendNoticesContainerEnd(final StringBuilder noticesHtmlBuilder) { |
|
| 108 | + noticesHtmlBuilder.append("</body></html>"); |
|
| 109 | + } |
|
| 110 | + |
|
| 111 | + private String getLicenseText(final License license) { |
|
| 112 | + if (license != null) { |
|
| 113 | + if (!mLicenseTextCache.containsKey(license)) { |
|
| 114 | + mLicenseTextCache.put(license, mShowFullLicenseText ? license.getFullText(mContext) : license.getSummaryText(mContext)); |
|
| 115 | + } |
|
| 116 | + return mLicenseTextCache.get(license); |
|
| 117 | + } |
|
| 118 | + return ""; |
|
| 119 | + } |
|
| 120 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/NoticesXmlParser.java
| ... | ... | @@ -0,0 +1,127 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog; |
|
| 18 | + |
|
| 19 | +import java.io.IOException; |
|
| 20 | +import java.io.InputStream; |
|
| 21 | + |
|
| 22 | +import org.xmlpull.v1.XmlPullParser; |
|
| 23 | +import org.xmlpull.v1.XmlPullParserException; |
|
| 24 | + |
|
| 25 | +import android.util.Xml; |
|
| 26 | +import de.psdev.licensesdialog.licenses.License; |
|
| 27 | +import de.psdev.licensesdialog.model.Notice; |
|
| 28 | +import de.psdev.licensesdialog.model.Notices; |
|
| 29 | + |
|
| 30 | +public final class NoticesXmlParser { |
|
| 31 | + |
|
| 32 | + private NoticesXmlParser() { |
|
| 33 | + } |
|
| 34 | + |
|
| 35 | + public static Notices parse(final InputStream inputStream) throws Exception { |
|
| 36 | + try { |
|
| 37 | + final XmlPullParser parser = Xml.newPullParser(); |
|
| 38 | + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); |
|
| 39 | + parser.setInput(inputStream, null); |
|
| 40 | + parser.nextTag(); |
|
| 41 | + return parse(parser); |
|
| 42 | + } finally { |
|
| 43 | + inputStream.close(); |
|
| 44 | + } |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + private static Notices parse(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 48 | + final Notices notices = new Notices(); |
|
| 49 | + parser.require(XmlPullParser.START_TAG, null, "notices"); |
|
| 50 | + while (parser.next() != XmlPullParser.END_TAG) { |
|
| 51 | + if (parser.getEventType() != XmlPullParser.START_TAG) { |
|
| 52 | + continue; |
|
| 53 | + } |
|
| 54 | + final String name = parser.getName(); |
|
| 55 | + // Starts by looking for the entry tag |
|
| 56 | + if ("notice".equals(name)) { |
|
| 57 | + notices.addNotice(readNotice(parser)); |
|
| 58 | + } else { |
|
| 59 | + skip(parser); |
|
| 60 | + } |
|
| 61 | + } |
|
| 62 | + return notices; |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + private static Notice readNotice(final XmlPullParser parser) throws IOException, |
|
| 66 | + XmlPullParserException { |
|
| 67 | + parser.require(XmlPullParser.START_TAG, null, "notice"); |
|
| 68 | + String name = null; |
|
| 69 | + String url = null; |
|
| 70 | + String copyright = null; |
|
| 71 | + License license = null; |
|
| 72 | + while (parser.next() != XmlPullParser.END_TAG) { |
|
| 73 | + if (parser.getEventType() != XmlPullParser.START_TAG) { |
|
| 74 | + continue; |
|
| 75 | + } |
|
| 76 | + final String element = parser.getName(); |
|
| 77 | + if ("name".equals(element)) { |
|
| 78 | + name = readName(parser); |
|
| 79 | + } else if ("url".equals(element)) { |
|
| 80 | + url = readUrl(parser); |
|
| 81 | + } else if ("copyright".equals(element)) { |
|
| 82 | + copyright = readCopyright(parser); |
|
| 83 | + } else if ("license".equals(element)) { |
|
| 84 | + license = readLicense(parser); |
|
| 85 | + } else { |
|
| 86 | + skip(parser); |
|
| 87 | + } |
|
| 88 | + } |
|
| 89 | + return new Notice(name, url, copyright, license); |
|
| 90 | + } |
|
| 91 | + |
|
| 92 | + private static String readName(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 93 | + return readTag(parser, "name"); |
|
| 94 | + } |
|
| 95 | + |
|
| 96 | + private static String readUrl(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 97 | + return readTag(parser, "url"); |
|
| 98 | + } |
|
| 99 | + |
|
| 100 | + private static String readCopyright(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 101 | + return readTag(parser, "copyright"); |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + private static License readLicense(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 105 | + final String license = readTag(parser, "license"); |
|
| 106 | + return LicenseResolver.read(license); |
|
| 107 | + } |
|
| 108 | + |
|
| 109 | + private static String readTag(final XmlPullParser parser, final String tag) throws IOException, XmlPullParserException { |
|
| 110 | + parser.require(XmlPullParser.START_TAG, null, tag); |
|
| 111 | + final String title = readText(parser); |
|
| 112 | + parser.require(XmlPullParser.END_TAG, null, tag); |
|
| 113 | + return title; |
|
| 114 | + } |
|
| 115 | + |
|
| 116 | + private static String readText(final XmlPullParser parser) throws IOException, XmlPullParserException { |
|
| 117 | + String result = ""; |
|
| 118 | + if (parser.next() == XmlPullParser.TEXT) { |
|
| 119 | + result = parser.getText(); |
|
| 120 | + parser.nextTag(); |
|
| 121 | + } |
|
| 122 | + return result; |
|
| 123 | + } |
|
| 124 | + |
|
| 125 | + private static void skip(final XmlPullParser parser) { |
|
| 126 | + } |
|
| 127 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/ApacheSoftwareLicense20.java
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class ApacheSoftwareLicense20 extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = 4854000061990891449L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "Apache Software License 2.0"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.asl_20_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.asl_20_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return "2.0"; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://www.apache.org/licenses/LICENSE-2.0.txt"; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | + |
|
| 52 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/BSD2ClauseLicense.java
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class BSD2ClauseLicense extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = -5205394619884027401L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "BSD 2-Clause License"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.bsd2_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.bsd2_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return ""; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://opensource.org/licenses/BSD-2-Clause"; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/BSD3ClauseLicense.java
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class BSD3ClauseLicense extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = -5205394619884057474L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "BSD 3-Clause License"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.bsd3_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.bsd3_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return ""; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://opensource.org/licenses/BSD-3-Clause"; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/CreativeCommonsAttributionNoDerivs30Unported.java
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2014 Peter Heisig |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class CreativeCommonsAttributionNoDerivs30Unported extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = 1L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "Creative Commons Attribution-NoDerivs 3.0 Unported"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.ccand_30_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.ccand_30_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return "3.0"; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://creativecommons.org/licenses/by-nd/3.0/"; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/GnuGeneralPublicLicense20.java
| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2014 Shaleen Jain <shaleen.jain95@gmail.com> |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class GnuGeneralPublicLicense20 extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = 1L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "GNU General Public License 2.0"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.gpl_20_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.gpl_20_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return "2.0"; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://www.gnu.org/licenses/"; |
|
| 49 | + } |
|
| 50 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/GnuGeneralPublicLicense30.java
| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2014 Shaleen Jain <shaleen.jain95@gmail.com> |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class GnuGeneralPublicLicense30 extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = 1L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "GNU General Public License 3.0"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.gpl_30_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.gpl_30_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return "3.0"; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://www.gnu.org/licenses/"; |
|
| 49 | + } |
|
| 50 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/GnuLesserGeneralPublicLicense21.java
| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2014 Peter Heisig |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | + |
|
| 23 | +public class GnuLesserGeneralPublicLicense21 extends License { |
|
| 24 | + |
|
| 25 | + private static final long serialVersionUID = 1L; |
|
| 26 | + |
|
| 27 | + @Override |
|
| 28 | + public String getName() { |
|
| 29 | + return "GNU Lesser General Public License 2.1"; |
|
| 30 | + } |
|
| 31 | + |
|
| 32 | + @Override |
|
| 33 | + public String readSummaryTextFromResources(final Context context) { |
|
| 34 | + return getContent(context, R.raw.lgpl_21_summary); |
|
| 35 | + } |
|
| 36 | + |
|
| 37 | + @Override |
|
| 38 | + public String readFullTextFromResources(final Context context) { |
|
| 39 | + return getContent(context, R.raw.lgpl_21_full); |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + @Override |
|
| 43 | + public String getVersion() { |
|
| 44 | + return "2.1"; |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + @Override |
|
| 48 | + public String getUrl() { |
|
| 49 | + return "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"; |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/GnuLesserGeneralPublicLicense3.java
| ... | ... | @@ -0,0 +1,53 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2015 Jakob Schrettenbrunner |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | + |
|
| 21 | +import de.psdev.licensesdialog.R; |
|
| 22 | + |
|
| 23 | + |
|
| 24 | +public class GnuLesserGeneralPublicLicense3 extends License { |
|
| 25 | + |
|
| 26 | + private static final long serialVersionUID = 1L; |
|
| 27 | + |
|
| 28 | + @Override |
|
| 29 | + public String getName() { |
|
| 30 | + return "GNU Lesser General Public License 3"; |
|
| 31 | + } |
|
| 32 | + |
|
| 33 | + @Override |
|
| 34 | + public String readSummaryTextFromResources(final Context context) { |
|
| 35 | + return getContent(context, R.raw.lgpl_3_summary); |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + @Override |
|
| 39 | + public String readFullTextFromResources(final Context context) { |
|
| 40 | + return getContent(context, R.raw.lgpl_3_full); |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + @Override |
|
| 44 | + public String getVersion() { |
|
| 45 | + return "3"; |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | + @Override |
|
| 49 | + public String getUrl() { |
|
| 50 | + return "http://www.gnu.org/licenses/lgpl.html"; |
|
| 51 | + } |
|
| 52 | + |
|
| 53 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/ISCLicense.java
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class ISCLicense extends License { |
|
| 23 | + private static final long serialVersionUID = -4636435634132169860L; |
|
| 24 | + |
|
| 25 | + @Override |
|
| 26 | + public String getName() { |
|
| 27 | + return "ISC License"; |
|
| 28 | + } |
|
| 29 | + |
|
| 30 | + @Override |
|
| 31 | + public String readSummaryTextFromResources(final Context context) { |
|
| 32 | + return getContent(context, R.raw.isc_summary); |
|
| 33 | + } |
|
| 34 | + |
|
| 35 | + @Override |
|
| 36 | + public String readFullTextFromResources(final Context context) { |
|
| 37 | + return getContent(context, R.raw.isc_full); |
|
| 38 | + } |
|
| 39 | + |
|
| 40 | + @Override |
|
| 41 | + public String getVersion() { |
|
| 42 | + return ""; |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + @Override |
|
| 46 | + public String getUrl() { |
|
| 47 | + return "http://opensource.org/licenses/isc-license.txt"; |
|
| 48 | + } |
|
| 49 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/License.java
| ... | ... | @@ -0,0 +1,94 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | + |
|
| 21 | +import java.io.BufferedReader; |
|
| 22 | +import java.io.IOException; |
|
| 23 | +import java.io.InputStream; |
|
| 24 | +import java.io.InputStreamReader; |
|
| 25 | +import java.io.Serializable; |
|
| 26 | + |
|
| 27 | +public abstract class License implements Serializable { |
|
| 28 | + |
|
| 29 | + private static final long serialVersionUID = 3100331505738956523L; |
|
| 30 | + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); |
|
| 31 | + |
|
| 32 | + private String mCachedSummaryText = null; |
|
| 33 | + private String mCachedFullText = null; |
|
| 34 | + |
|
| 35 | + public abstract String getName(); |
|
| 36 | + |
|
| 37 | + public abstract String readSummaryTextFromResources(final Context context); |
|
| 38 | + |
|
| 39 | + public abstract String readFullTextFromResources(final Context context); |
|
| 40 | + |
|
| 41 | + public abstract String getVersion(); |
|
| 42 | + |
|
| 43 | + public abstract String getUrl(); |
|
| 44 | + |
|
| 45 | + // |
|
| 46 | + |
|
| 47 | + public final String getSummaryText(final Context context) { |
|
| 48 | + if (mCachedSummaryText == null) { |
|
| 49 | + mCachedSummaryText = readSummaryTextFromResources(context); |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | + return mCachedSummaryText; |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + public final String getFullText(final Context context) { |
|
| 56 | + if (mCachedFullText == null) { |
|
| 57 | + mCachedFullText = readFullTextFromResources(context); |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + return mCachedFullText; |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + protected String getContent(final Context context, final int contentResourceId) { |
|
| 64 | + BufferedReader reader = null; |
|
| 65 | + try { |
|
| 66 | + final InputStream inputStream = context.getResources().openRawResource(contentResourceId); |
|
| 67 | + if (inputStream != null) { |
|
| 68 | + reader = new BufferedReader(new InputStreamReader(inputStream)); |
|
| 69 | + return toString(reader); |
|
| 70 | + } |
|
| 71 | + throw new IOException("Error opening license file."); |
|
| 72 | + } catch (final IOException e) { |
|
| 73 | + throw new IllegalStateException(e); |
|
| 74 | + } finally { |
|
| 75 | + if (reader != null) { |
|
| 76 | + try { |
|
| 77 | + reader.close(); |
|
| 78 | + } catch (final IOException e) { |
|
| 79 | + // Don't care. |
|
| 80 | + } |
|
| 81 | + } |
|
| 82 | + } |
|
| 83 | + } |
|
| 84 | + |
|
| 85 | + private String toString(final BufferedReader reader) throws IOException { |
|
| 86 | + final StringBuilder builder = new StringBuilder(); |
|
| 87 | + String line = null; |
|
| 88 | + while ((line = reader.readLine()) != null) { |
|
| 89 | + builder.append(line).append(LINE_SEPARATOR); |
|
| 90 | + } |
|
| 91 | + return builder.toString(); |
|
| 92 | + } |
|
| 93 | + |
|
| 94 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/licenses/MITLicense.java
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.licenses; |
|
| 18 | + |
|
| 19 | +import android.content.Context; |
|
| 20 | +import de.psdev.licensesdialog.R; |
|
| 21 | + |
|
| 22 | +public class MITLicense extends License { |
|
| 23 | + |
|
| 24 | + private static final long serialVersionUID = 5673599951781482594L; |
|
| 25 | + |
|
| 26 | + @Override |
|
| 27 | + public String getName() { |
|
| 28 | + return "MIT License"; |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + @Override |
|
| 32 | + public String readSummaryTextFromResources(final Context context) { |
|
| 33 | + return getContent(context, R.raw.mit_summary); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + @Override |
|
| 37 | + public String readFullTextFromResources(final Context context) { |
|
| 38 | + return getContent(context, R.raw.mit_full); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + @Override |
|
| 42 | + public String getVersion() { |
|
| 43 | + return ""; |
|
| 44 | + } |
|
| 45 | + |
|
| 46 | + @Override |
|
| 47 | + public String getUrl() { |
|
| 48 | + return "http://opensource.org/licenses/MIT"; |
|
| 49 | + } |
|
| 50 | + |
|
| 51 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/model/Notice.java
| ... | ... | @@ -0,0 +1,107 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.model; |
|
| 18 | + |
|
| 19 | +import android.os.Parcel; |
|
| 20 | +import android.os.Parcelable; |
|
| 21 | +import de.psdev.licensesdialog.licenses.License; |
|
| 22 | + |
|
| 23 | +public class Notice implements Parcelable { |
|
| 24 | + |
|
| 25 | + private String mName; |
|
| 26 | + private String mUrl; |
|
| 27 | + private String mCopyright; |
|
| 28 | + private License mLicense; |
|
| 29 | + |
|
| 30 | + // |
|
| 31 | + |
|
| 32 | + public Notice() { |
|
| 33 | + } |
|
| 34 | + |
|
| 35 | + public Notice(final String name, final String url, final String copyright, final License license) { |
|
| 36 | + mName = name; |
|
| 37 | + mUrl = url; |
|
| 38 | + mCopyright = copyright; |
|
| 39 | + mLicense = license; |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + // Setter / Getter |
|
| 43 | + |
|
| 44 | + public void setName(final String name) { |
|
| 45 | + mName = name; |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | + public void setUrl(final String url) { |
|
| 49 | + mUrl = url; |
|
| 50 | + } |
|
| 51 | + |
|
| 52 | + public void setCopyright(final String copyright) { |
|
| 53 | + mCopyright = copyright; |
|
| 54 | + } |
|
| 55 | + |
|
| 56 | + public void setLicense(final License license) { |
|
| 57 | + mLicense = license; |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + public String getName() { |
|
| 61 | + return mName; |
|
| 62 | + } |
|
| 63 | + |
|
| 64 | + public String getUrl() { |
|
| 65 | + return mUrl; |
|
| 66 | + } |
|
| 67 | + |
|
| 68 | + public String getCopyright() { |
|
| 69 | + return mCopyright; |
|
| 70 | + } |
|
| 71 | + |
|
| 72 | + public License getLicense() { |
|
| 73 | + return mLicense; |
|
| 74 | + } |
|
| 75 | + |
|
| 76 | + // Parcelable |
|
| 77 | + |
|
| 78 | + @Override |
|
| 79 | + public int describeContents() { |
|
| 80 | + return 0; |
|
| 81 | + } |
|
| 82 | + |
|
| 83 | + @Override |
|
| 84 | + public void writeToParcel(final Parcel dest, final int flags) { |
|
| 85 | + dest.writeString(mName); |
|
| 86 | + dest.writeString(mUrl); |
|
| 87 | + dest.writeString(mCopyright); |
|
| 88 | + dest.writeSerializable(mLicense); |
|
| 89 | + } |
|
| 90 | + |
|
| 91 | + private Notice(final Parcel in) { |
|
| 92 | + mName = in.readString(); |
|
| 93 | + mUrl = in.readString(); |
|
| 94 | + mCopyright = in.readString(); |
|
| 95 | + mLicense = (License) in.readSerializable(); |
|
| 96 | + } |
|
| 97 | + |
|
| 98 | + public static Creator<Notice> CREATOR = new Creator<Notice>() { |
|
| 99 | + public Notice createFromParcel(final Parcel source) { |
|
| 100 | + return new Notice(source); |
|
| 101 | + } |
|
| 102 | + |
|
| 103 | + public Notice[] newArray(final int size) { |
|
| 104 | + return new Notice[size]; |
|
| 105 | + } |
|
| 106 | + }; |
|
| 107 | +} |
mobile/licensesdialog_lib/de.psdev.licensesdialog/src/de/psdev/licensesdialog/model/Notices.java
| ... | ... | @@ -0,0 +1,69 @@ |
| 1 | +/* |
|
| 2 | + * Copyright 2013 Philip Schiffer |
|
| 3 | + * |
|
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | + * you may not use this file except in compliance with the License. |
|
| 6 | + * You may obtain a copy of the License at |
|
| 7 | + * |
|
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | + * |
|
| 10 | + * Unless required by applicable law or agreed to in writing, software |
|
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | + * See the License for the specific language governing permissions and |
|
| 14 | + * limitations under the License. |
|
| 15 | + */ |
|
| 16 | + |
|
| 17 | +package de.psdev.licensesdialog.model; |
|
| 18 | + |
|
| 19 | +import java.util.ArrayList; |
|
| 20 | +import java.util.List; |
|
| 21 | + |
|
| 22 | +import android.os.Parcel; |
|
| 23 | +import android.os.Parcelable; |
|
| 24 | + |
|
| 25 | +public class Notices implements Parcelable { |
|
| 26 | + |
|
| 27 | + private final List<Notice> mNotices; |
|
| 28 | + |
|
| 29 | + public Notices() { |
|
| 30 | + mNotices = new ArrayList<Notice>(); |
|
| 31 | + } |
|
| 32 | + |
|
| 33 | + // Setter / Getter |
|
| 34 | + |
|
| 35 | + public void addNotice(final Notice notice) { |
|
| 36 | + mNotices.add(notice); |
|
| 37 | + } |
|
| 38 | + |
|
| 39 | + public List<Notice> getNotices() { |
|
| 40 | + return mNotices; |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + // Parcelable |
|
| 44 | + |
|
| 45 | + @Override |
|
| 46 | + public int describeContents() { |
|
| 47 | + return 0; |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + @Override |
|
| 51 | + public void writeToParcel(final Parcel dest, final int flags) { |
|
| 52 | + dest.writeList(this.mNotices); |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + protected Notices(final Parcel in) { |
|
| 56 | + mNotices = new ArrayList<Notice>(); |
|
| 57 | + in.readList(this.mNotices, Notice.class.getClassLoader()); |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + public static Creator<Notices> CREATOR = new Creator<Notices>() { |
|
| 61 | + public Notices createFromParcel(final Parcel source) { |
|
| 62 | + return new Notices(source); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + public Notices[] newArray(final int size) { |
|
| 66 | + return new Notices[size]; |
|
| 67 | + } |
|
| 68 | + }; |
|
| 69 | +} |
mobile/licensesdialog_lib/pom.xml
| ... | ... | @@ -0,0 +1,260 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 3 | + <modelVersion>4.0.0</modelVersion> |
|
| 4 | + |
|
| 5 | + <parent> |
|
| 6 | + <groupId>org.sonatype.oss</groupId> |
|
| 7 | + <artifactId>oss-parent</artifactId> |
|
| 8 | + <version>7</version> |
|
| 9 | + </parent> |
|
| 10 | + |
|
| 11 | + <groupId>de.psdev.licensesdialog</groupId> |
|
| 12 | + <artifactId>parent</artifactId> |
|
| 13 | + <packaging>pom</packaging> |
|
| 14 | + |
|
| 15 | + <name>LicensesDialog</name> |
|
| 16 | + <description>LicensesDialog is an open source library to display licenses used by third-party libraries in an Android app.</description> |
|
| 17 | + <url>http://psdev.de/LicensesDialog</url> |
|
| 18 | + <inceptionYear>2013</inceptionYear> |
|
| 19 | + <version>1.8.0</version> |
|
| 20 | + |
|
| 21 | + <modules> |
|
| 22 | + <module>library</module> |
|
| 23 | + <module>sample</module> |
|
| 24 | + </modules> |
|
| 25 | + |
|
| 26 | + <scm> |
|
| 27 | + <url>https://github.com/PSDev/LicensesDialog</url> |
|
| 28 | + <connection>scm:git:git://github.com/PSDev/LicensesDialog.git</connection> |
|
| 29 | + <developerConnection>scm:git:git@github.com:PSDev/LicensesDialog.git</developerConnection> |
|
| 30 | + <tag>1.8.0</tag> |
|
| 31 | + </scm> |
|
| 32 | + |
|
| 33 | + <developers> |
|
| 34 | + <developer> |
|
| 35 | + <name>Philip Schiffer</name> |
|
| 36 | + <email>philip.schiffer@gmail.com</email> |
|
| 37 | + </developer> |
|
| 38 | + </developers> |
|
| 39 | + |
|
| 40 | + <organization> |
|
| 41 | + <name>PSDev</name> |
|
| 42 | + <url>http://psdev.de</url> |
|
| 43 | + </organization> |
|
| 44 | + |
|
| 45 | + <licenses> |
|
| 46 | + <license> |
|
| 47 | + <name>Apache License Version 2.0</name> |
|
| 48 | + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> |
|
| 49 | + <distribution>repo</distribution> |
|
| 50 | + </license> |
|
| 51 | + </licenses> |
|
| 52 | + |
|
| 53 | + <issueManagement> |
|
| 54 | + <system>GitHub Issues</system> |
|
| 55 | + <url>https://github.com/PSDev/LicensesDialog/issues</url> |
|
| 56 | + </issueManagement> |
|
| 57 | + |
|
| 58 | + <ciManagement> |
|
| 59 | + <system>Jenkins</system> |
|
| 60 | + <url>http://ci.psdev.de/job/PSDevLicensesDialog/</url> |
|
| 61 | + </ciManagement> |
|
| 62 | + |
|
| 63 | + <properties> |
|
| 64 | + <!-- Project Properties --> |
|
| 65 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|
| 66 | + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
|
| 67 | + <java.version>1.6</java.version> |
|
| 68 | + <android.sdk.platform>22</android.sdk.platform> |
|
| 69 | + |
|
| 70 | + <!-- Dependency Versions --> |
|
| 71 | + <junit.version>4.12</junit.version> |
|
| 72 | + <robolectric.version>3.0</robolectric.version> |
|
| 73 | + <android.version>5.1.1_r2</android.version> |
|
| 74 | + <android-support.version>22.2.1</android-support.version> |
|
| 75 | + <jsr305.version>3.0.0</jsr305.version> |
|
| 76 | + |
|
| 77 | + <!-- Plugin Versions --> |
|
| 78 | + <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version> |
|
| 79 | + <android-maven-plugin.version>4.0.0-rc.2</android-maven-plugin.version> |
|
| 80 | + <maven-release-plugin.version>2.5.2</maven-release-plugin.version> |
|
| 81 | + <maven-javadoc-plugin.version>2.10.3</maven-javadoc-plugin.version> |
|
| 82 | + <maven-source-plugin.version>2.4</maven-source-plugin.version> |
|
| 83 | + <jacoco-maven-plugin.version>0.7.2.201409121644</jacoco-maven-plugin.version> |
|
| 84 | + <maven-gpg-plugin.version>1.4</maven-gpg-plugin.version> |
|
| 85 | + </properties> |
|
| 86 | + |
|
| 87 | + <dependencyManagement> |
|
| 88 | + <dependencies> |
|
| 89 | + <!-- Testing --> |
|
| 90 | + <dependency> |
|
| 91 | + <groupId>junit</groupId> |
|
| 92 | + <artifactId>junit</artifactId> |
|
| 93 | + <version>${junit.version}</version> |
|
| 94 | + <scope>test</scope> |
|
| 95 | + </dependency> |
|
| 96 | + <dependency> |
|
| 97 | + <groupId>org.robolectric</groupId> |
|
| 98 | + <artifactId>robolectric</artifactId> |
|
| 99 | + <version>${robolectric.version}</version> |
|
| 100 | + <scope>test</scope> |
|
| 101 | + </dependency> |
|
| 102 | + |
|
| 103 | + <!-- Android --> |
|
| 104 | + <dependency> |
|
| 105 | + <groupId>com.google.android</groupId> |
|
| 106 | + <artifactId>android</artifactId> |
|
| 107 | + <version>${android.version}</version> |
|
| 108 | + </dependency> |
|
| 109 | + <dependency> |
|
| 110 | + <groupId>com.android.support</groupId> |
|
| 111 | + <artifactId>support-v4</artifactId> |
|
| 112 | + <version>${android-support.version}</version> |
|
| 113 | + <type>aar</type> |
|
| 114 | + </dependency> |
|
| 115 | + <dependency> |
|
| 116 | + <groupId>com.android.support</groupId> |
|
| 117 | + <artifactId>appcompat-v7</artifactId> |
|
| 118 | + <version>${android-support.version}</version> |
|
| 119 | + <type>aar</type> |
|
| 120 | + </dependency> |
|
| 121 | + |
|
| 122 | + <!-- Nullable support --> |
|
| 123 | + <dependency> |
|
| 124 | + <groupId>com.google.code.findbugs</groupId> |
|
| 125 | + <artifactId>jsr305</artifactId> |
|
| 126 | + <version>${jsr305.version}</version> |
|
| 127 | + </dependency> |
|
| 128 | + </dependencies> |
|
| 129 | + </dependencyManagement> |
|
| 130 | + |
|
| 131 | + <build> |
|
| 132 | + <plugins> |
|
| 133 | + <plugin> |
|
| 134 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 135 | + <artifactId>maven-release-plugin</artifactId> |
|
| 136 | + <version>${maven-release-plugin.version}</version> |
|
| 137 | + <configuration> |
|
| 138 | + <autoVersionSubmodules>true</autoVersionSubmodules> |
|
| 139 | + </configuration> |
|
| 140 | + </plugin> |
|
| 141 | + </plugins> |
|
| 142 | + |
|
| 143 | + <pluginManagement> |
|
| 144 | + <plugins> |
|
| 145 | + <plugin> |
|
| 146 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 147 | + <artifactId>maven-compiler-plugin</artifactId> |
|
| 148 | + <version>${maven-compiler-plugin.version}</version> |
|
| 149 | + <configuration> |
|
| 150 | + <source>${java.version}</source> |
|
| 151 | + <target>${java.version}</target> |
|
| 152 | + </configuration> |
|
| 153 | + </plugin> |
|
| 154 | + |
|
| 155 | + <plugin> |
|
| 156 | + <groupId>com.jayway.maven.plugins.android.generation2</groupId> |
|
| 157 | + <artifactId>android-maven-plugin</artifactId> |
|
| 158 | + <extensions>true</extensions> |
|
| 159 | + <version>${android-maven-plugin.version}</version> |
|
| 160 | + <configuration> |
|
| 161 | + <!-- General settings --> |
|
| 162 | + <sdk> |
|
| 163 | + <path>${env.ANDROID_HOME}</path> |
|
| 164 | + <platform>${android.sdk.platform}</platform> |
|
| 165 | + </sdk> |
|
| 166 | + <extractDuplicates>true</extractDuplicates> |
|
| 167 | + <undeployBeforeDeploy>true</undeployBeforeDeploy> |
|
| 168 | + <includeLibsJarsFromApklib>true</includeLibsJarsFromApklib> |
|
| 169 | + <includeLibsJarsFromAar>true</includeLibsJarsFromAar> |
|
| 170 | + |
|
| 171 | + <!-- Project Structure --> |
|
| 172 | + <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile> |
|
| 173 | + <assetsDirectory>${project.basedir}/assets</assetsDirectory> |
|
| 174 | + <resourceDirectory>${project.basedir}/res</resourceDirectory> |
|
| 175 | + <nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory> |
|
| 176 | + |
|
| 177 | + <!-- Lint --> |
|
| 178 | + <lintEnableLibraries>true</lintEnableLibraries> |
|
| 179 | + <lintFailOnError>true</lintFailOnError> |
|
| 180 | + <lintEnableHtml>true</lintEnableHtml> |
|
| 181 | + <lintConfig>${project.basedir}/lint.xml</lintConfig> |
|
| 182 | + <lintSkip>false</lintSkip> |
|
| 183 | + |
|
| 184 | + </configuration> |
|
| 185 | + </plugin> |
|
| 186 | + |
|
| 187 | + <plugin> |
|
| 188 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 189 | + <artifactId>maven-source-plugin</artifactId> |
|
| 190 | + <version>${maven-source-plugin.version}</version> |
|
| 191 | + </plugin> |
|
| 192 | + |
|
| 193 | + <plugin> |
|
| 194 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 195 | + <artifactId>maven-javadoc-plugin</artifactId> |
|
| 196 | + <version>${maven-javadoc-plugin.version}</version> |
|
| 197 | + </plugin> |
|
| 198 | + |
|
| 199 | + <plugin> |
|
| 200 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 201 | + <artifactId>maven-release-plugin</artifactId> |
|
| 202 | + <version>${maven-release-plugin.version}</version> |
|
| 203 | + <configuration> |
|
| 204 | + <tagNameFormat>@{project.version}</tagNameFormat> |
|
| 205 | + <autoVersionSubmodules>true</autoVersionSubmodules> |
|
| 206 | + </configuration> |
|
| 207 | + </plugin> |
|
| 208 | + |
|
| 209 | + <plugin> |
|
| 210 | + <groupId>org.jacoco</groupId> |
|
| 211 | + <artifactId>jacoco-maven-plugin</artifactId> |
|
| 212 | + <version>${jacoco-maven-plugin.version}</version> |
|
| 213 | + <configuration> |
|
| 214 | + <excludes> |
|
| 215 | + <exclude>**/BuildConfig.class</exclude> |
|
| 216 | + <exclude>**/R*.class</exclude> |
|
| 217 | + </excludes> |
|
| 218 | + </configuration> |
|
| 219 | + <executions> |
|
| 220 | + <execution> |
|
| 221 | + <id>jacoco-initialize</id> |
|
| 222 | + <phase>initialize</phase> |
|
| 223 | + <goals> |
|
| 224 | + <goal>prepare-agent</goal> |
|
| 225 | + </goals> |
|
| 226 | + </execution> |
|
| 227 | + <execution> |
|
| 228 | + <id>jacoco-site</id> |
|
| 229 | + <phase>package</phase> |
|
| 230 | + <goals> |
|
| 231 | + <goal>report</goal> |
|
| 232 | + </goals> |
|
| 233 | + </execution> |
|
| 234 | + </executions> |
|
| 235 | + </plugin> |
|
| 236 | + </plugins> |
|
| 237 | + </pluginManagement> |
|
| 238 | + </build> |
|
| 239 | + |
|
| 240 | + <profiles> |
|
| 241 | + <profile> |
|
| 242 | + <id>doclint-java8-disable</id> |
|
| 243 | + <activation> |
|
| 244 | + <jdk>[1.8,)</jdk> |
|
| 245 | + </activation> |
|
| 246 | + <build> |
|
| 247 | + <plugins> |
|
| 248 | + <plugin> |
|
| 249 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 250 | + <artifactId>maven-javadoc-plugin</artifactId> |
|
| 251 | + <configuration> |
|
| 252 | + <additionalparam>-Xdoclint:none</additionalparam> |
|
| 253 | + </configuration> |
|
| 254 | + </plugin> |
|
| 255 | + </plugins> |
|
| 256 | + </build> |
|
| 257 | + </profile> |
|
| 258 | + </profiles> |
|
| 259 | + |
|
| 260 | +</project> |
mobile/pom.xml
| ... | ... | @@ -16,13 +16,13 @@ |
| 16 | 16 | <!-- |
| 17 | 17 | <module>com.sap.sailing.racecommittee.app</module> |
| 18 | 18 | <module>com.sap.sailing.android.shared</module> |
| 19 | - <module>com.sap.sailing.adnroid.buoy.positioning.app</module> |
|
| 19 | + <module>com.sap.sailing.adnroid.buoy.positioning.app</module> |
|
| 20 | 20 | <module>com.sap.sailing.android.tracking.app</module> |
| 21 | 21 | --> |
| 22 | 22 | </modules> |
| 23 | 23 | |
| 24 | 24 | <properties> |
| 25 | - <!-- used to copy android apps to the static web dir (auto-update functionality) --> |
|
| 25 | + <!-- used to copy android apps to the static web dir (auto-update functionality) --> |
|
| 26 | 26 | <!-- relative dir as seen from the child modules --> |
| 27 | 27 | <additional-deployment-dir>../../java/com.sap.sailing.www/apps</additional-deployment-dir> |
| 28 | 28 | <!-- redefine in child poms --> |
| ... | ... | @@ -32,21 +32,21 @@ |
| 32 | 32 | |
| 33 | 33 | <dependencyManagement> |
| 34 | 34 | <dependencies> |
| 35 | - <!-- needed on remote repository --> |
|
| 36 | - <dependency> |
|
| 37 | - <groupId>android</groupId> |
|
| 38 | - <artifactId>android</artifactId> |
|
| 39 | - <version>4.4.2_r4</version> |
|
| 40 | - <scope>provided</scope> |
|
| 41 | - </dependency> |
|
| 35 | + <!-- needed on remote repository --> |
|
| 36 | + <dependency> |
|
| 37 | + <groupId>android</groupId> |
|
| 38 | + <artifactId>android</artifactId> |
|
| 39 | + <version>4.4.2_r4</version> |
|
| 40 | + <scope>provided</scope> |
|
| 41 | + </dependency> |
|
| 42 | 42 | |
| 43 | - <!-- needed on remote repository --> |
|
| 44 | - <dependency> |
|
| 45 | - <groupId>android.support</groupId> |
|
| 46 | - <artifactId>compatibility-v4</artifactId> |
|
| 47 | - <version>19</version> |
|
| 48 | - </dependency> |
|
| 49 | - </dependencies> |
|
| 43 | + <!-- needed on remote repository --> |
|
| 44 | + <dependency> |
|
| 45 | + <groupId>android.support</groupId> |
|
| 46 | + <artifactId>compatibility-v4</artifactId> |
|
| 47 | + <version>19</version> |
|
| 48 | + </dependency> |
|
| 49 | + </dependencies> |
|
| 50 | 50 | </dependencyManagement> |
| 51 | 51 | |
| 52 | 52 | <build> |
| ... | ... | @@ -55,90 +55,90 @@ |
| 55 | 55 | <plugin> |
| 56 | 56 | <groupId>com.jayway.maven.plugins.android.generation2</groupId> |
| 57 | 57 | <artifactId>android-maven-plugin</artifactId> |
| 58 | - <version>3.9.0-rc.1</version> |
|
| 59 | - <configuration> |
|
| 60 | - <sdk> |
|
| 61 | - <platform>19</platform> |
|
| 62 | - </sdk> |
|
| 63 | - </configuration> |
|
| 58 | + <version>3.9.0-rc.1</version> |
|
| 59 | + <configuration> |
|
| 60 | + <sdk> |
|
| 61 | + <platform>19</platform> |
|
| 62 | + </sdk> |
|
| 63 | + </configuration> |
|
| 64 | 64 | <extensions>true</extensions> |
| 65 | 65 | </plugin> |
| 66 | - <plugin> |
|
| 67 | - <groupId>org.apache.maven.plugins</groupId> |
|
| 68 | - <artifactId>maven-dependency-plugin</artifactId> |
|
| 69 | - <version>2.8</version> |
|
| 70 | - <executions> |
|
| 71 | - <execution> |
|
| 72 | - <id>copy-installed</id> |
|
| 73 | - <phase>install</phase> |
|
| 74 | - <goals> |
|
| 75 | - <goal>copy</goal> |
|
| 76 | - </goals> |
|
| 77 | - <configuration> |
|
| 78 | - <artifactItems> |
|
| 79 | - <artifactItem> |
|
| 80 | - <groupId>${project.groupId}</groupId> |
|
| 81 | - <artifactId>${project.artifactId}</artifactId> |
|
| 82 | - <version>${project.version}</version> |
|
| 83 | - <type>${project.packaging}</type> |
|
| 84 | - </artifactItem> |
|
| 85 | - </artifactItems> |
|
| 86 | - <outputDirectory>${additional-deployment-dir}</outputDirectory> |
|
| 87 | - <stripVersion>true</stripVersion> |
|
| 88 | - </configuration> |
|
| 89 | - </execution> |
|
| 90 | - </executions> |
|
| 91 | - </plugin> |
|
| 92 | - <plugin> |
|
| 93 | - <groupId>org.apache.maven.plugins</groupId> |
|
| 94 | - <artifactId>maven-antrun-plugin</artifactId> |
|
| 95 | - <version>1.3</version> |
|
| 96 | - <executions> |
|
| 97 | - <execution> |
|
| 98 | - <id>generate-version</id> |
|
| 99 | - <phase>install</phase> |
|
| 100 | - <goals> |
|
| 101 | - <goal>run</goal> |
|
| 102 | - </goals> |
|
| 103 | - <configuration> |
|
| 104 | - <tasks> |
|
| 105 | - <property name="target.dir" value="${additional-deployment-dir}" /> |
|
| 106 | - <property name="target.name" value="${additional-deployment-version-file}" /> |
|
| 107 | - |
|
| 108 | - <echo file="${target.dir}/${target.name}" message="${project.build.finalName}.apk=${app-version}" /> |
|
| 109 | - <echo message="Version file generated in ${target.dir}/${target.name}." /> |
|
| 110 | - </tasks> |
|
| 111 | - </configuration> |
|
| 112 | - </execution> |
|
| 113 | - </executions> |
|
| 114 | - </plugin> |
|
| 115 | - <plugin> |
|
| 116 | - <artifactId>maven-clean-plugin</artifactId> |
|
| 117 | - <version>2.5</version> |
|
| 118 | - <configuration> |
|
| 119 | - <filesets> |
|
| 120 | - <fileset> |
|
| 121 | - <directory>${additional-deployment-dir}</directory> |
|
| 122 | - <includes> |
|
| 123 | - <include>${project.build.finalName}.apk</include> |
|
| 124 | - <include>${additional-deployment-version-file}</include> |
|
| 125 | - </includes> |
|
| 126 | - <excludes> |
|
| 127 | - <exclude>*.gitignore</exclude> |
|
| 128 | - </excludes> |
|
| 129 | - <followSymlinks>false</followSymlinks> |
|
| 130 | - </fileset> |
|
| 131 | - </filesets> |
|
| 132 | - </configuration> |
|
| 133 | - </plugin> |
|
| 134 | - <plugin> |
|
| 135 | - <groupId>org.apache.maven.plugins</groupId> |
|
| 136 | - <artifactId>maven-compiler-plugin</artifactId> |
|
| 137 | - <configuration> |
|
| 138 | - <source>1.7</source> |
|
| 139 | - <target>1.7</target> |
|
| 140 | - </configuration> |
|
| 141 | - </plugin> |
|
| 66 | + <plugin> |
|
| 67 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 68 | + <artifactId>maven-dependency-plugin</artifactId> |
|
| 69 | + <version>2.8</version> |
|
| 70 | + <executions> |
|
| 71 | + <execution> |
|
| 72 | + <id>copy-installed</id> |
|
| 73 | + <phase>install</phase> |
|
| 74 | + <goals> |
|
| 75 | + <goal>copy</goal> |
|
| 76 | + </goals> |
|
| 77 | + <configuration> |
|
| 78 | + <artifactItems> |
|
| 79 | + <artifactItem> |
|
| 80 | + <groupId>${project.groupId}</groupId> |
|
| 81 | + <artifactId>${project.artifactId}</artifactId> |
|
| 82 | + <version>${project.version}</version> |
|
| 83 | + <type>${project.packaging}</type> |
|
| 84 | + </artifactItem> |
|
| 85 | + </artifactItems> |
|
| 86 | + <outputDirectory>${additional-deployment-dir}</outputDirectory> |
|
| 87 | + <stripVersion>true</stripVersion> |
|
| 88 | + </configuration> |
|
| 89 | + </execution> |
|
| 90 | + </executions> |
|
| 91 | + </plugin> |
|
| 92 | + <plugin> |
|
| 93 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 94 | + <artifactId>maven-antrun-plugin</artifactId> |
|
| 95 | + <version>1.3</version> |
|
| 96 | + <executions> |
|
| 97 | + <execution> |
|
| 98 | + <id>generate-version</id> |
|
| 99 | + <phase>install</phase> |
|
| 100 | + <goals> |
|
| 101 | + <goal>run</goal> |
|
| 102 | + </goals> |
|
| 103 | + <configuration> |
|
| 104 | + <tasks> |
|
| 105 | + <property name="target.dir" value="${additional-deployment-dir}" /> |
|
| 106 | + <property name="target.name" value="${additional-deployment-version-file}" /> |
|
| 107 | + |
|
| 108 | + <echo file="${target.dir}/${target.name}" message="${project.build.finalName}.apk=${app-version}" /> |
|
| 109 | + <echo message="Version file generated in ${target.dir}/${target.name}." /> |
|
| 110 | + </tasks> |
|
| 111 | + </configuration> |
|
| 112 | + </execution> |
|
| 113 | + </executions> |
|
| 114 | + </plugin> |
|
| 115 | + <plugin> |
|
| 116 | + <artifactId>maven-clean-plugin</artifactId> |
|
| 117 | + <version>2.5</version> |
|
| 118 | + <configuration> |
|
| 119 | + <filesets> |
|
| 120 | + <fileset> |
|
| 121 | + <directory>${additional-deployment-dir}</directory> |
|
| 122 | + <includes> |
|
| 123 | + <include>${project.build.finalName}.apk</include> |
|
| 124 | + <include>${additional-deployment-version-file}</include> |
|
| 125 | + </includes> |
|
| 126 | + <excludes> |
|
| 127 | + <exclude>*.gitignore</exclude> |
|
| 128 | + </excludes> |
|
| 129 | + <followSymlinks>false</followSymlinks> |
|
| 130 | + </fileset> |
|
| 131 | + </filesets> |
|
| 132 | + </configuration> |
|
| 133 | + </plugin> |
|
| 134 | + <plugin> |
|
| 135 | + <groupId>org.apache.maven.plugins</groupId> |
|
| 136 | + <artifactId>maven-compiler-plugin</artifactId> |
|
| 137 | + <configuration> |
|
| 138 | + <source>1.7</source> |
|
| 139 | + <target>1.7</target> |
|
| 140 | + </configuration> |
|
| 141 | + </plugin> |
|
| 142 | 142 | </plugins> |
| 143 | 143 | </pluginManagement> |
| 144 | 144 | </build> |
pom.xml
| ... | ... | @@ -1,68 +1,68 @@ |
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | <project |
| 3 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | - xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 3 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
|
| 4 | + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | 6 | |
| 7 | - <groupId>com.sap.sailing</groupId> |
|
| 8 | - <artifactId>workspace</artifactId> |
|
| 9 | - <version>1.0.0-SNAPSHOT</version> |
|
| 10 | - <packaging>pom</packaging> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <artifactId>workspace</artifactId> |
|
| 9 | + <version>1.0.0-SNAPSHOT</version> |
|
| 10 | + <packaging>pom</packaging> |
|
| 11 | 11 | |
| 12 | - <modules> |
|
| 13 | - <module>java</module> |
|
| 14 | - </modules> |
|
| 12 | + <modules> |
|
| 13 | + <module>java</module> |
|
| 14 | + </modules> |
|
| 15 | 15 | |
| 16 | - <profiles> |
|
| 17 | - <profile> |
|
| 18 | - <!-- deactivate with parameter '-P !with-mobile'--> |
|
| 19 | - <id>with-mobile</id> |
|
| 20 | - <activation> |
|
| 21 | - <activeByDefault>true</activeByDefault> |
|
| 22 | - </activation> |
|
| 23 | - <modules> |
|
| 24 | - <module>mobile</module> |
|
| 25 | - </modules> |
|
| 26 | - </profile> |
|
| 27 | - <profile> |
|
| 28 | - <!-- activate with parameter '-P with-ios'--> |
|
| 29 | - <id>with-ios</id> |
|
| 30 | - <modules> |
|
| 31 | - <module>ios</module> |
|
| 32 | - </modules> |
|
| 33 | - </profile> |
|
| 34 | - </profiles> |
|
| 16 | + <profiles> |
|
| 17 | + <profile> |
|
| 18 | + <!-- deactivate with parameter '-P !with-mobile'--> |
|
| 19 | + <id>with-mobile</id> |
|
| 20 | + <activation> |
|
| 21 | + <activeByDefault>true</activeByDefault> |
|
| 22 | + </activation> |
|
| 23 | + <modules> |
|
| 24 | + <module>mobile</module> |
|
| 25 | + </modules> |
|
| 26 | + </profile> |
|
| 27 | + <profile> |
|
| 28 | + <!-- activate with parameter '-P with-ios'--> |
|
| 29 | + <id>with-ios</id> |
|
| 30 | + <modules> |
|
| 31 | + <module>ios</module> |
|
| 32 | + </modules> |
|
| 33 | + </profile> |
|
| 34 | + </profiles> |
|
| 35 | 35 | |
| 36 | - <properties> |
|
| 37 | - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|
| 38 | - <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
|
| 39 | - </properties> |
|
| 40 | - |
|
| 41 | - <repositories> |
|
| 42 | - <repository> |
|
| 43 | - <id>equinox-sdk-3.9</id> |
|
| 44 | - <layout>p2</layout> |
|
| 45 | - <url>http://download.eclipse.org/releases/luna/</url> |
|
| 46 | - </repository> |
|
| 47 | -<!-- |
|
| 48 | - <repository> |
|
| 49 | - <id>sap-nexus</id> |
|
| 50 | - <url>http://nexus.wdf.sap.corp:8081/nexus/content/groups/build.snapshots</url> |
|
| 51 | - </repository> |
|
| 36 | + <properties> |
|
| 37 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|
| 38 | + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
|
| 39 | + </properties> |
|
| 40 | + |
|
| 41 | + <repositories> |
|
| 42 | + <repository> |
|
| 43 | + <id>equinox-sdk-3.9</id> |
|
| 44 | + <layout>p2</layout> |
|
| 45 | + <url>http://download.eclipse.org/releases/luna/</url> |
|
| 46 | + </repository> |
|
| 47 | +<!-- |
|
| 48 | + <repository> |
|
| 49 | + <id>sap-nexus</id> |
|
| 50 | + <url>http://nexus.wdf.sap.corp:8081/nexus/content/groups/build.snapshots</url> |
|
| 51 | + </repository> |
|
| 52 | 52 | --> |
| 53 | - <repository> |
|
| 54 | - <id>sailing-server-maven</id> |
|
| 55 | - <url>http://maven.sapsailing.com/maven</url> |
|
| 56 | - </repository> |
|
| 53 | + <repository> |
|
| 54 | + <id>sailing-server-maven</id> |
|
| 55 | + <url>http://maven.sapsailing.com/maven</url> |
|
| 56 | + </repository> |
|
| 57 | 57 | |
| 58 | - <repository> |
|
| 59 | - <id>central</id> |
|
| 60 | - <url>http://repo1.maven.org/maven2</url> |
|
| 61 | - </repository> |
|
| 58 | + <repository> |
|
| 59 | + <id>central</id> |
|
| 60 | + <url>http://repo1.maven.org/maven2</url> |
|
| 61 | + </repository> |
|
| 62 | 62 | |
| 63 | - <repository> |
|
| 64 | - <id>uni-luebeck</id> |
|
| 65 | - <url>http://www.itm.uni-luebeck.de/projects/maven/releases</url> |
|
| 66 | - </repository> |
|
| 67 | - </repositories> |
|
| 63 | + <repository> |
|
| 64 | + <id>uni-luebeck</id> |
|
| 65 | + <url>http://www.itm.uni-luebeck.de/projects/maven/releases</url> |
|
| 66 | + </repository> |
|
| 67 | + </repositories> |
|
| 68 | 68 | </project> |
wiki/Log-File-Analysis.md
| ... | ... | @@ -0,0 +1,166 @@ |
| 1 | +# Log File Analysis |
|
| 2 | + |
|
| 3 | +[[_TOC_]] |
|
| 4 | + |
|
| 5 | +## Log File Types |
|
| 6 | + |
|
| 7 | +There are three different types of log files produced by the server landscape under the umbrella of http://www.sapsailing.com: |
|
| 8 | + |
|
| 9 | + - Java server logs (sailing0.log.0, gc.log.0.current, ...) |
|
| 10 | + |
|
| 11 | + - Apache log files (access_log, error_log, ...) |
|
| 12 | + |
|
| 13 | + - Amazon EC2 Elastic Load Balancer (ELB) logs (017363970217_elasticloadbalancing_eu-west-1_ELBGermanLeague_20151118T1320Z_52.18.137.128_18dpodfi.log) |
|
| 14 | + |
|
| 15 | +### Java Server Logs |
|
| 16 | + |
|
| 17 | +The Java server logs contain health, memory and general progress data as well as information about exceptions that occurred, including deadlock situations and important application events such as adding a wind sensor account, starting to track a race, creating a new regatta, etc. The format of a typical Java server log line is |
|
| 18 | + |
|
| 19 | +<pre> |
|
| 20 | +Nov 03, 2015 6:32:24 PM com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl loadControlPointWithTwoMarks |
|
| 21 | +INFO: Migrating right Mark of ControlPointWithTwoMarks Gate White P / White S from old field GATE_RIGHT to CONTROLPOINTWITHTWOMARKS_RIGHT |
|
| 22 | +</pre> |
|
| 23 | + |
|
| 24 | +A typical garbage collection log from gc.log.0.current may look like this: |
|
| 25 | + |
|
| 26 | +<pre> |
|
| 27 | + ... |
|
| 28 | + [Ref Enq: 0.0 ms] |
|
| 29 | + [Redirty Cards: 0.2 ms] |
|
| 30 | + [Free CSet: 2.2 ms] |
|
| 31 | + [Eden: 5406.0M(5406.0M)->0.0B(5398.0M) Survivors: 26.0M->32.0M Heap: 8156.2M(9216.0M)->2757.5M(9216.0M)] |
|
| 32 | + [Times: user=0.28 sys=0.01, real=0.19 secs] |
|
| 33 | +</pre> |
|
| 34 | + |
|
| 35 | +The `Heap: ...` section gives hints as to the current heap memory consumption before and after the last GC run as well as the maximum heap allocated so far. |
|
| 36 | + |
|
| 37 | +### Apache Log Files |
|
| 38 | + |
|
| 39 | +Our primary, central Apache web server largely acts as a reverse proxy that maps subdomain names to virtual host declarations by means of a configuration file located at `/etc/httpd/conf.d/001-events.conf` which uses all sorts of clever macros to keep these mapping definitions concise. Due to the large number of these virtual hosts and in order to be able to keep the logs apart, we use the "combined" log file format which lists the virtual host name used as the first column in the log entry. This lets an `access_log` entry look like this: |
|
| 40 | + |
|
| 41 | +<pre> |
|
| 42 | +dutchleague2015.sapsailing.com 94.209.86.140 - - [08/Nov/2015:10:47:31 +0000] "POST /gwt/service/sailing HTTP/1.1" 200 751 "http://dutchleague2015.sapsailing.com/gwt/RaceBoard.html®attaName=Dutch%20Sailing%20League%202015%20-%20Almere" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.78.2 (KHTML, like Gecko) Version/6.1.6 Safari/537.78.2" |
|
| 43 | +</pre> |
|
| 44 | + |
|
| 45 | +After the virtual host name comes the client's IP address, followed by two unused fields regarding authentication, then the time stamp, the request, response code, number of bytes delivered, the referrer URL and the user agent. |
|
| 46 | + |
|
| 47 | +For load-balanced set-ups we have an Amazon Elastic Load Balancer (ELB) dispatch incoming requests to the instances linked to the ELB. The ELB can (and definitely should) be configured to write its own logs (see next section), but those are not in Apache log file format and contain no information about the referrer URL. Using an Apache server on the instances linked to the ELB partly solves this problem by generating logs in the same format that our central Apache server uses. |
|
| 48 | + |
|
| 49 | +In addition to this, the Apache servers on these load-balanced instances perform the same URL rewriting and reverse proxying using the same set of macros that the central Apache server uses. |
|
| 50 | + |
|
| 51 | +**However**, one key problem of these decentralized Apache log files is that the client IP address only identifies the load balancer or reverse proxy instance, not the original client itself. With this, any type of analysis that tries to count the number of visitors will deliver skewed results. Counting the plain number of hits, though, is OK, as is the identification of the most-frequently used referrer URLs which can, e.g., help to identify popular leaderboards and races. |
|
| 52 | + |
|
| 53 | +Still, in order to provide the true client IP in the log files, we use the `X-Forwarded-For` HTTP header field which contains the comma-separated list of "hops" through which the request was reverse-proxied so far. The following combination of Apache `httpd.conf` entries make this work: |
|
| 54 | + |
|
| 55 | +<pre> |
|
| 56 | + SetEnvIf X-Forwarded-For "^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*).*$" original_client_ip=$1 |
|
| 57 | + LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined |
|
| 58 | + LogFormat "%v %{original_client_ip}e %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" first_forwarded_for_ip |
|
| 59 | + CustomLog logs/access_log combined env=!original_client_ip |
|
| 60 | + CustomLog logs/access_log first_forwarded_for_ip env=original_client_ip |
|
| 61 | +</pre> |
|
| 62 | + |
|
| 63 | +This uses the SetEnvIf module, tries to match an IP address at the start of the `X-Forwarded-For` header field, and if found, assigns it to the `original_client_ip` variable. This variable, in turn, decides which of the two `CustomLog` directives is applied to the request. If the variable is set, instead of using the regular `%h` field for the client IP, the variable value is logged by `%{original_client_ip}`. |
|
| 64 | + |
|
| 65 | +### Amazon EC2 Elastic Load Balancer (ELB) Logs |
|
| 66 | + |
|
| 67 | +An Amazon ELB can be configured to write log files to the S3 storage. The general format is [explained here](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/access-log-collection.html#access-log-entry-format). It contains in particular the client IP where the request originated and can tell timing parameters for request forwarding and processing that otherwise would not be available. |
|
| 68 | + |
|
| 69 | +The format for these logs is |
|
| 70 | + |
|
| 71 | +<pre> |
|
| 72 | +timestamp elb client:port backend:port request_processing_time backend_processing_time response_processing_time elb_status_code backend_status_code received_bytes sent_bytes "request" "user_agent" ssl_cipher ssl_protocol |
|
| 73 | +</pre> |
|
| 74 | + |
|
| 75 | +It seems a good idea to always capture these logs for archiving purposes. They end up on an S3 bucket, and by default we use `sapsailing-access-logs`. |
|
| 76 | + |
|
| 77 | +Content can be synced from there to a local directory using the following command: |
|
| 78 | + |
|
| 79 | +``s3cmd sync s3://sapsailing-access-logs/elb-access-logs ./elb-access-logs/`` |
|
| 80 | + |
|
| 81 | +Our central web server at `www.sapsailing.com` does this periodically every day, sync'ing the logs to `/var/log/old/elb-access-logs/`. The corresponding cron job is defined in `/etc/cron.daily/syncEC2ElbLogs` which is a script also found in git in the `configuration/` folder. |
|
| 82 | + |
|
| 83 | +### Broken or Partly Missing Logs and How We Recover |
|
| 84 | + |
|
| 85 | +During a few events we unfortunately failed to create proper Apache log files according to the above rules for scenarios using a load-balanced setup ("ELB scenario"). In some cases, the Apache log format was missing the referrer URL. This is easy to patch into the files because we collected the logs on a per-server basis and we knew which server ran which event. For example, for Kieler Woche 2015 and Travemünder Woche 2015 we needed to insert `kielerwoche2015.sapsailing.com` and `tw2015.sapsailing.com`, respectively, to match the general log format used for analysis. |
|
| 86 | + |
|
| 87 | +The other problem, as described already above, is that of the original client IP address. Before we encountered how to log the original client IP from the `X-Forwarded-For` header field, only the ELB's IP addresses were logged in the Apache logs. While counting the correct number of hits is possible with such logs, they don't reveal the true number of unique visitors. They do, however, contain a valid referrer URL, telling us which leaderboards and races were the most popular. |
|
| 88 | + |
|
| 89 | +In case we had an ELB log active, storing the Amazon ELB logs to an S3 bucket, we were able to convert those with a script stored in our git at `configuration/convertELBLogToApacheFormat` into our general Apache log format. This allows us to count the unique visitors for those events, but the ELB logs don't contain the referrer URL, so we patch that to always be the plain event URL, such as `http://kielerwoche2015.sapsailing.com`. Therefore, while these converted logs tell the correct number of unique visitors and the correct number of hits, they don't allow for an analysis of the most popular leaderboards and races. |
|
| 90 | + |
|
| 91 | +We hope that these partially-logged events remain the exception and that future events are logged homogeneously according to the rules above. The following naming conventions have been established under `/var/log/old` that shall allow the automatic log analyzers to identify the log file contents by file name patterns: |
|
| 92 | + |
|
| 93 | + - `access_log*`: A proper Apache log file with virtual host name as the first field, followed by the original client's IP address and a valid referrer URL as the second-to-last field |
|
| 94 | + - `elb-origin-access_log*`: An Apache log file whose origin IP addresses are usually only the ELB IP addresses, therefore not allowing for unique visitor analysis |
|
| 95 | + - `bundesliga2015_elb_access_log.gz` and `tw2015_elb_access_log.gz`: ELB log files converted to Apache format, appended in order of ascending time stamps, prefixed with the virtual host name as the first field, using the original client IP address which allows for unique visitor analysis, and the virtual host name used again as generic referrer URL |
|
| 96 | + - `original-access_log*`: Apache log file without leading virtual host name field, also usually only with ELB IP addresses instead of an original client IP; not good for any log file analysis without further conversion, but kept for reference purposes |
|
| 97 | + |
|
| 98 | +## Automatic Log File Rotation to /var/log/old |
|
| 99 | + |
|
| 100 | +When an EC2 server is launched from its Amazon Machine Image (AMI), the /etc/init.d/sailing script is executed with the "start" parameter. This script is really just a link to `/home/sailing/code/configuration/sailing` which comes from the git version checked out to the workspace at `/home/sailing/code`. This script patches the file `/etc/logrotate.d/httpd` such that when log rotation happens, the existence of the directory `/var/log/old/$SERVER_NAME/$SERVER_IP` is ensured and the log files are copied there. |
|
| 101 | + |
|
| 102 | +This way, logs end up in a per server-name and per server-ip directory. |
|
| 103 | + |
|
| 104 | +The general log rotation rules (size, time, compression, etc.) is governed by `/etc/logrotate.conf`. |
|
| 105 | + |
|
| 106 | +## Analysis Tools |
|
| 107 | + |
|
| 108 | +### goaccess |
|
| 109 | + |
|
| 110 | +The file `/root/.goaccessrc` on `www.sapsailing.com` looks as follows: |
|
| 111 | + |
|
| 112 | +``` |
|
| 113 | +color_scheme 1 |
|
| 114 | +date_format %d/%b/%Y |
|
| 115 | +time_format %H:%M:%S |
|
| 116 | +log_format %^ %h %^[%d:%^] "%r" %s %b "%R" "%u" |
|
| 117 | +log_file STDIN |
|
| 118 | +``` |
|
| 119 | + |
|
| 120 | +Still, specific parameters are required for `goaccess` in order to parse our regular Apache logs that have the virtual host name as their first field: |
|
| 121 | + |
|
| 122 | +`goaccess --no-global-config -a -f /var/log/httpd/access_log` |
|
| 123 | + |
|
| 124 | +The unique visitors that goaccess lists are based on the common definition that counts requests as originating from the same visitor if they happened on the same day with equal user agent and IP address. |
|
| 125 | + |
|
| 126 | +### apachetop |
|
| 127 | + |
|
| 128 | +The simple command `apachetop` shows the traffic on the Apache httpd server running on the host where the command is invoked, based on the access log file in the usual location `/var/log/httpd/access_log`. |
|
| 129 | + |
|
| 130 | +### AWStats |
|
| 131 | + |
|
| 132 | +We use AWStats to analyze our Apache access log files and produce per-month reports at [http://awstats.sapsailing.com](http://awstats.sapsailing.com/awstats/awstats.pl?output=main&config=www.sapsailing.com&framename=index). The username is `awstats`. Ask axel.uhl@sap.com or stefan.lacher@sap.com for the password. |
|
| 133 | + |
|
| 134 | +AWStats report production is controlled by three things: a cron job hooked up by `/etc/cron.weekly/awstats` which is basically a one-liner launching the `awstats` command like this: |
|
| 135 | + |
|
| 136 | +`exec /usr/share/awstats/tools/awstats_updateall.pl now -configdir="/etc/awstats" -awstatsprog="/usr/share/awstats/wwwroot/cgi-bin/awstats.pl"` |
|
| 137 | + |
|
| 138 | +and a configuration file located at `/etc/awstats/awstats.www.sapsailing.com.conf` which describes in its `LogFile` directive the filename pattern to use for collecting the log files that shall be analyzed. Currently, the file name pattern is this: |
|
| 139 | + |
|
| 140 | +`/var/log/httpd/access_log /var/log/old/access_log-???????? /var/log/old/access_log-????????.gz /var/log/old/*/elb-origin-access_log* /var/log/old/*/*/elb-origin-access_log* /var/log/old/*/access_log* /var/log/old/*/*/access_log*` |
|
| 141 | + |
|
| 142 | +and all log entries that contain `HealthChecker` are eliminated as they are only a "ping" request sent by the load balancer to check the instance's health status which is not to be counted as a "hit." Note that according to the above explanations of our log file formats and variants this focuses on hit analysis for those events with broken or partial / incomplete log files such as Kieler Woche 2015 and Travemünder Woche 2015. It uses the `elb-origin-*` flavors, tolerating the fact that these don't have the original client's IP address. |
|
| 143 | + |
|
| 144 | +The third element of AWStats configuration is how it is published through Apache. This is described in `/etc/httpd/conf.d/awstats.conf` and uses the password definition file `/etc/httpd/conf/passwd.awstats` which can be updated using the `htpasswd` command. |
|
| 145 | + |
|
| 146 | +### Custom Scripts |
|
| 147 | + |
|
| 148 | +#### `unique_ips_per_referrer` |
|
| 149 | + |
|
| 150 | +The script is located in git at `configuration/unique_ips_per_referrer`. It has two variants next to it: `unique_ips_per_referrer_generate_results_only` and `unique_ips_per_referrer_generate_month_results_only`. The basic idea of this family of scripts is to count the unique visitors for each virtual host name (usually corresponding to an event), in total and by month. Neither the `goaccess` nor the AWStats tool provide us with these numbers. AWStats can only compute the _hits_ per virtual host name, and `goaccess` only lists unique visitors per day, not per virtual host. |
|
| 151 | + |
|
| 152 | +The script can be fed with a list of log files in our common Apache format, with virtual host name in first, original client IP in second, time stamp in third and user agent in last column. For all new files (files already analyzed are recorded in `/var/log/old/cache/unique-ips-per-referrer/visited) the script then reduces each line to its timestamp, original client IP and user agent fields, constituting the key for identifying a unique visitor. Each log entry that has been analyzed and reduced this way is then appended to a file under `/var/log/old/cache/unique-ips-per-referrer/stats/<virtual-host-name>.ips`. When done with all inputs, the `*.ips` files produced are filtered for unique entries (using `sort -u`) and number of lines are counted, resulting in the total number of unique visitors per virtual host name since the beginning of our log file records. |
|
| 153 | + |
|
| 154 | +Additionally, a per-month analysis is carried out by splitting the `*.ips` files by the months found in the time stamps and again applying a unique count. The resulting files can be found at `/var/log/old/cache/unique-ips-per-referrer/stats/unique-ips-days-useragents-per-event` and `/var/log/old/cache/unique-ips-per-referrer/stats/unique-ips-days-useragents-per-event-MMM-YYYY` where `MMM` represents the three-letter month name such as `Apr` and `YYYY` stands for the year. |
|
| 155 | + |
|
| 156 | +The `unique_ips_per_referrer` script is registered as a weekly cron job in `/etc/cron.weekly` and is fed the special converted log files of Travemünder Woche 2015 and the Bundesliga logs from 2015, as well as all files matching the file name pattern `access_log-*` anywhere under `/var/log/old`. This only matches proper Apache log files with original client IP addresses, not those with ELB IP addresses only (which are named `elb-origin-access_log*` by convention, see above). |
|
| 157 | + |
|
| 158 | +The variant `unique_ips_per_referrer_generate_results_only` assumes that the `*.ips` files have already been updated and produces the total and per-month output files. |
|
| 159 | + |
|
| 160 | +The variant `unique_ips_per_referrer_generate_month_results_only` produces only the per-month output files, also assuming that the `*.ips` files have already been updated. |
|
| 161 | + |
|
| 162 | +The results are published under the link [http://awstats.sapsailing.com/unique-visitors/](http://awstats.sapsailing.com/unique-visitors/) which uses the same credentials as the main AWStats publishing page. |
|
| 163 | + |
|
| 164 | +#### `convertELBLogToApacheFormat` |
|
| 165 | + |
|
| 166 | +This script was already briefly mentioned above. It is found at `configuration/convertELBLogToApacheFormat` and converts and Amazon Elastic Load Balancer (ELB) log file to our common Apache log file format with leading virtual host name. The virtual host name is expected as the first parameter; all subsequent parameters are treated as file names of ELB log files, either in GZIP format with `.gz` extension or uncompressed. The conversion result is streamed to the standard output and may therefore be redirected into a file. |
|
| ... | ... | \ No newline at end of file |
wiki/creating-ec2-image-from-scratch.md
| ... | ... | @@ -19,7 +19,8 @@ I then did a `yum update` and added the following packages: |
| 19 | 19 | - goaccess |
| 20 | 20 | - postfix (for sending e-mail, e.g., to invite competitors and buoy pingers) |
| 21 | 21 | - tigervnc-server |
| 22 | - - xdm (to have a rudimentary window manager available for the VNC server) |
|
| 22 | + - WindowMaker |
|
| 23 | + - xterm |
|
| 23 | 24 | |
| 24 | 25 | Then I created a mount point /home/sailing and copied the following lines from the /etc/fstab file from an existing SL instance: |
| 25 | 26 | |
| ... | ... | @@ -84,7 +85,17 @@ Added the following two lines to `/etc/security/limits.conf`: |
| 84 | 85 | |
| 85 | 86 | This increases the maximum number of open files allowed from the default 1024 to a more appropriate 65k. |
| 86 | 87 | |
| 87 | -Copied the httpd configuration files `/etc/httpd/conf/httpd.conf`, `/etc/httpd/conf.d/000-macros.conf` and the skeletal `/etc/httpd/conf.d/001-events.conf` from an existing server. |
|
| 88 | +Copied the httpd configuration files `/etc/httpd/conf/httpd.conf`, `/etc/httpd/conf.d/000-macros.conf` and the skeletal `/etc/httpd/conf.d/001-events.conf` from an existing server. Make sure the following lines are in httpd.conf: |
|
| 89 | + |
|
| 90 | +<pre> |
|
| 91 | + SetEnvIf X-Forwarded-For "^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*).*$" original_client_ip=$1 |
|
| 92 | + LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined |
|
| 93 | + LogFormat "%v %{original_client_ip}e %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" first_forwarded_for_ip |
|
| 94 | + CustomLog logs/access_log combined env=!original_client_ip |
|
| 95 | + CustomLog logs/access_log first_forwarded_for_ip env=original_client_ip |
|
| 96 | +</pre> |
|
| 97 | + |
|
| 98 | +They ensure that the original client IPs are logged also if the Apache server runs behind a reverse proxy or an ELB. See also [the section on log file analysis](/wiki/log-file-analysis#log-file-analysis_log-file-types_apache-log-files). |
|
| 88 | 99 | |
| 89 | 100 | Copied /etc/logrotate.conf from an existing SL instance so that `/var/log/logrotate-target` is used to rotate logs to. |
| 90 | 101 |
wiki/onboarding.md
| ... | ... | @@ -67,11 +67,13 @@ First of all, make sure you've looked at http://www.amazon.de/Patterns-Elements- |
| 67 | 67 | * Rebuild all projects |
| 68 | 68 | 4. Run the Race Analysis Suite |
| 69 | 69 | * Start the MongoDB |
| 70 | - * Start the appropriate Eclipse launch configuration (e.g. 'Sailing Server (Proxy)') You´ll find this in the run dropdown |
|
| 71 | - * Run "Security UI sdm" in the run dropdown |
|
| 72 | - * Run "SailingGWT" in the run dropdown |
|
| 73 | -5. Within the Race Analysis Suite |
|
| 70 | + * Start the appropriate Eclipse launch configuration (e.g. 'Sailing Server (Proxy)') You´ll find this in the debug dropdown |
|
| 71 | + * Run "Security UI sdm" in the debug dropdown |
|
| 72 | + * Run "SailingGWT" in the debug dropdown |
|
| 73 | +5. Import races within the Race Analysis Suite |
|
| 74 | + * Choose "Security UI sdm" in the upper left corner of the "Development Mode" Tab in Eclipse and open "...Login.html" in your browser |
|
| 74 | 75 | * Default Login: user "admin", password "admin" |
| 76 | + * Choose "Sailing GWT" in the "Development Mode" Tab and open "...AdminConsole.html..." (It is normal that the first try fails. Reload the page after the first try) |
|
| 75 | 77 | * For TracTrac Events: (Date 27.11.2012) Use Live URI tcp://10.18.22.156:4412, Stored URI tcp://10.18.22.156:4413, JSON URL http://germanmaster.traclive.dk/events/event_20120905_erEuropean/jsonservice.php |
| 76 | 78 | * Press List Races |
| 77 | 79 |