diff --git a/pom.xml b/pom.xml index a9f7ca38d1a992b7ca76aa63f79d6bb9d247e6e0..e7f137af89ffdbf0f1065aaac6ff4b26f673a02d 100644 --- a/pom.xml +++ b/pom.xml @@ -155,6 +155,11 @@ <groupId>com.ibm.icu</groupId> <artifactId>icu4j</artifactId> <version>52.1</version> +</dependency> +<dependency> +<groupId>jaxen</groupId> +<artifactId>jaxen</artifactId> +<version>1.1.1</version> </dependency> </dependencies> diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Observation.java b/src/main/java/no/bioforsk/vips/logic/entity/Observation.java index ef191de4790bbf481b9c39ba67045395db71032f..2a91d68bbee79173a75fb61f1de09da877218c65 100644 --- a/src/main/java/no/bioforsk/vips/logic/entity/Observation.java +++ b/src/main/java/no/bioforsk/vips/logic/entity/Observation.java @@ -56,7 +56,7 @@ import org.hibernate.annotations.Type; @NamedQuery(name = "Observation.findByTimeOfObservation", query = "SELECT o FROM Observation o WHERE o.timeOfObservation = :timeOfObservation"), @NamedQuery(name = "Observation.findByObservedValue", query = "SELECT o FROM Observation o WHERE o.observedValue = :observedValue"), @NamedQuery(name = "Observation.findByDenominator", query = "SELECT o FROM Observation o WHERE o.denominator = :denominator")}) -public class Observation implements Serializable { +public class Observation implements Serializable, no.bioforsk.vips.observation.Observation { private static final long serialVersionUID = 1L; private Integer observationId; @@ -215,4 +215,22 @@ public class Observation implements Serializable { this.organism = organism; } + @Override + @Transient + public Double getLatitude() { + return this.getLocationCoordinate().y; + } + + @Override + @Transient + public Double getLongitude() { + return this.getLocationCoordinate().x; + } + + @Override + @Transient + public String getName() { + return this.getOrganism().getLatinName(); + } + } diff --git a/src/main/java/no/bioforsk/vips/logic/service/LogicService.java b/src/main/java/no/bioforsk/vips/logic/service/LogicService.java index 83e5afca453ab55de564f35823ed1ece54389821..414831db89bacbed567b3e5816a3ddf3c18e0faa 100644 --- a/src/main/java/no/bioforsk/vips/logic/service/LogicService.java +++ b/src/main/java/no/bioforsk/vips/logic/service/LogicService.java @@ -60,6 +60,7 @@ import no.bioforsk.vips.logic.entity.VipsLogicUser; import no.bioforsk.vips.logic.util.SessionControllerGetter; import no.bioforsk.vips.logic.util.SystemTime; import no.bioforsk.vips.util.ServletUtil; +import no.bioforsk.vips.util.weather.ALabDataParser; import no.bioforsk.vips.util.weather.MetosDataParser; import no.bioforsk.vips.util.weather.ParseWeatherDataException; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; @@ -356,6 +357,40 @@ public class LogicService { return Response.ok().entity(observations).build(); } + @GET + @POST + @Path("weather/proxy/alab/{stationId}") + @Produces("application/json;charset=UTF-8") + public Response getALabWeatherData( + @PathParam("stationId") String stationId, + @FormParam("timeZone") String timeZonePOST, + @QueryParam("timeZone") String timeZoneGET, + @FormParam("startDate") String startDatePOST, + @QueryParam("startDate") String startDateGET, + @FormParam("userName") String userNamePOST, + @QueryParam("userName") String userNameGET, + @FormParam("password") String passwordPOST, + @QueryParam("password") String passwordGET + ) + { + List<WeatherObservation> observations; + try + { + String timeZoneParam = timeZonePOST != null ? timeZonePOST : timeZoneGET != null ? timeZoneGET : "UTC"; + TimeZone timeZone = TimeZone.getTimeZone(timeZoneParam); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + format.setTimeZone(timeZone); + String startDateParam = startDatePOST != null ? startDatePOST : startDateGET; + Date startDate1 = format.parse(startDateParam); + String userName = userNamePOST != null ? userNamePOST:userNameGET; + String password = passwordPOST != null ? passwordPOST:passwordGET; + observations = new ALabDataParser().getWeatherObservations(stationId, timeZone, startDate1, userName, password); + } catch (ParseException | ParseWeatherDataException | NullPointerException ex) { + return Response.serverError().entity(ex).build(); + } + return Response.ok().entity(observations).build(); + } + private ManagerResource getManagerResource() { Client client = ClientBuilder.newClient(); diff --git a/src/main/java/no/bioforsk/vips/util/weather/ALabDataParser.java b/src/main/java/no/bioforsk/vips/util/weather/ALabDataParser.java new file mode 100644 index 0000000000000000000000000000000000000000..ca8b317c07bda09cc28f26e465ee6f328f7e2abf --- /dev/null +++ b/src/main/java/no/bioforsk/vips/util/weather/ALabDataParser.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic 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 + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.bioforsk.vips.util.weather; + +import java.io.IOException; +import java.net.URL; +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import no.bioforsk.vips.entity.WeatherObservation; +import no.bioforsk.vips.util.InvalidAggregationTypeException; +import no.bioforsk.vips.util.WeatherObservationListException; +import no.bioforsk.vips.util.WeatherUtil; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Node; +import org.dom4j.io.SAXReader; + +/** + * Reads/parses data from A-Lab weather stations + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class ALabDataParser { + + private static final Map<String, String> parameters; + static { + Map<String, String> staticMap = new HashMap<>(); + staticMap.put("119", "TM"); + staticMap.put("120", "UM"); + staticMap.put("121", "RRACC"); // Accumulated rain over an unkown amount of time! + staticMap.put("122", "DD2"); + staticMap.put("123", "FF2"); + staticMap.put("124", "PPP"); + staticMap.put("125", "TJM10"); + staticMap.put("126", "VAN10p"); + parameters = Collections.unmodifiableMap(staticMap); + } + // + public final static String ALAB_URL_TEMPLATE = "http://xml.a-log.net/xml-export.cgi?devid={0}&username={1}&password={2}&measurements=all&from={3}&to={4}"; + + public List<WeatherObservation> getWeatherObservations(String stationID, TimeZone timeZone, Date startDate, String userName, String password) throws ParseWeatherDataException + { + List<WeatherObservation> retVal = new ArrayList<>(); + DateFormat timeParseFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + timeParseFormat.setTimeZone(timeZone); + + WeatherUtil wUtil = new WeatherUtil(); + startDate = wUtil.normalizeToExactDate(startDate, timeZone); + Date endDate = wUtil.normalizeToExactDate(new Date(), timeZone); + DateFormat urlDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + urlDateFormat.setTimeZone(timeZone); + String from = urlDateFormat.format(startDate); + String to = urlDateFormat.format(endDate); + + // Get the raw data from service, serialize into WeatherObservations + Map<String, List<WeatherObservation>> serialized = new HashMap<>(); + try { + URL aLabURL = new URL(MessageFormat.format(ALabDataParser.ALAB_URL_TEMPLATE, stationID,userName,password,from,to)); + Document doc = this.getDocument(aLabURL); + + // Get all measurements at 15 min intervals + // Must aggregate afterwards + List<Node> list = doc.selectNodes("//Measurement"); + + for(Node node:list) + { + Date timeMeasured = timeParseFormat.parse(node.valueOf("@Time")); + List<Node> valueNodes = node.selectNodes("Value"); + for(Node valueNode : valueNodes) + { + WeatherObservation obs = new WeatherObservation(); + obs.setTimeMeasured(timeMeasured); + obs.setElementMeasurementTypeId(ALabDataParser.parameters.get(valueNode.valueOf("@Type"))); + // Set logInterval to 15min + obs.setLogIntervalId(WeatherObservation.LOG_INTERVAL_ID_15M); + obs.setValue(Double.valueOf(valueNode.getText())); + + if(!serialized.containsKey(obs.getElementMeasurementTypeId())) + { + serialized.put(obs.getElementMeasurementTypeId(), new ArrayList<WeatherObservation>()); + } + serialized.get(obs.getElementMeasurementTypeId()).add(obs); + + } + //System.out.println(timeMeasured); + } + } + catch(IOException | DocumentException | ParseException ex) + { + throw new ParseWeatherDataException(ex.getMessage()); + } + + try + { + // Convert from 15 min intervals to hourly intervals + // Bear in mind that RRACC must be converted to RR + for(String param:serialized.keySet()) + { + List<WeatherObservation> paramObs = serialized.get(param); + paramObs = wUtil.removeDuplicateWeatherObservations(paramObs, 0.05); + if(!param.equals("RRACC")) + { + retVal.addAll(wUtil.getAggregateHourlyValues(paramObs, timeZone, WeatherObservation.LOG_INTERVAL_ID_15M, WeatherUtil.AGGREGATION_TYPE_AVERAGE)); + } + else + { + //System.out.println("RRACC being calculated"); + retVal.addAll(wUtil.getIncrementalValuesFromAccumulated(paramObs, timeZone, WeatherObservation.LOG_INTERVAL_ID_1H)); + } + } + }catch (WeatherObservationListException | InvalidAggregationTypeException ex) + { + throw new ParseWeatherDataException(ex.getMessage()); + } + Collections.sort(retVal); + + + return retVal; + } + + private Document getDocument(URL url) throws IOException, DocumentException + { + //System.out.println("URL=" + url.toString()); + /*BufferedReader in = new BufferedReader( + new InputStreamReader(url.openStream())); + + String inputLine; + while ((inputLine = in.readLine()) != null) + { + System.out.println(inputLine); + }*/ + + Document doc = new SAXReader().read(url); + return doc; + + } +} diff --git a/src/main/java/no/bioforsk/vips/util/weather/MetosDataParser.java b/src/main/java/no/bioforsk/vips/util/weather/MetosDataParser.java index c2e83e8f658d5147f0f01ff861856e90ec9e20b0..9e2ac9bda513d195938ade5a97c104d874c5239d 100644 --- a/src/main/java/no/bioforsk/vips/util/weather/MetosDataParser.java +++ b/src/main/java/no/bioforsk/vips/util/weather/MetosDataParser.java @@ -139,7 +139,7 @@ public class MetosDataParser { } } in.close(); - } catch (IOException ex) { + } catch (IOException ex) { throw new ParseWeatherDataException(ex.getMessage()); } diff --git a/src/test/java/no/bioforsk/vips/util/weather/ALabDataParserTest.java b/src/test/java/no/bioforsk/vips/util/weather/ALabDataParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..706695be1bd5991a8addbda792ba5fc659d31e8e --- /dev/null +++ b/src/test/java/no/bioforsk/vips/util/weather/ALabDataParserTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic 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 + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ +package no.bioforsk.vips.util.weather; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import no.bioforsk.vips.entity.WeatherObservation; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author treinar + */ +public class ALabDataParserTest { + + public ALabDataParserTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of getWeatherObservations method, of class ALabDataParser. + */ + //@Test + public void testGetWeatherObservations_5args() throws Exception { + System.out.println("getWeatherObservations"); + String stationID = "000000000010FDC62301"; + TimeZone timeZone = TimeZone.getTimeZone("Europe/Helsinki"); + DateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd"); + dFormat.setTimeZone(timeZone); + Date startDate = dFormat.parse("2015-01-01"); + String userName = "fmi"; + String password = "ectoncha"; + ALabDataParser instance = new ALabDataParser(); + List<WeatherObservation> expResult = null; + List<WeatherObservation> result = instance.getWeatherObservations(stationID, timeZone, startDate, userName, password); + assertNotNull(result); + /**for(WeatherObservation obs: result) + { + if(obs.getElementMeasurementTypeId().equals("RR")) + { + System.out.println(obs); + } + }*/ + } + + + +}