diff --git a/java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/ColoradoTest.java b/java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/ColoradoTest.java index a0b6ea1ca73..8f6b3aca688 100755 --- a/java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/ColoradoTest.java +++ b/java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/ColoradoTest.java @@ -3,6 +3,9 @@ package com.sap.sailing.declination.test; import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.text.ParseException; +import java.util.GregorianCalendar; +import java.util.TimeZone; import javax.xml.parsers.ParserConfigurationException; @@ -11,14 +14,30 @@ import org.xml.sax.SAXException; import com.sap.sailing.declination.Declination; import com.sap.sailing.declination.impl.ColoradoImporter; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sse.common.impl.MillisecondsTimePoint; public class ColoradoTest { @Test public void simpleDocumentParsingTest() throws SAXException, IOException, ParserConfigurationException { final Declination declination = new ColoradoImporter().getDeclinationFromXml(getClass().getResourceAsStream("/colorado.xml")); + validateSomeDeclinationInJanuary2018(declination); + } + + private void validateSomeDeclinationInJanuary2018(final Declination declination) { assertEquals(10.0, declination.getPosition().getLatDeg(), 0.000001); assertEquals(20.0, declination.getPosition().getLngDeg(), 0.000001); assertEquals(1.89255, declination.getBearing().getDegrees(), 0.000001); assertEquals(0.10649, declination.getAnnualChange().getDegrees(), 0.000001); } + + @Test + public void simpleOnlineTest() throws IOException, ParseException { + final GregorianCalendar cal = new GregorianCalendar(2018, 0, 23); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + final Declination declination = new ColoradoImporter().getDeclination(new DegreePosition(10, 20), + new MillisecondsTimePoint(cal.getTime()), + /* timeoutForOnlineFetchInMilliseconds */ 5000); + validateSomeDeclinationInJanuary2018(declination); + } } diff --git a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/ColoradoImporter.java b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/ColoradoImporter.java index ee0d7d8d033..8019535cc76 100755 --- a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/ColoradoImporter.java +++ b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/ColoradoImporter.java @@ -2,6 +2,10 @@ package com.sap.sailing.declination.impl; import java.io.IOException; import java.io.InputStream; +import java.net.URL; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; @@ -11,8 +15,10 @@ import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.sap.sailing.declination.Declination; +import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; /** @@ -43,7 +49,9 @@ import com.sap.sse.common.impl.MillisecondsTimePoint; * @author Axel Uhl (D043530) * */ -public class ColoradoImporter { +public class ColoradoImporter extends DeclinationImporter { + private static final String URL_PATTERN = "http://magcalc.geomag.info/?model=WMM2015&sourcePage=oldCalc&decimalLatitude=%f&decimalLongitude=%f&minYear=%d&minMonth=%d&minDay=%d"; + private static class XmlElementHandler extends DefaultHandler { private double dateAsDecimalYear; private double latDeg; @@ -104,4 +112,13 @@ public class ColoradoImporter { SAXParserFactory.newInstance().newSAXParser().parse(is, handler); return handler.getDeclination(); } + + @Override + public Declination importRecord(Position position, TimePoint timePoint) + throws IOException, ParserConfigurationException, SAXException { + final Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + cal.setTime(timePoint.asDate()); + final URL url = new URL(String.format(URL_PATTERN, position.getLatDeg(), position.getLngDeg(), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH))); + return getDeclinationFromXml(url.openStream()); + } } diff --git a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/DeclinationImporter.java b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/DeclinationImporter.java new file mode 100755 index 00000000000..bd0ffa14d9e --- /dev/null +++ b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/DeclinationImporter.java @@ -0,0 +1,63 @@ +package com.sap.sailing.declination.impl; + +import java.io.IOException; +import java.text.ParseException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; + +import com.sap.sailing.declination.Declination; +import com.sap.sailing.domain.common.Position; +import com.sap.sse.common.TimePoint; + +public abstract class DeclinationImporter { + private static final Logger logger = Logger.getLogger(DeclinationImporter.class.getName()); + + public abstract Declination importRecord(Position position, TimePoint timePoint) + throws IOException, ParserConfigurationException, SAXException; + + /** + * Tries two things in parallel: fetch a more or less precise response from the online service and load + * the requested year's declination values from a stored resource to look up a value that comes close. + * The online lookup will be given preference. However, should it take longer than + * timeoutForOnlineFetchInMilliseconds, then the method will return whatever it found + * in the stored file, or null if no file exists for the year of timePoint. + * + * @param timeoutForOnlineFetchInMilliseconds if 0, this means wait forever for the online result + * @throws ParseException + * @throws ClassNotFoundException + * @throws IOException + */ + public Declination getDeclination(final Position position, final TimePoint timePoint, + long timeoutForOnlineFetchInMilliseconds) throws IOException, ParseException { + final Declination[] result = new Declination[1]; + Thread fetcher = new Thread("Declination fetcher for "+position+"@"+timePoint) { + @Override + public void run() { + try { + Declination fetched = importRecord(position, timePoint); + synchronized (result) { + result[0] = fetched; + result.notifyAll(); + } + } catch (IOException | ParserConfigurationException | SAXException e) { + logger.log(Level.FINE, "Exception while trying to load magnetic declination online", e); + } + } + }; + fetcher.start(); + synchronized (result) { + if (result[0] == null) { + try { + result.wait(timeoutForOnlineFetchInMilliseconds); + } catch (InterruptedException e) { + // ignore; simply use value from file in this case + } + } + } + return result[0]; + } +} diff --git a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java index 2e265682a56..3febf4decc3 100755 --- a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java +++ b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java @@ -4,12 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; -import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; @@ -31,8 +28,7 @@ import com.sap.sse.common.TimePoint; * @author Axel Uhl (d043530) * */ -public class NOAAImporter { - private static final Logger logger = Logger.getLogger(NOAAImporter.class.getName()); +public class NOAAImporter extends DeclinationImporter { private static final String QUERY_URL = "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination"; private static final String REGEXP_DECLINATION = "

Declination = ([0-9]*)° ([0-9]*)' *([EW])"; private static final String REGEXP_ANNUAL_CHANGE = "changing by *([0-9]*)° *([0-9]*)' ([EW])/year *

"; @@ -54,6 +50,7 @@ public class NOAAImporter { return annualChangePattern; } + @Override public Declination importRecord(Position position, TimePoint timePoint) throws IOException, ParserConfigurationException, SAXException { Declination result = null; Date date = timePoint.asDate(); @@ -80,46 +77,4 @@ public class NOAAImporter { return result; } - /** - * Tries two things in parallel: fetch a more or less precise response from the online service and load - * the requested year's declination values from a stored resource to look up a value that comes close. - * The online lookup will be given preference. However, should it take longer than - * timeoutForOnlineFetchInMilliseconds, then the method will return whatever it found - * in the stored file, or null if no file exists for the year of timePoint. - * - * @param timeoutForOnlineFetchInMilliseconds if 0, this means wait forever for the online result - * @throws ParseException - * @throws ClassNotFoundException - * @throws IOException - */ - public Declination getDeclination(final Position position, final TimePoint timePoint, - long timeoutForOnlineFetchInMilliseconds) throws IOException, ParseException { - final Declination[] result = new Declination[1]; - Thread fetcher = new Thread("Declination fetcher for "+position+"@"+timePoint) { - @Override - public void run() { - try { - Declination fetched = importRecord(position, timePoint); - synchronized (result) { - result[0] = fetched; - result.notifyAll(); - } - } catch (IOException | ParserConfigurationException | SAXException e) { - logger.log(Level.FINE, "Exception while trying to load magnetic declination online", e); - } - } - }; - fetcher.start(); - synchronized (result) { - if (result[0] == null) { - try { - result.wait(timeoutForOnlineFetchInMilliseconds); - } catch (InterruptedException e) { - // ignore; simply use value from file in this case - } - } - } - return result[0]; - } - }