From ef2a2ae0b1e1e95e2d446c5dbd2a52b1e169e2ae Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 17 Sep 2019 16:56:31 +0200 Subject: [PATCH] avoid code duplication in certificate importers Change-Id: Ifc44bbabf03610294a95788b82640c925c2b606b --- .../impl/AbstractORCCertificateImporter.java | 16 +++++++++ .../orc/impl/ORCCertificateImporterJSON.java | 14 ++++---- .../orc/impl/ORCCertificateImporterRMS.java | 33 ++++++------------- .../ORCPerformanceCurveRankingMetric.java | 14 +++++--- 4 files changed, 41 insertions(+), 36 deletions(-) create mode 100755 java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificateImporter.java diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificateImporter.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificateImporter.java new file mode 100755 index 00000000000..cec11d9a1a6 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificateImporter.java @@ -0,0 +1,16 @@ +package com.sap.sailing.domain.orc.impl; + +import com.sap.sailing.domain.orc.ORCCertificateImporter; + +public abstract class AbstractORCCertificateImporter implements ORCCertificateImporter { + + /** + * From a sail number which may contain spaces, also redundantly and repeatedly, as well + * as dashes, slashes or other special characters, and where upper and lower case may be mixed, + * constructs a canonicalized version such that the chances for producing a match when searching + * for a sail number is maximized, while still minimizing the chances for a false match. + */ + protected String getCanonicalizedSailNumber(String sailNumber) { + return sailNumber.replaceAll(" ", "").toUpperCase(); + } +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterJSON.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterJSON.java index eaccffb1a23..660ed55453b 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterJSON.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterJSON.java @@ -18,7 +18,6 @@ import org.json.simple.parser.ParseException; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.orc.ORCCertificate; import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl; -import com.sap.sailing.domain.orc.ORCCertificateImporter; import com.sap.sse.common.Bearing; import com.sap.sse.common.Distance; import com.sap.sse.common.Duration; @@ -38,9 +37,8 @@ import com.sap.sse.common.impl.SecondsDurationImpl; * @author Daniel Lisunkin (i505543) * */ -public class ORCCertificateImporterJSON implements ORCCertificateImporter { - - private Map data; +public class ORCCertificateImporterJSON extends AbstractORCCertificateImporter { + private Map data; private static final String RUN = "Run"; private static final String BEAT = "Beat"; private static final String WINDWARD_LEEWARD = "WL"; @@ -53,7 +51,7 @@ public class ORCCertificateImporterJSON implements ORCCertificateImporter { * {@code .json} file. */ public ORCCertificateImporterJSON(InputStream in) throws IOException, ParseException { - Map result = new HashMap<>(); + Map result = new HashMap<>(); String defaultEncoding = "UTF-8"; BOMInputStream bomInputStream = new BOMInputStream(in); ByteOrderMark bom = bomInputStream.getBOM(); @@ -63,7 +61,7 @@ public class ORCCertificateImporterJSON implements ORCCertificateImporter { JSONArray dataArray = (JSONArray) parsedJson.get("rms"); for (int i = 0; i < dataArray.size(); i++) { JSONObject object = (JSONObject) dataArray.get(i); - result.put(((String) object.get("SailNo")).replaceAll(" ", "").toUpperCase(), object); + result.put(getCanonicalizedSailNumber((String) object.get("SailNo")), object); } data = result; } @@ -83,8 +81,8 @@ public class ORCCertificateImporterJSON implements ORCCertificateImporter { Map> velocityPredictionPerTrueWindSpeedAndAngle = new HashMap<>(); Map> allowanceDurationsPerTrueWindAngleAndSpeed = new HashMap<>(); //per nautical mile Map> predefinedAllowanceDurationsPerTrueWindSpeed = new HashMap<>(); //per nautical mile - String searchString = sailnumber.replaceAll(" ", "").toUpperCase(); - JSONObject object = (JSONObject) data.get(searchString); + String searchString = getCanonicalizedSailNumber(sailnumber); + JSONObject object = data.get(searchString); if (object == null) { //TODO Throw Exception for sailnumber not found. InvalidArgumentException? return null; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterRMS.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterRMS.java index 16c7b541640..5d063888553 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterRMS.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificateImporterRMS.java @@ -6,9 +6,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -22,7 +22,6 @@ import org.apache.commons.io.input.BOMInputStream; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.orc.ORCCertificate; import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl; -import com.sap.sailing.domain.orc.ORCCertificateImporter; import com.sap.sse.common.Bearing; import com.sap.sse.common.Distance; import com.sap.sse.common.Duration; @@ -50,7 +49,7 @@ import com.sap.sse.common.impl.SecondsDurationImpl; * */ -public class ORCCertificateImporterRMS implements ORCCertificateImporter { +public class ORCCertificateImporterRMS extends AbstractORCCertificateImporter { //Codes used in the RMS document as column names for different information private static final String TWA_COURSES = "R"; private static final String CDL = "CDL"; @@ -95,30 +94,22 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { String line; while ((line = br.readLine()) != null) { final Map parsedLine = parseLine(line); - certificateValuesBySailnumber.put(parsedLine.get(sailnumberColumnName).replaceAll(" ", "").toUpperCase(), parsedLine); + certificateValuesBySailnumber.put(getCanonicalizedSailNumber(parsedLine.get(sailnumberColumnName)), parsedLine); } } public ORCCertificateImporterRMS(InputStream in) throws IOException { + this(getReaderForInputStream(in)); + } + + private static BufferedReader getReaderForInputStream(InputStream in) throws IOException, UnsupportedEncodingException { String defaultEncoding = "UTF-8"; BOMInputStream bomInputStream = new BOMInputStream(in); ByteOrderMark bom = bomInputStream.getBOM(); String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); InputStreamReader reader = new InputStreamReader(new BufferedInputStream(bomInputStream), charsetName); BufferedReader br = new BufferedReader(reader); - columnNamesAndWidths = readColumnWidthsFromFirstLine(br.readLine()); - Iterator iterator = columnNamesAndWidths.keySet().iterator(); - iterator.next(); // the first column contains the IDs of the certificates - final String sailnumberColumnName = iterator.next(); // the second column contains the sail numbers, which are easier to use for identification - certificateValuesBySailnumber = new HashMap<>(); - String line; - - while ((line = br.readLine()) != null) { - final Map parsedLine = parseLine(line); - certificateValuesBySailnumber.put(parsedLine.get(sailnumberColumnName).replaceAll(" ", "").toUpperCase(), parsedLine); - } - - br.close(); + return br; } private Map parseLine(final String line) { @@ -145,7 +136,6 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { splitBySpaceMode = true; } start = end; - } return result; } @@ -171,13 +161,13 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { } public ORCCertificateValues getValuesForSailnumber(String sailnumber) { - String searchString = sailnumber.replaceAll(" ", "").toUpperCase(); + String searchString = getCanonicalizedSailNumber(sailnumber); return certificateValuesBySailnumber.containsKey(searchString) ? new ORCCertificateValues(searchString) : null; } @Override public ORCCertificate getCertificate(String sailnumber) { - String searchString = sailnumber.replaceAll(" ", "").toUpperCase(); + String searchString = getCanonicalizedSailNumber(sailnumber); ORCCertificateValues certificateValues = getValuesForSailnumber(searchString); final String boatclass = certificateValues.getValue(BOATCLASS); final Distance length = new MeterDistance(Double.parseDouble(certificateValues.getValue(LENGTH))); @@ -194,7 +184,6 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { final Map longDistanceSpeedPredictionPerTrueWindSpeed = new HashMap<>(); final Map circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>(); final Map nonSpinnakerSpeedPredictionPerTrueWindSpeed = new HashMap<>(); - for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) { String windSpeed = Integer.toString((int) tws.getKnots()); String beatAngleKey = BEAT_ANGLE + windSpeed; @@ -227,7 +216,6 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { } velocityPredictionsPerTrueWindSpeedAndAngle.put(tws, velocityPredictionPerTrueWindAngle); } - return new ORCCertificateImpl(searchString, boatclass, length, gph, cdl, velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, @@ -239,7 +227,6 @@ public class ORCCertificateImporterRMS implements ORCCertificateImporter { @Override public Map getCertificates(String[] sailnumbers) { Map result = new HashMap<>(); - for (String sailnumber : sailnumbers) { result.put(sailnumber, getCertificate(sailnumber)); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java index 9d819c8ef0b..db87186a7ce 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java @@ -532,11 +532,15 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { try { timeForCompetitorImpliedWindCalculation = nowOrLegFinishTimeIfFinishedAtTimePoint(trackedLegOfCompetitor, timePoint, cache); final ORCPerformanceCurve competitorPerformanceCurveForLeg = getPerformanceCurveForPartialCourse(competitor, timeForCompetitorImpliedWindCalculation, cache); - final TimePoint timeForLegLeaderImpliedWindCalculation = nowOrLegFinishTimeIfFinishedAtTimePoint( - getTrackedRace().getTrackedLeg(legLeader, trackedLegOfCompetitor.getLeg()), timePoint, cache); - final Speed legLeaderImpliedWindInOrAtEndOfLeg = getImpliedWind(legLeader, timeForLegLeaderImpliedWindCalculation, cache); - final Duration correctedTimeOfLegLeaderInCompetitorsPerformanceCurve = competitorPerformanceCurveForLeg.getAllowancePerCourse(legLeaderImpliedWindInOrAtEndOfLeg); - result = actualRaceDurationForCompetitor.minus(correctedTimeOfLegLeaderInCompetitorsPerformanceCurve); + if (competitorPerformanceCurveForLeg == null) { + result = null; + } else { + final TimePoint timeForLegLeaderImpliedWindCalculation = nowOrLegFinishTimeIfFinishedAtTimePoint( + getTrackedRace().getTrackedLeg(legLeader, trackedLegOfCompetitor.getLeg()), timePoint, cache); + final Speed legLeaderImpliedWindInOrAtEndOfLeg = getImpliedWind(legLeader, timeForLegLeaderImpliedWindCalculation, cache); + final Duration correctedTimeOfLegLeaderInCompetitorsPerformanceCurve = competitorPerformanceCurveForLeg.getAllowancePerCourse(legLeaderImpliedWindInOrAtEndOfLeg); + result = actualRaceDurationForCompetitor.minus(correctedTimeOfLegLeaderInCompetitorsPerformanceCurve); + } } catch (FunctionEvaluationException | MaxIterationsExceededException e) { logger.log(Level.WARNING, "Problem with performance curve calculation for competitor "+competitor+" or "+legLeader, e); result = null;