mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-14 22:43:57 +00:00
direct search for valid ORC certificates using dedicated org.org API
This commit is contained in:
1 parent
9ec4525b15
commit
5aad5e596b
5 files changed
+225
-22
No files matched your search
+17
-18
@@ -1,11 +1,12 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
@@ -13,9 +14,8 @@ import org.junit.runners.model.Statement;
|
||||
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase.CertificateHandle;
|
||||
import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase.CountryOverview;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.CountryCodeFactory;
|
||||
|
||||
/***
|
||||
* A IgnoreInvalidOrcCerticatesRule is an implementation of TestRule. This class execution depends on
|
||||
@@ -57,7 +57,7 @@ public class FailIfNoValidOrcCertificateRule implements TestRule {
|
||||
this.description = description;
|
||||
availableCerts = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* This method executes for every test case having {@link TestRule} annotation of
|
||||
* {@link FailIfNoValidOrcCertificateRule} class. Assume statement at the end of this method evaluates whether
|
||||
@@ -68,22 +68,21 @@ public class FailIfNoValidOrcCertificateRule implements TestRule {
|
||||
boolean certificateExists = true;
|
||||
FailIfNoValidOrcCertificates annotation = description.getAnnotation(FailIfNoValidOrcCertificates.class);
|
||||
if (annotation != null) {
|
||||
int currentYear = LocalDate.now().getYear();
|
||||
final CountryOverview countryWithMostValidCertificates = StreamSupport
|
||||
.stream(db.getCountriesWithValidCertificates().spliterator(), /* parallel */ false)
|
||||
.max((c1, c2) -> c1.getCertCount() - c2.getCertCount()).get();
|
||||
certificateExists = false;
|
||||
for (int year=currentYear; year>=currentYear-1; year--) {
|
||||
for (CountryCode countryCode : CountryCodeFactory.INSTANCE.getAll()) {
|
||||
try {
|
||||
Iterable<CertificateHandle> certificateHandles = db.search(countryCode, year, null, null, null, null, /* includeInvalid */ false);
|
||||
Iterable<ORCCertificate> orcCertificates = db.getCertificates(certificateHandles);
|
||||
orcCertificates.forEach(availableCerts::add);
|
||||
if (orcCertificates.iterator().hasNext()) {
|
||||
certificateExists = true;
|
||||
break; // Note: this stops after the first valid certificates for a country have been read!
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Exceptions are ignored because we are searching for any country's ORC certificate availability.
|
||||
}
|
||||
try {
|
||||
Iterable<CertificateHandle> certificateHandles = db.search(countryWithMostValidCertificates.getIssuingCountry(),
|
||||
countryWithMostValidCertificates.getVPPYear(), null, null, null, null, /* includeInvalid */ false);
|
||||
Iterable<ORCCertificate> orcCertificates = db.getCertificates(certificateHandles);
|
||||
orcCertificates.forEach(availableCerts::add);
|
||||
if (orcCertificates.iterator().hasNext()) {
|
||||
certificateExists = true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "Problem trying to fetch certificates for country "+countryWithMostValidCertificates.getIssuingCountry()+
|
||||
" and year "+countryWithMostValidCertificates.getVPPYear());
|
||||
}
|
||||
}
|
||||
if (certificateExists) {
|
||||
|
||||
+15
-2
@@ -10,6 +10,9 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.commons.math.ArgumentOutsideDomainException;
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
@@ -20,6 +23,8 @@ import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ErrorCollector;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
@@ -31,7 +36,9 @@ import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveCourseImpl;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
|
||||
import com.sap.sailing.domain.orc.impl.ORCCertificatesJsonImporter;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveImpl;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
@@ -81,7 +88,8 @@ public class TestORCPerformanceCurve {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void initialize() throws IOException, ParseException {
|
||||
public static void initialize() throws IOException, ParseException, DOMException, SAXException,
|
||||
ParserConfigurationException, java.text.ParseException {
|
||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(2.23), new DegreeBearingImpl(10)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(2.00), new DegreeBearingImpl(170)));
|
||||
@@ -97,7 +105,12 @@ public class TestORCPerformanceCurve {
|
||||
File fileWithSpecificBins = new File(RESOURCES + "newFormatCertificate.json");
|
||||
importerWithSpecificBins = new ORCCertificatesJsonImporter().read(new FileInputStream(fileWithSpecificBins));
|
||||
// Online File:
|
||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownBoatRMS&CountryId=GER&ext=json").openStream());
|
||||
final CountryCode countryWithMostValidCertificates = StreamSupport
|
||||
.stream(ORCPublicCertificateDatabaseImpl.INSTANCE.getCountriesWithValidCertificates().spliterator(),
|
||||
/* parallel */ false)
|
||||
.max((c1, c2) -> c1.getCertCount() - c2.getCertCount()).get().getIssuingCountry();
|
||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownBoatRMS&CountryId="+
|
||||
countryWithMostValidCertificates.getThreeLetterIOCCode()+"&ext=json").openStream());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+9
-1
@@ -160,6 +160,14 @@ public class TestORCPublicCertificateDatabase {
|
||||
* boat class name; could be set to cert.getBoatClassName() but there are
|
||||
* deviations in ORC DBs and query API, so leaving null:
|
||||
*/ null, /* includeInvalid */ false);
|
||||
if (Util.isEmpty(certHandles)) {
|
||||
// there were certs; get one from the previous year
|
||||
certHandles = db.search(null, LocalDate.now().getYear()-1, null, cert.getBoatName(),
|
||||
cert.getSailNumber(), /*
|
||||
* boat class name; could be set to cert.getBoatClassName() but there are
|
||||
* deviations in ORC DBs and query API, so leaving null:
|
||||
*/ null, /* includeInvalid */ false);
|
||||
}
|
||||
Optional<CertificateHandle> certificateHandle = Optional.ofNullable(certHandles.iterator().hasNext() ? certHandles.iterator().next() : null);
|
||||
assertTrue("No certificate found for handle "+certificateHandle+
|
||||
" extracted from certificates "+certificates, certificateHandle.isPresent());
|
||||
@@ -188,7 +196,7 @@ public class TestORCPublicCertificateDatabase {
|
||||
new BoatClassImpl(orcCertificate.getBoatClassName(), true)));
|
||||
}
|
||||
for (Future<Set<ORCCertificate>> futureResult : futures) {
|
||||
isYearFound = isYearFound || assertFoundYear(futureResult.get(), year);
|
||||
isYearFound = isYearFound || assertFoundYear(futureResult.get(), year) || assertFoundYear(futureResult.get(), year-1);
|
||||
}
|
||||
assertTrue(isYearFound);
|
||||
}
|
||||
|
||||
+40
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -9,6 +11,11 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
@@ -128,6 +135,36 @@ public interface ORCPublicCertificateDatabase {
|
||||
return familyById.get(familyId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data about valid certificates in a country, as obtained, e.g., from http://data.orc.org/public/WPub.dll/RMS. Such a
|
||||
* record, in its original XML representation, looks like this:
|
||||
*
|
||||
* <pre>
|
||||
<CountryId>AUS</CountryId>
|
||||
<Family></Family>
|
||||
<CertType>3</CertType>
|
||||
<VPPYear>2020</VPPYear>
|
||||
<CertCount>161</CertCount>
|
||||
<CountryName>Australia</CountryName>
|
||||
<LastUpdate>2021-01-08T08:12:57.000Z</LastUpdate>
|
||||
<CertName>Club</CertName>
|
||||
<RMSCode>CLUB</RMSCode>
|
||||
* </pre>
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
public interface CountryOverview {
|
||||
CountryCode getIssuingCountry();
|
||||
CertificateFamily getFamily();
|
||||
Integer getCertType();
|
||||
Integer getVPPYear();
|
||||
int getCertCount();
|
||||
TimePoint getLastUpdate();
|
||||
String getCertName();
|
||||
String getRMSCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality and hash code of such handles is based on the {@link #getReferenceNumber() reference number} only.
|
||||
*
|
||||
@@ -229,4 +266,7 @@ public interface ORCPublicCertificateDatabase {
|
||||
Future<Set<ORCCertificate>> search(String yachtName, String sailNumber, BoatClass boatClass);
|
||||
|
||||
Date parseDate(final String dateString) throws DateTimeParseException;
|
||||
|
||||
Iterable<CountryOverview> getCountriesWithValidCertificates()
|
||||
throws SAXException, IOException, ParserConfigurationException, DOMException, ParseException;
|
||||
}
|
||||
+144
-1
@@ -2,7 +2,9 @@ package com.sap.sailing.domain.orc.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -25,12 +27,14 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.http.HttpMessage;
|
||||
import org.apache.http.HttpResponse;
|
||||
@@ -46,6 +50,7 @@ import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.BoatClassMasterdata;
|
||||
@@ -76,6 +81,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
private static final NameValuePair ACTION_PARAM = new BasicNameValuePair(ACTION_PARAM_NAME, ACTION_PARAM_VALUE_LIST_CERT);
|
||||
private static final NameValuePair XSLP_PARAM = new BasicNameValuePair(XSLP_PARAM_NAME, XSLP_PARAM_VALUE_LIST_CERT);
|
||||
private static final String SEARCH_URL = "http://data.orc.org/public/WPub.dll";
|
||||
private static final String COUNTRY_OVERVIEW_URL = SEARCH_URL+"/RMS";
|
||||
private static final String SINGLE_CERTIFICATE_DOWNLOAD_URL = "http://data.orc.org/public/WPub.dll?action=DownBoatRMS";
|
||||
private static final String ROOT_ELEMENT = "ROOT";
|
||||
private static final String DATA_ELEMENT = "DATA";
|
||||
@@ -96,6 +102,62 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
|
||||
};
|
||||
|
||||
private static class CountryOverviewImpl implements CountryOverview {
|
||||
private final CountryCode issuingCountry;
|
||||
private final CertificateFamily family;
|
||||
private final Integer certType;
|
||||
private final Integer vppYear;
|
||||
private final int certCount;
|
||||
private final TimePoint lastUpdate;
|
||||
private final String certName;
|
||||
private final String rmsCode;
|
||||
|
||||
protected CountryOverviewImpl(CountryCode issuingCountry, CertificateFamily family, Integer certType,
|
||||
Integer vppYear, int certCount, TimePoint lastUpdate, String certName, String rmsCode) {
|
||||
super();
|
||||
this.issuingCountry = issuingCountry;
|
||||
this.family = family;
|
||||
this.certType = certType;
|
||||
this.vppYear = vppYear;
|
||||
this.certCount = certCount;
|
||||
this.lastUpdate = lastUpdate;
|
||||
this.certName = certName;
|
||||
this.rmsCode = rmsCode;
|
||||
}
|
||||
@Override
|
||||
public CountryCode getIssuingCountry() {
|
||||
return issuingCountry;
|
||||
}
|
||||
@Override
|
||||
public CertificateFamily getFamily() {
|
||||
return family;
|
||||
}
|
||||
@Override
|
||||
public Integer getCertType() {
|
||||
return certType;
|
||||
}
|
||||
@Override
|
||||
public Integer getVPPYear() {
|
||||
return vppYear;
|
||||
}
|
||||
@Override
|
||||
public int getCertCount() {
|
||||
return certCount;
|
||||
}
|
||||
@Override
|
||||
public TimePoint getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
@Override
|
||||
public String getCertName() {
|
||||
return certName;
|
||||
}
|
||||
@Override
|
||||
public String getRMSCode() {
|
||||
return rmsCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code and equality as based on {@link #getReferenceNumber() the reference number field} only.
|
||||
*
|
||||
@@ -325,6 +387,81 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<CountryOverview> getCountriesWithValidCertificates()
|
||||
throws SAXException, IOException, ParserConfigurationException, DOMException, ParseException {
|
||||
final Set<ORCPublicCertificateDatabase.CountryOverview> result = new HashSet<>();
|
||||
final HttpClient client = HttpClientBuilder.create().build();
|
||||
final List<NameValuePair> params = new ArrayList<>();
|
||||
final HttpPost postRequest = new HttpPost(COUNTRY_OVERVIEW_URL);
|
||||
addAuthorizationHeader(postRequest);
|
||||
logger.fine(()->"Searching for "+params+"...");
|
||||
final HttpResponse processorResponse = client.execute(postRequest);
|
||||
final InputStream content = processorResponse.getEntity().getContent();
|
||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
final Document document = builder.parse(content);
|
||||
final NodeList dataNodes = document.getElementsByTagName(ROOT_ELEMENT).item(0).getChildNodes();
|
||||
for (int dataNodeIndex=0; dataNodeIndex<dataNodes.getLength(); dataNodeIndex++) {
|
||||
final Node dataNode = dataNodes.item(dataNodeIndex);
|
||||
if (dataNode.getNodeName().equals(DATA_ELEMENT)) {
|
||||
final NodeList rowNodes = dataNode.getChildNodes();
|
||||
for (int rowNodeIndex=0; rowNodeIndex<rowNodes.getLength(); rowNodeIndex++) {
|
||||
final Node rowNode = rowNodes.item(rowNodeIndex);
|
||||
if (rowNode.getNodeName().equals(ROW_ELEMENT)) {
|
||||
final CountryOverview countryOverview = parseCountryOverview(rowNode);
|
||||
if (countryOverview.getVPPYear() != null) {
|
||||
result.add(countryOverview);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.fine(()->"Search for "+params+" returned "+result.size()+" results");
|
||||
return result;
|
||||
}
|
||||
|
||||
private CountryOverview parseCountryOverview(Node rowNode) throws DOMException, ParseException {
|
||||
final DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.mmmX");
|
||||
CountryCode issuingCountry = null;
|
||||
CertificateFamily family = null;
|
||||
Integer certType = null;
|
||||
Integer vppYear = null;
|
||||
int certCount = 0;
|
||||
TimePoint lastUpdate = null;
|
||||
String certName = null;
|
||||
String rmsCode = null;
|
||||
for (int i=0; i<rowNode.getChildNodes().getLength(); i++) {
|
||||
final Node child = rowNode.getChildNodes().item(i);
|
||||
switch (child.getNodeName()) {
|
||||
case "CountryId":
|
||||
issuingCountry = CountryCodeFactory.INSTANCE.getFromThreeLetterIOCName(child.getTextContent().trim());
|
||||
break;
|
||||
case "Family":
|
||||
family = Util.hasLength(child.getTextContent().trim()) ? CertificateFamily.fromId(new Integer(child.getTextContent().trim())) : null;
|
||||
break;
|
||||
case "CertType":
|
||||
certType = child.getTextContent().trim().isEmpty() ? null : Integer.valueOf(child.getTextContent().trim());
|
||||
break;
|
||||
case "VPPYear":
|
||||
vppYear = child.getTextContent().trim().isEmpty() ? null : Integer.valueOf(child.getTextContent().trim());
|
||||
break;
|
||||
case "CertCount":
|
||||
certCount = Integer.valueOf(child.getTextContent().trim()).intValue();
|
||||
break;
|
||||
case "LastUpdate":
|
||||
lastUpdate = TimePoint.of(isoDateFormat.parse(child.getTextContent().trim()));
|
||||
break;
|
||||
case "CertName":
|
||||
certName = child.getTextContent().trim();
|
||||
break;
|
||||
case "RMSCode":
|
||||
rmsCode = child.getTextContent().trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new CountryOverviewImpl(issuingCountry, family, certType, vppYear, certCount, lastUpdate, certName, rmsCode);
|
||||
}
|
||||
|
||||
private void addAuthorizationHeader(final HttpMessage httpMessage) {
|
||||
httpMessage.addHeader("Authorization", "Basic "+new String(Base64.getEncoder().encode((USER_NAME+":"+getDecodedCredentials()).getBytes())));
|
||||
}
|
||||
@@ -486,7 +623,13 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
public ORCCertificate getCertificate(String referenceNumber, CertificateFamily family) throws Exception {
|
||||
final String queryParameters = "ext=json&RefNo="+referenceNumber+"&family="+family.getFamilyQueryParamValue();
|
||||
logger.fine("Obtaining certificate for reference number "+referenceNumber);
|
||||
final ORCCertificate result = getSingleCertificate(queryParameters);
|
||||
ORCCertificate result;
|
||||
try {
|
||||
result = getSingleCertificate(queryParameters);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Error trying to find ORC certificate with reference number "+referenceNumber, e);
|
||||
result = null;
|
||||
}
|
||||
if (result == null) {
|
||||
logger.info("Couldn't find ORC certificate with reference number "+referenceNumber);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user