bug5693: extract Sailti event name from one of the XRR docs referenced if available;

adjusted boat class comparison in Division, using BoatClassMasterdata.
unifyBoatClassNameBasedOnExistingMasterdata so that "N17" compares equal
to "Nacra 17" which otherwise would have been a problem as Sailti
reports the boat class name different across the XRR docs and the
HTML navigational doc
This commit is contained in:
Axel Uhl
2022-03-23 18:30:31 +01:00
parent b433c46ee4
commit f4e52b1b48
8 changed files with 135 additions and 70 deletions
@@ -51,11 +51,10 @@ public class ResultUrlRegistryImpl implements ResultUrlRegistry {
public Iterable<URL> getReadableResultUrls(String resultProviderName) { public Iterable<URL> getReadableResultUrls(String resultProviderName) {
final Subject subject = SecurityUtils.getSubject(); final Subject subject = SecurityUtils.getSubject();
final Iterable<URL> result = getAllResultUrls(resultProviderName); final Iterable<URL> result = getAllResultUrls(resultProviderName);
for (final Iterator<URL> urlIterator = result.iterator(); urlIterator.hasNext();) { for (final Iterator<URL> urlIterator = result.iterator(); urlIterator.hasNext();) {
final URL url = urlIterator.next(); final URL url = urlIterator.next();
if (!subject.isPermitted(SecuredDomainType.RESULT_IMPORT_URL if (!subject.isPermitted(SecuredDomainType.RESULT_IMPORT_URL.getStringPermissionForTypeRelativeIdentifier(
.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ, DefaultActions.READ, new TypeRelativeObjectIdentifier(resultProviderName, url.toString())))) {
new TypeRelativeObjectIdentifier(resultProviderName, url.toString())))) {
urlIterator.remove(); urlIterator.remove();
} }
} }
@@ -0,0 +1 @@
<h3>Resultados por clases:</h3><p>470 Men<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406143343.xml">XML-Pelicano_131_2360_20190406143343.xml</a><br/></p><p>470 Women<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406145455.xml">XML-Pelicano_131_2360_20190406145455.xml</a><br/></p><p>49er<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190405190140.xml">XML-Pelicano_131_2360_20190405190140.xml</a><br/></p><p>49er FX<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190405215548.xml">XML-Pelicano_131_2360_20190405215548.xml</a><br/></p><p>Finn<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406173554.xml">XML-Pelicano_131_2360_20190406173554.xml</a><br/></p><p>Laser Standard<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406155748.xml">XML-Pelicano_131_2360_20190406155748.xml</a><br/></p><p>Laser Radial<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406134243.xml">XML-Pelicano_131_2360_20190406134243.xml</a><br/></p><p>Nacra 17<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190405194348.xml">XML-Pelicano_131_2360_20190405194348.xml</a><br/></p><p>RS:X Men<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406145446.xml">XML-Pelicano_131_2360_20190406145446.xml</a><br/></p><p>RS:X Women<br/><a href="/uploaded_files/XML-Pelicano_131_2360_20190406141115.xml">XML-Pelicano_131_2360_20190406141115.xml</a><br/></p>
@@ -3,6 +3,8 @@ package com.sap.sailing.sailti.resultimport;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@@ -13,8 +15,8 @@ import com.sap.sse.common.TimePoint;
public class TestXrrFileNamePattern { public class TestXrrFileNamePattern {
@Test @Test
public void testXrrFileNamePatternWithSimpleExample() throws ParseException { public void testXrrFileNamePatternWithSimpleExample() throws ParseException, MalformedURLException {
final SailtiEventResultsParserImpl parser = new SailtiEventResultsParserImpl(); final SailtiEventResultsParserImpl parser = new SailtiEventResultsParserImpl(new URL("http://localhost"));
final String sample = "XML-Pelicano_131_5430_20220314190806.xml"; final String sample = "XML-Pelicano_131_5430_20220314190806.xml";
final Matcher matcher = SailtiEventResultsParserImpl.xrrFileNamePattern.matcher(sample); final Matcher matcher = SailtiEventResultsParserImpl.xrrFileNamePattern.matcher(sample);
assertTrue(matcher.matches()); assertTrue(matcher.matches());
@@ -0,0 +1,65 @@
package com.sap.sailing.sailti.resultimport.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.common.RegattaScoreCorrections;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryImpl;
import com.sap.sailing.sailti.resultimport.EventResultDescriptor;
import com.sap.sailing.sailti.resultimport.SailtiEventResultsParserImpl;
import com.sap.sailing.sailti.resultimport.ScoreCorrectionProviderImpl;
import com.sap.sailing.xrr.resultimport.ParserFactory;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.util.HttpUrlConnectionHelper;
public class TestParsingEventHtml {
@Test
public void parseOldEventHtml() throws IOException {
final EventResultDescriptor eventResults = new SailtiEventResultsParserImpl(new URL("http://localhost")).getEventResult(getClass().getResourceAsStream("/EventTestHtml.xml"));
assertEquals(10, eventResults.getRegattaResults().size());
}
@Test
public void parseOldEventHtmlOnline() throws IOException {
final URL url = new URL("https://www.trofeoprincesasofia.org/default/racesajax/race-results-ws/token/2360");
final EventResultDescriptor eventResults = new SailtiEventResultsParserImpl(url)
.getEventResult(HttpUrlConnectionHelper.redirectConnection(url).getInputStream());
assertEquals(10, eventResults.getRegattaResults().size());
}
@Test
public void parseXrrOfOldEventHtmlOnline() throws Exception {
final URL url = new URL("https://www.trofeoprincesasofia.org/default/racesajax/race-results-ws/token/2360");
final ResultUrlRegistry resultUrlRegistry = mock(ResultUrlRegistryImpl.class);
final ScoreCorrectionProvider scoreCorrectionProvider = new ScoreCorrectionProviderImpl(ParserFactory.INSTANCE, resultUrlRegistry);
when(resultUrlRegistry.getAllResultUrls(scoreCorrectionProvider.getName())).thenReturn(Collections.singleton(url));
when(resultUrlRegistry.getReadableResultUrls(scoreCorrectionProvider.getName())).thenReturn(Collections.singleton(url));
resultUrlRegistry.registerResultUrl(scoreCorrectionProvider.getName(), url);
final Map<String, Set<Pair<String, TimePoint>>> results = scoreCorrectionProvider.getHasResultsForBoatClassFromDateByEventName();
assertEquals(1, results.size());
final String eventName = results.keySet().iterator().next();
assertEquals("50 Trofeo S.A.R. Princesa Sofía IBEROSTAR", eventName);
final Set<Pair<String, TimePoint>> resultsPerBoatClass = results.values().iterator().next();
assertEquals(10, resultsPerBoatClass.size());
for (final Pair<String, TimePoint> boatClassAndResultTimePoint : resultsPerBoatClass) {
final RegattaScoreCorrections result = scoreCorrectionProvider.getScoreCorrections(eventName, boatClassAndResultTimePoint.getA(), boatClassAndResultTimePoint.getB());
assertNotNull(
"Expected result for event " + eventName + " and boat class " + boatClassAndResultTimePoint.getA()
+ " for time point " + boatClassAndResultTimePoint.getB() + " to not be null",
result);
}
}
}
@@ -9,13 +9,16 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.sap.sailing.xrr.resultimport.ParserFactory;
import com.sap.sailing.xrr.schema.Event;
import com.sap.sailing.xrr.schema.RegattaResults;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.util.HttpUrlConnectionHelper;
/** /**
* From a Sailti event result overview document that consists of pairs of class names and the names / URLs of the XRR documents * From a Sailti event result overview document that consists of pairs of class names and the names / URLs of the XRR documents
@@ -34,42 +37,69 @@ import com.sap.sse.common.TimePoint;
*/ */
public class SailtiEventResultsParserImpl implements SailtiEventResultsParser { public class SailtiEventResultsParserImpl implements SailtiEventResultsParser {
private static final Logger logger = Logger.getLogger(SailtiEventResultsParserImpl.class.getName()); private static final Logger logger = Logger.getLogger(SailtiEventResultsParserImpl.class.getName());
static final Pattern xrrFileNamePattern = Pattern.compile("XML-(.*)_([0-9][0-9]*)_([0-9][0-9]*)_([0-9]*).xml");
static final Pattern xrrFileNamePattern = Pattern.compile("XML-([^_]*)_([0-9][0-9]*)_([0-9][0-9]*)_([0-9]*).xml");
static final Pattern classAndXrrLinkPattern = Pattern.compile("<p>([^<]*)<br/>\\s*<a *href=\"(([^\"]*)"+xrrFileNamePattern+")\"\\s*>");
private final URL baseUrl;
public SailtiEventResultsParserImpl(URL baseUrl) {
super();
this.baseUrl = baseUrl;
}
/** /**
* @param is closed before the method returns, also in case of exception * @param is closed before the method returns, also in case of exception
*/ */
public EventResultDescriptor getEventResult(InputStream is) throws IOException { public EventResultDescriptor getEventResult(InputStream is) throws IOException {
EventResultDescriptor result = null; EventResultDescriptor result = null;
try { try {
final BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); try (final BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
List<RegattaResultDescriptor> regattaResults = new ArrayList<>(); List<RegattaResultDescriptor> regattaResults = new ArrayList<>();
String className; final StringBuilder eventHtml = new StringBuilder();
while ((className = br.readLine()) != null) { String line;
final String xrrDocumentUrl = br.readLine(); while ((line = br.readLine()) != null) {
final Matcher matcher = xrrFileNamePattern.matcher(xrrDocumentUrl); eventHtml.append(line);
if (matcher.matches()) {
regattaResults.add(new RegattaResultDescriptor(matcher.group(2), matcher.group(3), className, new URL(xrrDocumentUrl), getTimePoint(matcher)));
} }
final Matcher matcher = classAndXrrLinkPattern.matcher(eventHtml.toString());
while (matcher.find()) {
regattaResults.add(new RegattaResultDescriptor(matcher.group(1)+"/"+matcher.group(5)+"/"+matcher.group(6), matcher.group(1), getBoatClassName(matcher),
new URL(baseUrl, getAbsoluteXrrUrlPath(matcher)), getTimePoint(matcher)));
}
final String eventName;
if (regattaResults.isEmpty()) {
eventName = getEventId();
} else {
final URL xrrFinalUrl = regattaResults.iterator().next().getXrrFinalUrl();
final RegattaResults anyXrr = ParserFactory.INSTANCE.createParser(
HttpUrlConnectionHelper.redirectConnection(xrrFinalUrl).getInputStream(), xrrFinalUrl.toString()).parse();
if (anyXrr == null) {
eventName = getEventId();
} else {
eventName = anyXrr.getPersonOrBoatOrTeam().stream().filter(o->(o instanceof Event)).findAny().map(o->((Event) o).getTitle()).get();
}
}
result = new EventResultDescriptor(getEventId(), eventName, regattaResults);
} }
result = new EventResultDescriptor(/* TODO bug5693 ID */ ""+new Random().nextDouble(),
/* TODO bug5693 name */ ""+new Random().nextDouble(),
regattaResults);
is.close();
} catch(Exception e) { } catch(Exception e) {
logger.log(Level.SEVERE, "Problem parsing Sailti event document", e); logger.log(Level.SEVERE, "Problem parsing Sailti event document", e);
} finally {
is.close();
} }
return result; return result;
} }
private String getEventId() {
return baseUrl.getPath().substring(baseUrl.getPath().lastIndexOf('/')+1);
}
private String getAbsoluteXrrUrlPath(Matcher matcher) {
return matcher.group(2);
}
String getBoatClassName(Matcher matcher) { String getBoatClassName(Matcher matcher) {
return matcher.group(1); return matcher.group(1);
} }
TimePoint getTimePoint(Matcher matcher) throws ParseException { TimePoint getTimePoint(Matcher matcher) throws ParseException {
return TimePoint.of(new SimpleDateFormat("yyyyMMddhhmmssX").parse(matcher.group(4)+"Z")); return TimePoint.of(new SimpleDateFormat("yyyyMMddhhmmssX").parse(matcher.group(7)+"Z"));
} }
} }
@@ -4,7 +4,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -12,11 +11,6 @@ import com.sap.sailing.domain.resultimport.ResultUrlProvider;
import com.sap.sailing.resultimport.ResultDocumentDescriptor; import com.sap.sailing.resultimport.ResultDocumentDescriptor;
import com.sap.sailing.resultimport.ResultDocumentProvider; import com.sap.sailing.resultimport.ResultDocumentProvider;
import com.sap.sailing.resultimport.impl.ResultDocumentDescriptorImpl; import com.sap.sailing.resultimport.impl.ResultDocumentDescriptorImpl;
import com.sap.sailing.xrr.resultimport.impl.XRRParserUtil;
import com.sap.sailing.xrr.schema.Division;
import com.sap.sailing.xrr.schema.Event;
import com.sap.sailing.xrr.schema.RegattaResults;
import com.sap.sse.common.TimePoint;
import com.sap.sse.util.HttpUrlConnectionHelper; import com.sap.sse.util.HttpUrlConnectionHelper;
/** /**
@@ -34,34 +28,6 @@ public class SailtiResultDocumentProvider implements ResultDocumentProvider {
this.resultUrlProvider = resultUrlProvider; this.resultUrlProvider = resultUrlProvider;
} }
public List<ResultDocumentDescriptor> resolveResultDocumentDescriptors(RegattaResults xrrParserResult, URL url) {
List<ResultDocumentDescriptor> result = new ArrayList<>();
final TimePoint xrrDocumentDateAndTime = XRRParserUtil.calculateTimePointForRegattaResults(xrrParserResult);
for (Object o : xrrParserResult.getPersonOrBoatOrTeam()) {
if (o instanceof Event) {
Event event = (Event) o;
String eventName = event.getTitle();
for (Object d: event.getRaceOrDivisionOrRegattaSeriesResult()) {
if (d instanceof Division) {
Division division = (Division) d;
String regattaName = division.getTitle();
String boatClass = division.getTitle();
try {
String requestUrl = url.toString() + "&Class=" + URLEncoder.encode(boatClass, "UTF-8");
URL urlByClass = new URL(requestUrl);
result.add(new UrlResultDocumentDescriptorImpl(urlByClass, requestUrl, xrrDocumentDateAndTime,
eventName, regattaName, boatClass));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return result;
}
private URL getDocumentUrlForRegatta(RegattaResultDescriptor regattaResult) { private URL getDocumentUrlForRegatta(RegattaResultDescriptor regattaResult) {
return regattaResult.getXrrFinalUrl(); return regattaResult.getXrrFinalUrl();
} }
@@ -73,8 +39,8 @@ public class SailtiResultDocumentProvider implements ResultDocumentProvider {
@Override @Override
public Iterable<ResultDocumentDescriptor> getResultDocumentDescriptors() throws IOException { public Iterable<ResultDocumentDescriptor> getResultDocumentDescriptors() throws IOException {
List<ResultDocumentDescriptor> result = new ArrayList<>(); List<ResultDocumentDescriptor> result = new ArrayList<>();
SailtiEventResultsParserImpl parser = new SailtiEventResultsParserImpl();
for (URL url : resultUrlProvider.getReadableUrls()) { for (URL url : resultUrlProvider.getReadableUrls()) {
SailtiEventResultsParserImpl parser = new SailtiEventResultsParserImpl(url);
URLConnection eventResultConn = HttpUrlConnectionHelper.redirectConnection(url); URLConnection eventResultConn = HttpUrlConnectionHelper.redirectConnection(url);
EventResultDescriptor eventResult = parser.getEventResult((InputStream) eventResultConn.getContent()); EventResultDescriptor eventResult = parser.getEventResult((InputStream) eventResultConn.getContent());
addResultsForEvent(result, eventResult); addResultsForEvent(result, eventResult);
@@ -15,13 +15,13 @@ import com.sap.sse.util.HttpUrlConnectionHelper;
public class UrlResultDocumentDescriptorImpl implements ResultDocumentDescriptor { public class UrlResultDocumentDescriptorImpl implements ResultDocumentDescriptor {
private static final Logger logger = Logger.getLogger(UrlResultDocumentDescriptorImpl.class.getName()); private static final Logger logger = Logger.getLogger(UrlResultDocumentDescriptorImpl.class.getName());
private URL documentURL; private final URL documentURL;
private String documentName; private final String documentName;
private TimePoint lastModified; private final TimePoint lastModified;
private String eventName; private final String eventName;
private String regattaName; private final String regattaName;
private String boatClass; private final String boatClass;
private CompetitorGenderType competitorGenderType; private final CompetitorGenderType competitorGenderType;
public UrlResultDocumentDescriptorImpl(URL documentURL, String documentName, TimePoint lastModified) { public UrlResultDocumentDescriptorImpl(URL documentURL, String documentName, TimePoint lastModified) {
this(documentURL, documentName, lastModified, null, null, null, null); this(documentURL, documentName, lastModified, null, null, null, null);
@@ -10,6 +10,7 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; import javax.xml.bind.Unmarshaller;
import com.sap.sailing.domain.common.BoatClassMasterdata;
import com.sap.sailing.domain.common.RegattaScoreCorrections; import com.sap.sailing.domain.common.RegattaScoreCorrections;
import com.sap.sailing.domain.common.ScoreCorrectionProvider; import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.xrr.resultimport.Parser; import com.sap.sailing.xrr.resultimport.Parser;
@@ -120,10 +121,11 @@ public class ParserImpl implements Parser {
} else { } else {
divisionBoatClassAndGender = divisionBoatClass; divisionBoatClassAndGender = divisionBoatClass;
} }
if (!boatClassNameFilter.isPresent() final String unifiedBoatClassNameFilter = boatClassNameFilter.map(n->BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(n)).orElse(null);
|| boatClassNameFilter.get().equalsIgnoreCase(divisionBoatClass) if (unifiedBoatClassNameFilter == null
|| boatClassNameFilter.get().equalsIgnoreCase(divisionBoatClassAndGender) || unifiedBoatClassNameFilter.equals(BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(divisionBoatClass))
|| boatClassNameFilter.get().contains(divisionBoatClassAndGender)) { || unifiedBoatClassNameFilter.equals(BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(divisionBoatClassAndGender))
|| unifiedBoatClassNameFilter.contains(BoatClassMasterdata.unifyBoatClassNameBasedOnExistingMasterdata(divisionBoatClassAndGender))) {
return new XRRRegattaResultsAsScoreCorrections(event, division, scoreCorrectionProvider, this); return new XRRRegattaResultsAsScoreCorrections(event, division, scoreCorrectionProvider, this);
} }
} }