diff --git a/src/main/java/no/bioforsk/vips/logic/VIPSLogicApplication.java b/src/main/java/no/bioforsk/vips/logic/VIPSLogicApplication.java index c3bf5213855c454bdb71ad24e6494ecfda5223fb..dee31d1ea086ffd74597744bf7014127935a9c64 100644 --- a/src/main/java/no/bioforsk/vips/logic/VIPSLogicApplication.java +++ b/src/main/java/no/bioforsk/vips/logic/VIPSLogicApplication.java @@ -46,6 +46,7 @@ public class VIPSLogicApplication extends Application */ private void addRestResourceClassesManually(Set<Class<?>> resources) { resources.add(no.bioforsk.vips.logic.service.LogicService.class); + resources.add(no.bioforsk.vips.logic.modules.barleynetblotch.BarleyNetBlotchModelService.class); //resources.add(no.bioforsk.vips.logic.service.JacksonConfig.class); //resources.add(no.bioforsk.vips.coremanager.service.ManagerResourceImpl.class); } @@ -56,6 +57,8 @@ public class VIPSLogicApplication extends Application * given list with all resources defined in the project. */ private void addRestResourceClasses(Set<Class<?>> resources) { + + resources.add(no.bioforsk.vips.logic.modules.barleynetblotch.BarleyNetBlotchModelService.class); resources.add(no.bioforsk.vips.logic.service.JacksonConfig.class); resources.add(no.bioforsk.vips.logic.service.LogicService.class); diff --git a/src/main/java/no/bioforsk/vips/logic/controller/session/ForecastBean.java b/src/main/java/no/bioforsk/vips/logic/controller/session/ForecastBean.java index 42fea7c6df225e3b9ec480ad30b8256625de809e..6b044aa2f3642897fa2b7444ccce22352b0ae2ed 100644 --- a/src/main/java/no/bioforsk/vips/logic/controller/session/ForecastBean.java +++ b/src/main/java/no/bioforsk/vips/logic/controller/session/ForecastBean.java @@ -524,6 +524,31 @@ public class ForecastBean { } } + public List<Result> runForecast(ModelConfiguration config, Integer VIPSCoreUserId) throws RunModelException + { + ModelRunRequest request = new ModelRunRequest(config); + Map<String,String> loginInfo = new HashMap<>(); + // VIPSLogic logs in on behalf of client + loginInfo.put("username",System.getProperty("no.bioforsk.vips.logic.CORE_BATCH_USERNAME")); + //loginInfo.put("username","wrongusername"); + loginInfo.put("password",System.getProperty("no.bioforsk.vips.logic.CORE_BATCH_PASSWORD")); + request.setLoginInfo(loginInfo); + //System.out.println("VIPSCoreUserId = " + VIPSCoreUserId + ", name=" + forecastConfiguration.getVipsLogicUserId().getLastName()); + request.setVipsCoreUserId(VIPSCoreUserId); + //System.out.println("RunModel for wsId" + forecastConfiguration.getWeatherStationPointOfInterestId()); + Response resp = this.getManagerResource().runModel(config.getModelId(), request); + + if(resp.getStatus() == Response.Status.OK.getStatusCode()) + { + List<Result> results = (List<Result>) resp.readEntity(new GenericType<List<Result>>(){}); + return results; + } + else + { + throw new RunModelException(resp.readEntity(String.class)); + } + } + /** * Get the interface for REST resources in VIPSCoreManager * @return diff --git a/src/main/java/no/bioforsk/vips/logic/controller/session/OrganismBean.java b/src/main/java/no/bioforsk/vips/logic/controller/session/OrganismBean.java index d9dc6ecebc0b9db8bd31311b519fb5221826749d..144ef1f275ae1c747069ba25896272229d79d069 100644 --- a/src/main/java/no/bioforsk/vips/logic/controller/session/OrganismBean.java +++ b/src/main/java/no/bioforsk/vips/logic/controller/session/OrganismBean.java @@ -23,10 +23,10 @@ import com.ibm.icu.util.ULocale; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import javax.ejb.Stateless; import javax.persistence.EntityManager; +import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; import no.bioforsk.vips.logic.entity.ExternalResource; @@ -36,9 +36,7 @@ import no.bioforsk.vips.logic.entity.Organism; import no.bioforsk.vips.logic.entity.OrganismExternalResource; import no.bioforsk.vips.logic.entity.OrganismLocale; import no.bioforsk.vips.logic.entity.OrganismLocalePK; -import no.bioforsk.vips.logic.i18n.SessionLocaleUtil; import no.bioforsk.vips.logic.util.HierarchyCategoryLocaleNames; -import no.bioforsk.vips.logic.util.SessionControllerGetter; /** * @copyright 2014 <a href="http://www.bioforsk.no/">Bioforsk</a> @@ -217,4 +215,36 @@ public class OrganismBean { } } + /** + * + * @param latinName Latin name of the species (assuming that latin name is unique for species) + * @return children of the specified species + */ + public List<Organism> getSpeciesChildren(String latinName) + { + HierarchyCategory speciesCat = em.createNamedQuery("HierarchyCategory.findByDefaultName", HierarchyCategory.class) + .setParameter("defaultName", "Species") + .getSingleResult(); + try + { + List<Organism> tmp = em.createNamedQuery("Organism.findByLatinName") + .setParameter("latinName", latinName) + .getResultList(); + for(Organism org : tmp) + { + if(org.getHierarchyCategoryId().equals(speciesCat.getHierarchyCategoryId())) + { + return em.createNamedQuery("Organism.findByParentOrganismId") + .setParameter("parentOrganismId", org.getOrganismId()) + .getResultList(); + } + } + } + catch(NoResultException ex) + { + return null; + } + + return null; + } } diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Currency.java b/src/main/java/no/bioforsk/vips/logic/entity/Currency.java new file mode 100644 index 0000000000000000000000000000000000000000..48322e234597015cd532dc0e23e7312695e554c6 --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/entity/Currency.java @@ -0,0 +1,108 @@ +/* + * 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.logic.entity; + +import java.io.Serializable; +import java.util.Collection; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "currency") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "Currency.findAll", query = "SELECT c FROM Currency c"), + @NamedQuery(name = "Currency.findByCurrencyId", query = "SELECT c FROM Currency c WHERE c.currencyId = :currencyId"), + @NamedQuery(name = "Currency.findByCurrencyName", query = "SELECT c FROM Currency c WHERE c.currencyName = :currencyName")}) +public class Currency implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @Basic(optional = false) + @NotNull + @Size(min = 1, max = 10) + @Column(name = "currency_id") + private String currencyId; + @Size(max = 255) + @Column(name = "currency_name") + private String currencyName; + + public Currency() { + } + + public Currency(String currencyId) { + this.currencyId = currencyId; + } + + public String getCurrencyId() { + return currencyId; + } + + public void setCurrencyId(String currencyId) { + this.currencyId = currencyId; + } + + public String getCurrencyName() { + return currencyName; + } + + public void setCurrencyName(String currencyName) { + this.currencyName = currencyName; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (currencyId != null ? currencyId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof Currency)) { + return false; + } + Currency other = (Currency) object; + if ((this.currencyId == null && other.currencyId != null) || (this.currencyId != null && !this.currencyId.equals(other.currencyId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.bioforsk.vips.logic.entity.Currency[ currencyId=" + currencyId + " ]"; + } + +} diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Organism.java b/src/main/java/no/bioforsk/vips/logic/entity/Organism.java index 2be85aff4684dd716f91d58b5476b8a2af47b8e3..204ca9af4c23d192342f4a6db24ddd4af506c7c3 100644 --- a/src/main/java/no/bioforsk/vips/logic/entity/Organism.java +++ b/src/main/java/no/bioforsk/vips/logic/entity/Organism.java @@ -19,8 +19,10 @@ package no.bioforsk.vips.logic.entity; import java.io.Serializable; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import javax.persistence.Basic; import javax.persistence.CascadeType; @@ -51,6 +53,7 @@ import javax.xml.bind.annotation.XmlRootElement; @NamedQuery(name = "Organism.findAllCrops", query = "SELECT o FROM Organism o WHERE o.isCrop = true AND o.logicallyDeleted = false"), @NamedQuery(name = "Organism.findAllPests", query = "SELECT o FROM Organism o WHERE o.isPest = true AND o.logicallyDeleted = false"), @NamedQuery(name = "Organism.findByOrganismId", query = "SELECT o FROM Organism o WHERE o.organismId = :organismId"), + @NamedQuery(name = "Organism.findByOrganismIds", query = "SELECT o FROM Organism o WHERE o.organismId IN :organismIds"), @NamedQuery(name = "Organism.findByParentOrganismId", query = "SELECT o FROM Organism o WHERE o.parentOrganismId = :parentOrganismId"), @NamedQuery(name = "Organism.findByLatinName", query = "SELECT o FROM Organism o WHERE o.latinName = :latinName"), @NamedQuery(name = "Organism.findByTradeName", query = "SELECT o FROM Organism o WHERE o.tradeName = :tradeName"), @@ -90,6 +93,9 @@ public class Organism implements Serializable { @Transient private List<Organism> childOrganisms; + @Transient + private Map<String,Object> extraProperties; + /*@OneToMany(cascade = CascadeType.ALL, mappedBy = "organism") private Set<OrganismLocale> organismLocaleSet; @OneToMany(cascade = CascadeType.ALL, mappedBy = "organism") @@ -318,4 +324,24 @@ public class Organism implements Serializable { public void setIsCrop(boolean isCrop) { this.isCrop = isCrop; } + + /** + * @return the extraProperties + */ + @Transient + public Map<String,Object> getExtraProperties() { + if(this.extraProperties == null) + { + this.extraProperties = new HashMap<>(); + } + return extraProperties; + } + + /** + * @param extraProperties the extraProperties to set + */ + @Transient + public void setExtraProperties(Map<String,Object> extraProperties) { + this.extraProperties = extraProperties; + } } diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Preparation.java b/src/main/java/no/bioforsk/vips/logic/entity/Preparation.java new file mode 100644 index 0000000000000000000000000000000000000000..e11b46fd0dfd0f302713c07c2451088a6869590d --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/entity/Preparation.java @@ -0,0 +1,141 @@ +/* + * 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.logic.entity; + +import java.io.Serializable; +import java.math.BigInteger; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "preparation") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "Preparation.findAll", query = "SELECT p FROM Preparation p"), + @NamedQuery(name = "Preparation.findByPreparationId", query = "SELECT p FROM Preparation p WHERE p.preparationId = :preparationId"), + @NamedQuery(name = "Preparation.findByPreparationName", query = "SELECT p FROM Preparation p WHERE p.preparationName = :preparationName"), + @NamedQuery(name = "Preparation.findByPrice", query = "SELECT p FROM Preparation p WHERE p.price = :price")}) +public class Preparation implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Basic(optional = false) + @Column(name = "preparation_id") + private Integer preparationId; + @Size(max = 255) + @Column(name = "preparation_name") + private String preparationName; + @Column(name = "price") + private BigInteger price; + @JoinColumn(name = "preparation_type_id", referencedColumnName = "preparation_type_id") + @ManyToOne + private PreparationType preparationTypeId; + @JoinColumn(name = "currency_id", referencedColumnName = "currency_id") + @ManyToOne + private Currency currencyId; + + public Preparation() { + } + + public Preparation(Integer preparationId) { + this.preparationId = preparationId; + } + + public Integer getPreparationId() { + return preparationId; + } + + public void setPreparationId(Integer preparationId) { + this.preparationId = preparationId; + } + + public String getPreparationName() { + return preparationName; + } + + public void setPreparationName(String preparationName) { + this.preparationName = preparationName; + } + + public BigInteger getPrice() { + return price; + } + + public void setPrice(BigInteger price) { + this.price = price; + } + + public PreparationType getPreparationTypeId() { + return preparationTypeId; + } + + public void setPreparationTypeId(PreparationType preparationTypeId) { + this.preparationTypeId = preparationTypeId; + } + + public Currency getCurrencyId() { + return currencyId; + } + + public void setCurrencyId(Currency currencyId) { + this.currencyId = currencyId; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (preparationId != null ? preparationId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof Preparation)) { + return false; + } + Preparation other = (Preparation) object; + if ((this.preparationId == null && other.preparationId != null) || (this.preparationId != null && !this.preparationId.equals(other.preparationId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.bioforsk.vips.logic.entity.Preparation[ preparationId=" + preparationId + " ]"; + } + +} diff --git a/src/main/java/no/bioforsk/vips/logic/entity/PreparationType.java b/src/main/java/no/bioforsk/vips/logic/entity/PreparationType.java new file mode 100644 index 0000000000000000000000000000000000000000..1e7c90b5d2200c9efcb9bceb2447a8bc82659152 --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/entity/PreparationType.java @@ -0,0 +1,118 @@ +/* + * 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.logic.entity; + +import java.io.Serializable; +import java.util.Collection; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "preparation_type") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "PreparationType.findAll", query = "SELECT p FROM PreparationType p"), + @NamedQuery(name = "PreparationType.findByPreparationTypeId", query = "SELECT p FROM PreparationType p WHERE p.preparationTypeId = :preparationTypeId"), + @NamedQuery(name = "PreparationType.findByPreparationTypeName", query = "SELECT p FROM PreparationType p WHERE p.preparationTypeName = :preparationTypeName")}) +public class PreparationType implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @Basic(optional = false) + @NotNull + @Column(name = "preparation_type_id") + private Integer preparationTypeId; + @Size(max = 255) + @Column(name = "preparation_type_name") + private String preparationTypeName; + @OneToMany(mappedBy = "preparationTypeId") + private Collection<Preparation> preparationCollection; + + public PreparationType() { + } + + public PreparationType(Integer preparationTypeId) { + this.preparationTypeId = preparationTypeId; + } + + public Integer getPreparationTypeId() { + return preparationTypeId; + } + + public void setPreparationTypeId(Integer preparationTypeId) { + this.preparationTypeId = preparationTypeId; + } + + public String getPreparationTypeName() { + return preparationTypeName; + } + + public void setPreparationTypeName(String preparationTypeName) { + this.preparationTypeName = preparationTypeName; + } + + @XmlTransient + public Collection<Preparation> getPreparationCollection() { + return preparationCollection; + } + + public void setPreparationCollection(Collection<Preparation> preparationCollection) { + this.preparationCollection = preparationCollection; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (preparationTypeId != null ? preparationTypeId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof PreparationType)) { + return false; + } + PreparationType other = (PreparationType) object; + if ((this.preparationTypeId == null && other.preparationTypeId != null) || (this.preparationTypeId != null && !this.preparationTypeId.equals(other.preparationTypeId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.bioforsk.vips.logic.entity.PreparationType[ preparationTypeId=" + preparationTypeId + " ]"; + } + +} diff --git a/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java new file mode 100644 index 0000000000000000000000000000000000000000..d880aee05639c8f4290f689ab8a9f9e19d82fe6b --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java @@ -0,0 +1,244 @@ +/* + * 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.logic.modules.barleynetblotch; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.PersistenceContext; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import no.bioforsk.vips.coremanager.service.ManagerResource; +import no.bioforsk.vips.entity.ModelConfiguration; +import no.bioforsk.vips.entity.Result; +import no.bioforsk.vips.entity.WeatherObservation; +import no.bioforsk.vips.logic.entity.Organism; +import no.bioforsk.vips.logic.entity.Organization; +import no.bioforsk.vips.logic.entity.PointOfInterestWeatherStation; +import no.bioforsk.vips.logic.entity.Preparation; +import no.bioforsk.vips.logic.util.RunModelException; +import no.bioforsk.vips.logic.util.SessionControllerGetter; +import no.bioforsk.vips.logic.util.SystemTime; +import no.bioforsk.vips.observation.ObservationImpl; +import no.bioforsk.vips.pestmanagement.SprayingImpl; +import no.bioforsk.vips.util.ParseRESTParamUtil; +import no.bioforsk.vips.util.WeatherElements; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; +import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Path("rest/barleynetblotchmodel") +public class BarleyNetBlotchModelService { + private final static String VIPSCOREMANAGER_URL = System.getProperty("no.bioforsk.vips.logic.VIPSCOREMANAGER_URL"); + + @PersistenceContext(unitName="VIPSLogic-PU") + EntityManager em; + + @GET + @Path("barleyvarieties/{organizationId}") + @Produces("application/json;charset=UTF-8") + public Response getBarleyVarieties(@PathParam("organizationId") Integer organizationId) + { + try + { + Organization o = em.find(Organization.class, organizationId); + List<Factors> barleyVarietyFactors = em.createNamedQuery("Factors.findByOrganizationId") + .setParameter("organizationId", o).getResultList(); + + List<Integer> varietyIds = new ArrayList<>(); + for(Factors f:barleyVarietyFactors) + { + varietyIds.add(f.getCropOrganismId()); + } + + List<Organism> barleyVarieties = new ArrayList<>(); + if(varietyIds.size() > 0) + { + barleyVarieties = em.createNamedQuery("Organism.findByOrganismIds") + .setParameter("organismIds", varietyIds).getResultList(); + for(Organism variety:barleyVarieties) + { + for(Factors f:barleyVarietyFactors) + { + if(f.getCropOrganismId().equals(variety.getOrganismId())) + { + variety.getExtraProperties().put("factors", f); + } + } + } + } + return Response.ok().entity(barleyVarieties).build(); + } + catch(NoResultException ex) + { + return Response.ok().entity(ex.getMessage()).build(); + } + + } + + @GET + @Path("preparations/{organizationId}") + @Produces("application/json;charset=UTF-8") + public Response getPreparations(@PathParam("organizationId") Integer organizationId) + { + try + { + // TODO: Get all organization children as well + // Must get the preparations first + List<Preparation> preparations = em.createNativeQuery( + "SELECT * FROM preparation " + + "WHERE organization_id = :organizationId " + + "AND preparation_id IN (" + + "SELECT preparation_id FROM barleynetb.preparation_effect_factor" + + ")", + Preparation.class) + .setParameter("organizationId", organizationId) + .getResultList(); + return Response.ok().entity(preparations).build(); + } + catch(NoResultException ex) + { + return Response.ok().entity(ex.getMessage()).build(); + } + } + + @GET + @Path("runmodel/{organizationId}") + @Produces("application/json;charset=UTF-8") + public Response runModel( + @PathParam("organizationId") Integer organizationId, + @QueryParam("timeZone") String timeZoneStr, + @QueryParam("weatherStationId") Integer weatherStationId, + @QueryParam("sowingDate") String sowingDateStr, + @QueryParam("cropId") Integer cropOrganismId, + @QueryParam("observationDate") String observationDateStr, + @QueryParam("observationValue") String observationValueStr, + @QueryParam("sameCropAsLastSeason") String sameCropAsLastSeasonStr, + @QueryParam("plowed") String plowedStr, + @QueryParam("sprayingDate") String sprayingDateStr, + @QueryParam("preparationId") String preparationIdStr, + @QueryParam("preparationDose") String preparationDoseStr + ) + { + // Some parsing needed... + ParseRESTParamUtil parseUtil = new ParseRESTParamUtil(); + TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr); + Date sowingDate = parseUtil.parseISODate(sowingDateStr, timeZone); + Date observationDate = parseUtil.parseISODateTime(observationDateStr, timeZone); + Double observationValue = parseUtil.parseDouble(observationValueStr); + Boolean sameCropAsLastSeason = parseUtil.parseCheckbox(sameCropAsLastSeasonStr); + Boolean plowed = parseUtil.parseCheckbox(plowedStr); + Date sprayingDate = parseUtil.parseISODate(sprayingDateStr, timeZone); + Integer preparationId = parseUtil.parseInteger(preparationIdStr); + Double preparationDose = parseUtil.parseDouble(preparationDoseStr); + + // Build model configuration + ModelConfiguration config = new ModelConfiguration(); + config.setModelId("BARLEYNETB"); + // Get weather data from weather station + PointOfInterestWeatherStation weatherStation = em.find(PointOfInterestWeatherStation.class, weatherStationId); + WeatherDataSourceUtil wsdUtil = new WeatherDataSourceUtil(); + Calendar cal = Calendar.getInstance(timeZone); + cal.setTime(SystemTime.getSystemTime()); + cal.add(Calendar.DATE, 10); + Date nearFuture = cal.getTime(); + List<WeatherObservation> observations; + try { + observations = wsdUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1D, + new String[]{ + WeatherElements.TEMPERATURE_MEAN, + WeatherElements.PRECIPITATION + }, + sowingDate, + nearFuture + ); + } catch (WeatherDataSourceException ex) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + + if(observations == null || observations.isEmpty()) + { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Could not find weather data for weather station with id=" + weatherStationId).build(); + } + + // Mandatory parameters + config.setConfigParameter("observations", observations); + config.setConfigParameter("timeZone", timeZone.getID()); + config.setConfigParameter("sowingDate", sowingDate); + config.setConfigParameter("plowed", plowed); + config.setConfigParameter("sameCropAsLastSeason", sameCropAsLastSeason); + // Optional parameters + if(observationDate != null && observationValue != null) + { + ObservationImpl observation = new ObservationImpl(); + observation.setName("Pyrenophora teres"); + observation.setObservedValue(observationValue); + observation.setDenominator(100); + config.setConfigParameter("observation", observation); + } + if(sprayingDate != null && preparationId != null && preparationDose != null) + { + SprayingImpl spraying = new SprayingImpl(); + spraying.setSprayingDate(sprayingDate); + PreparationEffectFactor preparationEffectFactor = em.createNamedQuery("PreparationEffectFactor.findByPreparationId", PreparationEffectFactor.class) + .setParameter("preparationId", preparationId).getSingleResult(); + spraying.setSprayingEffectFactor(preparationEffectFactor.getFactorValue().doubleValue()); + config.setConfigParameter("spraying", spraying); + } + + + // Must get the VIPSCore user id for this organization + Organization org = em.find(Organization.class, organizationId); + Integer VIPSCoreUserId = org.getDefaultVipsCoreUserId(); + + List<Result> results; + try + { + results = SessionControllerGetter.getForecastBean().runForecast(config, VIPSCoreUserId); + } + catch(RunModelException ex) + { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + return Response.ok().entity(results).build(); + } + + +} diff --git a/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/Factors.java b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/Factors.java new file mode 100644 index 0000000000000000000000000000000000000000..135f413b0b1df46785217f64f5823918dc3eb9db --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/Factors.java @@ -0,0 +1,132 @@ +/* + * 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.logic.modules.barleynetblotch; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.BigInteger; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "factors", schema = "barleynetb") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "Factors.findAll", query = "SELECT f FROM Factors f"), + @NamedQuery(name = "Factors.findByOrganizationId", query = "SELECT f FROM Factors f where f.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o = :organizationId OR o.parentOrganizationId = :organizationId)"), + @NamedQuery(name = "Factors.findByCropOrganismId", query = "SELECT f FROM Factors f WHERE f.cropOrganismId = :cropOrganismId"), + @NamedQuery(name = "Factors.findByResistanceFactor", query = "SELECT f FROM Factors f WHERE f.resistanceFactor = :resistanceFactor"), + @NamedQuery(name = "Factors.findByConversionCorrectionFactor", query = "SELECT f FROM Factors f WHERE f.conversionCorrectionFactor = :conversionCorrectionFactor")}) +public class Factors implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @Basic(optional = false) + @NotNull + @Column(name = "crop_organism_id") + private Integer cropOrganismId; + @Column(name = "organization_id") + private Integer organizationId; + @Column(name = "resistance_factor") + private BigDecimal resistanceFactor; + @Column(name = "conversion_correction_factor") + private BigDecimal conversionCorrectionFactor; + + public Factors() { + } + + public Factors(Integer cropOrganismId) { + this.cropOrganismId = cropOrganismId; + } + + public Integer getCropOrganismId() { + return cropOrganismId; + } + + public void setCropOrganismId(Integer cropOrganismId) { + this.cropOrganismId = cropOrganismId; + } + + public BigDecimal getResistanceFactor() { + return resistanceFactor; + } + + public void setResistanceFactor(BigDecimal resistanceFactor) { + this.resistanceFactor = resistanceFactor; + } + + public BigDecimal getConversionCorrectionFactor() { + return conversionCorrectionFactor; + } + + public void setConversionCorrectionFactor(BigDecimal conversionCorrectionFactor) { + this.conversionCorrectionFactor = conversionCorrectionFactor; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (cropOrganismId != null ? cropOrganismId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof Factors)) { + return false; + } + Factors other = (Factors) object; + if ((this.cropOrganismId == null && other.cropOrganismId != null) || (this.cropOrganismId != null && !this.cropOrganismId.equals(other.cropOrganismId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.bioforsk.vips.logic.modules.barleynetblotch.Factors[ cropOrganismId=" + cropOrganismId + " ]"; + } + + /** + * @return the organizationId + */ + public Integer getOrganizationId() { + return organizationId; + } + + /** + * @param organizationId the organizationId to set + */ + public void setOrganizationId(Integer organizationId) { + this.organizationId = organizationId; + } + +} diff --git a/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java new file mode 100644 index 0000000000000000000000000000000000000000..d6796f3dd3ca46c08d2296a1259410845ffdaf03 --- /dev/null +++ b/src/main/java/no/bioforsk/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java @@ -0,0 +1,114 @@ +/* + * 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.logic.modules.barleynetblotch; + +import java.io.Serializable; +import java.math.BigDecimal; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "preparation_effect_factor", schema = "barleynetb") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "PreparationEffectFactor.findAll", query = "SELECT p FROM PreparationEffectFactor p"), + @NamedQuery(name = "PreparationEffectFactor.findByPreparationId", query = "SELECT p FROM PreparationEffectFactor p WHERE p.preparationId = :preparationId"), + @NamedQuery(name = "PreparationEffectFactor.findByFullDosisMlDaa", query = "SELECT p FROM PreparationEffectFactor p WHERE p.fullDosisMlDaa = :fullDosisMlDaa"), + @NamedQuery(name = "PreparationEffectFactor.findByFactorValue", query = "SELECT p FROM PreparationEffectFactor p WHERE p.factorValue = :factorValue")}) +public class PreparationEffectFactor implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @Basic(optional = false) + @NotNull + @Column(name = "preparation_id") + private Integer preparationId; + @Column(name = "full_dosis_ml_daa") + private BigDecimal fullDosisMlDaa; + @Column(name = "factor_value") + private BigDecimal factorValue; + + public PreparationEffectFactor() { + } + + public PreparationEffectFactor(Integer preparationId) { + this.preparationId = preparationId; + } + + public Integer getPreparationId() { + return preparationId; + } + + public void setPreparationId(Integer preparationId) { + this.preparationId = preparationId; + } + + public BigDecimal getFullDosisMlDaa() { + return fullDosisMlDaa; + } + + public void setFullDosisMlDaa(BigDecimal fullDosisMlDaa) { + this.fullDosisMlDaa = fullDosisMlDaa; + } + + public BigDecimal getFactorValue() { + return factorValue; + } + + public void setFactorValue(BigDecimal factorValue) { + this.factorValue = factorValue; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (preparationId != null ? preparationId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof PreparationEffectFactor)) { + return false; + } + PreparationEffectFactor other = (PreparationEffectFactor) object; + if ((this.preparationId == null && other.preparationId != null) || (this.preparationId != null && !this.preparationId.equals(other.preparationId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.bioforsk.vips.logic.modules.barleynetblotch.PreparationEffectFactor[ preparationId=" + preparationId + " ]"; + } + +} diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/ModelRunPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/ModelRunPreprocessor.java index 0ee533e5b31759c1af027dfdd9dfc71bd82d4df7..9daeedb340064a6cbd6ba7cb42b5e732c1972485 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/ModelRunPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/ModelRunPreprocessor.java @@ -19,29 +19,8 @@ package no.bioforsk.vips.logic.scheduling.model; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -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.ModelConfiguration; -import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; -import no.bioforsk.vips.logic.entity.PointOfInterestWeatherStation; -import no.bioforsk.vips.util.weather.ParseWeatherDataException; -import no.bioforsk.vips.util.weather.WeatherForecastProvider; -import no.bioforsk.vips.util.weather.WeatherStationProviderFactory; -import org.apache.commons.io.IOUtils; /** @@ -55,210 +34,5 @@ public abstract class ModelRunPreprocessor { public abstract String getModelId(); - /** - * Collects weather observations from a data source - * @param fetchURI Base URI. E.g. http://lmt.bioforsk.no/agrometbase/export/getVIPS3JSONWeatherData.php?weatherStationId=13 - * @param logIntervalId - * @param elementMeasurementTypes - * @param startTime - * @param endTime - * @param timeZone - * @return - */ - protected List<WeatherObservation> getWeatherObservations(String fetchURI, Integer logIntervalId, String[] elementMeasurementTypes, Date startTime, Date endTime, TimeZone timeZone) throws PreprocessorException - { - SimpleDateFormat dateOutput = new SimpleDateFormat("yyyy-MM-dd"); - dateOutput.setTimeZone(timeZone); - SimpleDateFormat hourOutput = new SimpleDateFormat("H"); - hourOutput.setTimeZone(timeZone); - - StringBuilder URL = new StringBuilder(fetchURI) - .append(fetchURI.contains("?") ? "&" : "?") - .append("logIntervalId=").append(logIntervalId) - .append("&timeZone=").append(timeZone.getID()) - .append("&startDate=").append(dateOutput.format(startTime)) - .append("&startTime=").append(hourOutput.format(startTime)) - .append("&endDate=").append(dateOutput.format(endTime)) - .append("&endTime=").append(hourOutput.format(endTime)); - for(String type: elementMeasurementTypes) - { - URL.append("&elementMeasurementTypes[]=").append(type); - } - //System.out.println("URL = " + URL.toString()); - URLConnection URLConn = null; - InputStream URLStream = null; - InputStream error = null; - String URLOutput; - try - { - URL weatherURL = new URL(URL.toString()); - URLConn = weatherURL.openConnection(); - URLStream = URLConn.getInputStream(); - URLOutput = IOUtils.toString(URLStream); - List<WeatherObservation> preliminaryResult = this.getWeatherObservations(URLOutput); - // Need to filter only the values with correct resolution (logIntervalId) - List<WeatherObservation> filteredObservations = new ArrayList<>(); - for(WeatherObservation candidateObs:preliminaryResult) - { - if(candidateObs.getLogIntervalId().equals(logIntervalId)) - { - filteredObservations.add(candidateObs); - } - } - return filteredObservations; - }catch(IOException ex) - { - // Create error message to logging system - StringBuilder errorMessage = new StringBuilder() - .append("Could not fetch weather observations from URI ") - .append(URL.toString()).append(".\n"); - - // Try to get error message from weather server and append it - String errorOutput = ""; - try - { - error = ((HttpURLConnection) URLConn).getErrorStream(); - errorOutput = IOUtils.toString(error); - } - catch(IOException | NullPointerException ex2) {} - - if(errorOutput.isEmpty()) - { - errorMessage.append("There was no output from weather data server to explain this."); - } - else - { - errorMessage.append("Output from weather data server was: \n").append(errorOutput); - } - // Getting the first parts of the error message from code - errorMessage.append("\nFirst error output from code was: \n") - .append(ex.getMessage()); - throw new PreprocessorException(errorMessage.toString()); - } - finally - { - if(URLStream != null) - { - IOUtils.closeQuietly(URLStream); - } - if(error != null) - { - IOUtils.closeQuietly(error); - } - } - - } - - public List<WeatherObservation> getWeatherObservations(String JSONtext) throws IOException - { - return new ObjectMapper().readValue(JSONtext, new TypeReference<List<WeatherObservation>>(){}); - } - - /** - * Fetches measured data from the stations weather data source, and optionally - * a weather forecast provider (if so specified in the weather station configuration). - * Regarding weather forecast parameters: All requested parameters need be present in the - * forecast in order for any parameters to be fetched. So if you request e.g. TJM5 and TM, - * you won't get forecast values for any of them, because TJM5 is not present. Solve this - * by calling this method twice: Once for the parameters with forecasts, and one for the - * remaining. - * - * @param station The WeatherStation to fetch data from - * @param logIntervalId hourly/daily etc. - * @param elementMeasurementTypes Which parameters should be fetched - * @param startTime When to start - * @param endTime When to stop - * @return - * @throws PreprocessorException - */ - protected List<WeatherObservation> getWeatherObservations(PointOfInterestWeatherStation station, Integer logIntervalId, String[] elementMeasurementTypes, Date startTime, Date endTime) throws PreprocessorException - { - List<WeatherObservation> observations = this.getWeatherObservations(station.getDataFetchUri(), logIntervalId, elementMeasurementTypes, startTime, endTime, TimeZone.getTimeZone(station.getTimeZone())); - Collections.sort(observations); - Date latestTimeOfMeasuredObservations = observations.isEmpty() ? null : observations.get(observations.size()-1).getTimeMeasured(); - // If the station has a weather forecast provider, add forecasts - if(station.getWeatherForecastProviderId() != null) - { - try - { - WeatherForecastProvider forecastProvider = WeatherStationProviderFactory.getWeatherForecastProvider(station.getWeatherForecastProviderId().getWeatherForecastProviderId()); - List<WeatherObservation> forecasts = forecastProvider.getWeatherForecasts(station); - // Make sure we have the same amount and timing of the different parameters - // Create a map with one list for each parameter - Map<String, List<WeatherObservation>> obsMap = new HashMap<>(); - for(String elementMeasurementType : elementMeasurementTypes) - { - obsMap.put(elementMeasurementType, new ArrayList<WeatherObservation>()); - } - // Populate the lists and see what we've got - for(WeatherObservation obs:forecasts) - { - // We don't add irrelevant parameters from the forecast - if(obs.getLogIntervalId().equals(logIntervalId) && obsMap.get(obs.getElementMeasurementTypeId()) != null) - { - obsMap.get(obs.getElementMeasurementTypeId()).add(obs); - } - } - - // Find the latest date where all parameters are present - Date latestCommonDate = null; - for(String elementMeasurementType : elementMeasurementTypes) - { - List<WeatherObservation> paramObs = obsMap.get(elementMeasurementType); - if(paramObs.isEmpty()) - { - continue; - } - Collections.sort(paramObs); - latestCommonDate = latestCommonDate == null ? - paramObs.get(paramObs.size()-1).getTimeMeasured() - : new Date(Math.min(latestCommonDate.getTime(), paramObs.get(paramObs.size()-1).getTimeMeasured().getTime()) - ); - } - // We remove all observations after that date - // And before the measured data ends - Integer previousObsSize = null; - for(String elementMeasurementType : elementMeasurementTypes) - { - List<WeatherObservation> paramForecastObs = obsMap.get(elementMeasurementType); - List<WeatherObservation> forecastsOutsideScope = new ArrayList<>(); - for(WeatherObservation obs:paramForecastObs) - { - if(obs.getTimeMeasured().compareTo(latestCommonDate) > 0 - || (latestTimeOfMeasuredObservations != null && obs.getTimeMeasured().compareTo(latestTimeOfMeasuredObservations) <= 0) - ) - { - forecastsOutsideScope.add(obs); - } - } - paramForecastObs.removeAll(forecastsOutsideScope); - // Have we got the same amount of observations for each parameter? - if(previousObsSize != null && previousObsSize != paramForecastObs.size()) - { - throw new PreprocessorException("Weather forecast from " - + station.getWeatherForecastProviderId().getName() - + " does not provide consistent data. Array length differ " - + "between parameters for same time span. First deviation " - + "was found for " + elementMeasurementType + ", it has " - + paramForecastObs.size() + " elements, compared to " + previousObsSize - + " for the previous parameter. End of the period is " + latestCommonDate - ); - } - } - - // Everything seemingly OK, we add parameters to observation list - for(String elementMeasurementType : elementMeasurementTypes) - { - observations.addAll(obsMap.get(elementMeasurementType)); - } - - } - catch(ParseWeatherDataException ex) - { - throw new PreprocessorException(ex.getMessage()); - } - } - return observations; - } } diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java index 8bd985fc426a77685d3334e718323668a95f2472..5872a37ea2a051b73d7fd2b35213107688c2e3dd 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java @@ -28,6 +28,8 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; import no.bioforsk.vips.entity.ModelConfiguration; import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; @@ -39,6 +41,8 @@ import no.bioforsk.vips.model.ConfigValidationException; import no.bioforsk.vips.util.WeatherElements; import no.bioforsk.vips.util.WeatherObservationListException; import no.bioforsk.vips.util.WeatherUtil; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; /** * Gathers necessary data to run the Apple Scab Model (APPLESCABM). @@ -95,20 +99,26 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ { System.out.println("Getting weather data at " + new Date().toString()); } - List<WeatherObservation> observations = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.TEMPERATURE_MEAN, - WeatherElements.PRECIPITATION, - WeatherElements.LEAF_WETNESS, - WeatherElements.RELATIVE_HUMIDITY_MEAN, - WeatherElements.GLOBAL_RADIATION, - WeatherElements.WIND_SPEED_2M - }, - startDateAscosporeMaturity, - dateEndWeatherData - ); + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); + List<WeatherObservation> observations; + try { + observations = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[]{ + WeatherElements.TEMPERATURE_MEAN, + WeatherElements.PRECIPITATION, + WeatherElements.LEAF_WETNESS, + WeatherElements.RELATIVE_HUMIDITY_MEAN, + WeatherElements.GLOBAL_RADIATION, + WeatherElements.WIND_SPEED_2M + }, + startDateAscosporeMaturity, + dateEndWeatherData + ); + } catch (WeatherDataSourceException ex) { + throw new PreprocessorException(ex.getMessage()); + } if(DEBUG) { diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/DeliaRadicumModelPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/DeliaRadicumModelPreprocessor.java index 5c4306f7f27ab815173af7786873b9d728a6dbe1..80722296d37b77f957e179da360e2f21d65061ee 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/DeliaRadicumModelPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/DeliaRadicumModelPreprocessor.java @@ -23,6 +23,8 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; import no.bioforsk.vips.entity.ModelConfiguration; import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; @@ -32,6 +34,8 @@ import no.bioforsk.vips.logic.scheduling.model.PreprocessorException; import no.bioforsk.vips.logic.util.SystemTime; import no.bioforsk.vips.util.WeatherElements; import no.bioforsk.vips.util.WeatherUtil; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; /** * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> @@ -55,28 +59,38 @@ public class DeliaRadicumModelPreprocessor extends ModelRunPreprocessor { Date startDate = wUtil.normalizeToExactDate(configuration.getDateStart(), timeZone); ModelConfiguration retVal = new ModelConfiguration(); - List<WeatherObservation> observations = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1D, + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); + List<WeatherObservation> observations; + try { + observations = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1D, new String[]{ WeatherElements.TEMPERATURE_MEAN, WeatherElements.SOIL_TEMPERATURE_10CM_MEAN - }, + }, startDate, endDate); + } catch (WeatherDataSourceException ex) { + throw new PreprocessorException(ex.getMessage()); + } // If daily observations are not available, try hourly if(observations == null || observations.isEmpty()) { - observations = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.TEMPERATURE_MEAN, - WeatherElements.SOIL_TEMPERATURE_10CM_MEAN - }, - startDate, - endDate); + try { + observations = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[]{ + WeatherElements.TEMPERATURE_MEAN, + WeatherElements.SOIL_TEMPERATURE_10CM_MEAN + }, + startDate, + endDate); + } catch (WeatherDataSourceException ex) { + throw new PreprocessorException(ex.getMessage()); + } } // TODO: weather data validation diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/HoplocampaFlavaModelPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/HoplocampaFlavaModelPreprocessor.java index e95dcd8cc865d5da5ea7d6323d6f386891095a90..d484bbd5c24c7587762fba9b9ce587cc3fe8c102 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/HoplocampaFlavaModelPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/HoplocampaFlavaModelPreprocessor.java @@ -26,6 +26,8 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; import no.bioforsk.vips.entity.ModelConfiguration; import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; @@ -36,6 +38,8 @@ import no.bioforsk.vips.logic.util.SystemTime; import no.bioforsk.vips.util.WeatherElements; import no.bioforsk.vips.util.WeatherObservationListException; import no.bioforsk.vips.util.WeatherUtil; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; /** * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> @@ -59,52 +63,66 @@ public class HoplocampaFlavaModelPreprocessor extends ModelRunPreprocessor { ModelConfiguration retVal = new ModelConfiguration(); + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); + // Getting the parameters one by one // TM first - List<WeatherObservation> TM = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1D, + List<WeatherObservation> TM; + try { + TM = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1D, new String[]{ WeatherElements.TEMPERATURE_MEAN - }, + }, startDate, endDate); - // If daily observations are not available, try hourly - if(TM == null || TM.isEmpty()) - { - TM = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.TEMPERATURE_MEAN - }, - startDate, - endDate); + + // If daily observations are not available, try hourly + if(TM == null || TM.isEmpty()) + { + TM = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[]{ + WeatherElements.TEMPERATURE_MEAN + }, + startDate, + endDate); + } + } catch (WeatherDataSourceException ex) { + throw new PreprocessorException(ex.getMessage()); } // TJM5 (soil temp at 5 cm) - List<WeatherObservation> TJM5 = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1D, + List<WeatherObservation> TJM5; + try { + TJM5 = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1D, new String[]{ WeatherElements.SOIL_TEMPERATURE_5CM_MEAN - }, + }, startDate, endDate); - // If daily observations are not available, try hourly - if(TJM5 == null || TJM5.isEmpty()) - { - TJM5 = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.SOIL_TEMPERATURE_5CM_MEAN - }, - startDate, - endDate); + + // If daily observations are not available, try hourly + if(TJM5 == null || TJM5.isEmpty()) + { + TJM5 = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[]{ + WeatherElements.SOIL_TEMPERATURE_5CM_MEAN + }, + startDate, + endDate); + } + } catch (WeatherDataSourceException ex) { + throw new PreprocessorException(ex.getMessage()); } diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/NaerstadModelPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/NaerstadModelPreprocessor.java index 4b07f3570ab6660c346360fa5758c5d89560cec9..269fc3188e8a870845b869b44ffdd6f703276c2e 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/NaerstadModelPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/NaerstadModelPreprocessor.java @@ -42,6 +42,8 @@ import no.bioforsk.vips.model.ConfigValidationException; import no.bioforsk.vips.util.WeatherElements; import no.bioforsk.vips.util.WeatherObservationListException; import no.bioforsk.vips.util.WeatherUtil; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; /** * @copyright 2013-2014 <a href="http://www.bioforsk.no/">Bioforsk</a> @@ -77,29 +79,31 @@ public class NaerstadModelPreprocessor extends ModelRunPreprocessor{ cal.add(Calendar.DATE, 3); Date nearFuture = cal.getTime(); Date dateEndWeatherData = configuration.getDateEndInTimeZone().compareTo(nearFuture) < 0 ? configuration.getDateEndInTimeZone(): nearFuture; + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); + + List<WeatherObservation> observations; - List<WeatherObservation> observations = getWeatherObservations( - weatherStation.getDataFetchUri(), - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.TEMPERATURE_MEAN, - WeatherElements.PRECIPITATION, - WeatherElements.LEAF_WETNESS, - WeatherElements.RELATIVE_HUMIDITY_MEAN, - WeatherElements.GLOBAL_RADIATION, - WeatherElements.WIND_SPEED_2M - }, - configuration.getDateStartInTimeZone(), - dateEndWeatherData, - timeZone); try { - - observations = validateAndSanitizeObservations(observations, configuration.getDateStartInTimeZone()); + observations = wdsUtil.getWeatherObservations( + weatherStation.getDataFetchUri(), + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[]{ + WeatherElements.TEMPERATURE_MEAN, + WeatherElements.PRECIPITATION, + WeatherElements.LEAF_WETNESS, + WeatherElements.RELATIVE_HUMIDITY_MEAN, + WeatherElements.GLOBAL_RADIATION, + WeatherElements.WIND_SPEED_2M + }, + configuration.getDateStartInTimeZone(), + dateEndWeatherData, + timeZone); + observations = validateAndSanitizeObservations(observations, configuration.getDateStartInTimeZone()); //System.out.println(configuration.getDateStartInTimeZone()); - } catch (ConfigValidationException | WeatherObservationListException ex) { - ex.printStackTrace(); - throw new PreprocessorException(ex.getMessage()); - } + } catch (ConfigValidationException | WeatherObservationListException | WeatherDataSourceException ex) { + ex.printStackTrace(); + throw new PreprocessorException(ex.getMessage()); + } ModelConfiguration retVal = new ModelConfiguration(); retVal.setModelId(this.getModelId()); diff --git a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessor.java b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessor.java index 6a7cf3f03ba7f9bc735e609d5f44ea61439c8825..92bf4aa07ed7a66c6c74fdda7c48d5dc866af116 100644 --- a/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessor.java +++ b/src/main/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessor.java @@ -25,6 +25,8 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; import no.bioforsk.vips.entity.ModelConfiguration; import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; @@ -35,6 +37,8 @@ import no.bioforsk.vips.logic.util.SystemTime; import no.bioforsk.vips.util.WeatherElements; import no.bioforsk.vips.util.WeatherObservationListException; import no.bioforsk.vips.util.WeatherUtil; +import no.bioforsk.vips.util.weather.WeatherDataSourceException; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; /** * @copyright 2015 <a href="http://www.bioforsk.no/">Bioforsk</a> @@ -58,36 +62,40 @@ public class PlasmoparaViticolaModelPreprocessor extends ModelRunPreprocessor{ Date startDate = wUtil.normalizeToExactDate(cal.getTime(), timeZone); ModelConfiguration retVal = new ModelConfiguration(); - List<WeatherObservation> observations = getWeatherObservations( - weatherStation, - WeatherObservation.LOG_INTERVAL_ID_1H, + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); + List<WeatherObservation> observations; + try { + observations = wdsUtil.getWeatherObservations( + weatherStation, + WeatherObservation.LOG_INTERVAL_ID_1H, new String[]{ WeatherElements.TEMPERATURE_MEAN, WeatherElements.PRECIPITATION - }, + }, startDate, endDate); - /*Collections.sort(observations); - cal.set(2015, Calendar.APRIL, 10, 0, 0, 0); - Date tenth = cal.getTime(); - cal.set(2015, Calendar.APRIL, 11, 0, 0, 0); - Date eleventh = cal.getTime(); - for(WeatherObservation obs: observations) - { - if(obs.getElementMeasurementTypeId().equals("TM") - && obs.getTimeMeasured().compareTo(tenth) > 0 - && obs.getTimeMeasured().compareTo(eleventh) < 0 - ) - { - System.out.println(obs.toString()); - } - }*/ - // Weather data validation/sanitation - try { + /*Collections.sort(observations); + cal.set(2015, Calendar.APRIL, 10, 0, 0, 0); + Date tenth = cal.getTime(); + cal.set(2015, Calendar.APRIL, 11, 0, 0, 0); + Date eleventh = cal.getTime(); + for(WeatherObservation obs: observations) + { + if(obs.getElementMeasurementTypeId().equals("TM") + && obs.getTimeMeasured().compareTo(tenth) > 0 + && obs.getTimeMeasured().compareTo(eleventh) < 0 + ) + { + System.out.println(obs.toString()); + } + }*/ + + // Weather data validation/sanitation + observations = wUtil.fixHourlyValuesForParameters(observations, new HashSet(Arrays.asList(WeatherElements.TEMPERATURE_MEAN, WeatherElements.PRECIPITATION)), startDate, null); - } catch (WeatherObservationListException ex) { + } catch (WeatherDataSourceException | WeatherObservationListException ex) { throw new PreprocessorException(this.getClass().getName() + ": Missing weather data. Error message was :\n" + ex.getMessage()); } 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 414831db89bacbed567b3e5816a3ddf3c18e0faa..21acc048724cae0be0a346bbd0b5d80669208fdc 100644 --- a/src/main/java/no/bioforsk/vips/logic/service/LogicService.java +++ b/src/main/java/no/bioforsk/vips/logic/service/LogicService.java @@ -54,7 +54,6 @@ import no.bioforsk.vips.logic.entity.MessageTag; import no.bioforsk.vips.logic.entity.Observation; import no.bioforsk.vips.logic.entity.Organism; import no.bioforsk.vips.logic.entity.Organization; -import no.bioforsk.vips.logic.entity.PointOfInterest; import no.bioforsk.vips.logic.entity.PointOfInterestWeatherStation; import no.bioforsk.vips.logic.entity.VipsLogicUser; import no.bioforsk.vips.logic.util.SessionControllerGetter; diff --git a/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceException.java b/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceException.java new file mode 100644 index 0000000000000000000000000000000000000000..3f5c541a1354a46896f1c1ade163bbcbbb23cf1a --- /dev/null +++ b/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceException.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** + * @copyright 2015 <a href="http://www.bioforsk.no/">Bioforsk</a> + * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no> + */ +public class WeatherDataSourceException extends Exception { + + /** + * Creates a new instance of <code>WeatherDataSourceException</code> without detail message. + */ + public WeatherDataSourceException() { + } + + + /** + * Constructs an instance of <code>WeatherDataSourceException</code> with the specified detail message. + * @param msg the detail message. + */ + public WeatherDataSourceException(String msg) { + super(msg); + } +} diff --git a/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceUtil.java b/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..f3dfb00187916f78c3326fb772443231cdaa8d4a --- /dev/null +++ b/src/main/java/no/bioforsk/vips/util/weather/WeatherDataSourceUtil.java @@ -0,0 +1,182 @@ +/* + * 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 com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +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.logic.entity.PointOfInterestWeatherStation; +import no.bioforsk.vips.logic.scheduling.model.PreprocessorException; +import org.apache.commons.io.IOUtils; + +/** + * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class WeatherDataSourceUtil { + + /** + * Fetches measured data from the stations weather data source, and optionally + * a weather forecast provider (if so specified in the weather station configuration). + * Regarding weather forecast parameters: All requested parameters need be present in the + * forecast in order for any parameters to be fetched. So if you request e.g. TJM5 and TM, + * you won't get forecast values for any of them, because TJM5 is not present. Solve this + * by calling this method twice: Once for the parameters with forecasts, and one for the + * remaining. + * + * @param station The WeatherStation to fetch data from + * @param logIntervalId hourly/daily etc. + * @param elementMeasurementTypes Which parameters should be fetched + * @param startTime When to start + * @param endTime When to stop + * @return + * @throws PreprocessorException + */ + public List<WeatherObservation> getWeatherObservations(PointOfInterestWeatherStation station, Integer logIntervalId, String[] elementMeasurementTypes, Date startTime, Date endTime) throws WeatherDataSourceException { + List<WeatherObservation> observations = this.getWeatherObservations(station.getDataFetchUri(), logIntervalId, elementMeasurementTypes, startTime, endTime, TimeZone.getTimeZone(station.getTimeZone())); + Collections.sort(observations); + Date latestTimeOfMeasuredObservations = observations.isEmpty() ? null : observations.get(observations.size() - 1).getTimeMeasured(); + if (station.getWeatherForecastProviderId() != null) { + try { + WeatherForecastProvider forecastProvider = WeatherStationProviderFactory.getWeatherForecastProvider(station.getWeatherForecastProviderId().getWeatherForecastProviderId()); + List<WeatherObservation> forecasts = forecastProvider.getWeatherForecasts(station); + Map<String, List<WeatherObservation>> obsMap = new HashMap<>(); + for (String elementMeasurementType : elementMeasurementTypes) { + obsMap.put(elementMeasurementType, new ArrayList<WeatherObservation>()); + } + for (WeatherObservation obs : forecasts) { + if (obs.getLogIntervalId().equals(logIntervalId) && obsMap.get(obs.getElementMeasurementTypeId()) != null) { + obsMap.get(obs.getElementMeasurementTypeId()).add(obs); + } + } + Date latestCommonDate = null; + for (String elementMeasurementType : elementMeasurementTypes) { + List<WeatherObservation> paramObs = obsMap.get(elementMeasurementType); + if (paramObs.isEmpty()) { + continue; + } + Collections.sort(paramObs); + latestCommonDate = latestCommonDate == null ? paramObs.get(paramObs.size() - 1).getTimeMeasured() : new Date(Math.min(latestCommonDate.getTime(), paramObs.get(paramObs.size() - 1).getTimeMeasured().getTime())); + } + Integer previousObsSize = null; + for (String elementMeasurementType : elementMeasurementTypes) { + List<WeatherObservation> paramForecastObs = obsMap.get(elementMeasurementType); + List<WeatherObservation> forecastsOutsideScope = new ArrayList<>(); + for (WeatherObservation obs : paramForecastObs) { + if (obs.getTimeMeasured().compareTo(latestCommonDate) > 0 || (latestTimeOfMeasuredObservations != null && obs.getTimeMeasured().compareTo(latestTimeOfMeasuredObservations) <= 0)) { + forecastsOutsideScope.add(obs); + } + } + paramForecastObs.removeAll(forecastsOutsideScope); + if (previousObsSize != null && previousObsSize != paramForecastObs.size()) { + throw new WeatherDataSourceException("Weather forecast from " + station.getWeatherForecastProviderId().getName() + " does not provide consistent data. Array length differ " + "between parameters for same time span. First deviation " + "was found for " + elementMeasurementType + ", it has " + paramForecastObs.size() + " elements, compared to " + previousObsSize + " for the previous parameter. End of the period is " + latestCommonDate); + } + } + for (String elementMeasurementType : elementMeasurementTypes) { + observations.addAll(obsMap.get(elementMeasurementType)); + } + } catch (ParseWeatherDataException ex) { + throw new WeatherDataSourceException(ex.getMessage()); + } + } + return observations; + } + + public List<WeatherObservation> getWeatherObservations(String JSONtext) throws IOException { + return new ObjectMapper().readValue(JSONtext, new TypeReference<List<WeatherObservation>>() { + }); + } + + /** + * Collects weather observations from a data source + * @param fetchURI Base URI. E.g. http://lmt.bioforsk.no/agrometbase/export/getVIPS3JSONWeatherData.php?weatherStationId=13 + * @param logIntervalId + * @param elementMeasurementTypes + * @param startTime + * @param endTime + * @param timeZone + * @return + */ + public List<WeatherObservation> getWeatherObservations(String fetchURI, Integer logIntervalId, String[] elementMeasurementTypes, Date startTime, Date endTime, TimeZone timeZone) throws WeatherDataSourceException { + SimpleDateFormat dateOutput = new SimpleDateFormat("yyyy-MM-dd"); + dateOutput.setTimeZone(timeZone); + SimpleDateFormat hourOutput = new SimpleDateFormat("H"); + hourOutput.setTimeZone(timeZone); + StringBuilder URL = new StringBuilder(fetchURI).append(fetchURI.contains("?") ? "&" : "?").append("logIntervalId=").append(logIntervalId).append("&timeZone=").append(timeZone.getID()).append("&startDate=").append(dateOutput.format(startTime)).append("&startTime=").append(hourOutput.format(startTime)).append("&endDate=").append(dateOutput.format(endTime)).append("&endTime=").append(hourOutput.format(endTime)); + for (String type : elementMeasurementTypes) { + URL.append("&elementMeasurementTypes[]=").append(type); + } + //System.out.println("URL: " + URL.toString()); + URLConnection URLConn = null; + InputStream URLStream = null; + InputStream error = null; + String URLOutput; + try { + URL weatherURL = new URL(URL.toString()); + URLConn = weatherURL.openConnection(); + URLStream = URLConn.getInputStream(); + URLOutput = IOUtils.toString(URLStream); + List<WeatherObservation> preliminaryResult = this.getWeatherObservations(URLOutput); + List<WeatherObservation> filteredObservations = new ArrayList<>(); + for (WeatherObservation candidateObs : preliminaryResult) { + if (candidateObs.getLogIntervalId().equals(logIntervalId)) { + filteredObservations.add(candidateObs); + } + } + return filteredObservations; + } catch (IOException ex) { + StringBuilder errorMessage = new StringBuilder().append("Could not fetch weather observations from URI ").append(URL.toString()).append(".\n"); + String errorOutput = ""; + try { + error = ((HttpURLConnection) URLConn).getErrorStream(); + errorOutput = IOUtils.toString(error); + } catch (IOException | NullPointerException ex2) { + } + if (errorOutput.isEmpty()) { + errorMessage.append("There was no output from weather data server to explain this."); + } else { + errorMessage.append("Output from weather data server was: \n").append(errorOutput); + } + errorMessage.append("\nFirst error output from code was: \n").append(ex.getMessage()); + throw new WeatherDataSourceException(errorMessage.toString()); + } finally { + if (URLStream != null) { + IOUtils.closeQuietly(URLStream); + } + if (error != null) { + IOUtils.closeQuietly(error); + } + } + } + +} diff --git a/src/main/setup/jboss-ds.xml b/src/main/setup/jboss-ds.xml index 09938db7a1193b05f06e57a4f790dcf200c87e5c..d3623fe9d8db480415c5223daa4f8772833091e2 100644 --- a/src/main/setup/jboss-ds.xml +++ b/src/main/setup/jboss-ds.xml @@ -10,4 +10,14 @@ <max-pool-size>20</max-pool-size> <idle-timeout-minutes>5</idle-timeout-minutes> </local-tx-datasource> + <local-tx-datasource> + <jndi-name>barleynetb</jndi-name> + <connection-url>jdbc:postgresql://localhost:5432/vipslogic?searchpath=barleynetb</connection-url> + <driver-class>org.postgresql.Driver</driver-class> + <user-name>vipslogic</user-name> + <password>VIPS123</password> + <min-pool-size>5</min-pool-size> + <max-pool-size>20</max-pool-size> + <idle-timeout-minutes>5</idle-timeout-minutes> + </local-tx-datasource> </datasources> diff --git a/src/test/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessorTest.java b/src/test/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessorTest.java index 5cb688f4620819715f69e4588717bd173be6394e..c4e711bbb1675805f6552f92f04de3a9c73163d7 100644 --- a/src/test/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessorTest.java +++ b/src/test/java/no/bioforsk/vips/logic/scheduling/model/preprocessor/PlasmoparaViticolaModelPreprocessorTest.java @@ -30,6 +30,7 @@ import java.util.List; import no.bioforsk.vips.entity.ModelConfiguration; import no.bioforsk.vips.entity.WeatherObservation; import no.bioforsk.vips.logic.entity.ForecastConfiguration; +import no.bioforsk.vips.util.weather.WeatherDataSourceUtil; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.AfterClass; @@ -77,7 +78,7 @@ public class PlasmoparaViticolaModelPreprocessorTest { URLConnection URLConn = weatherURL.openConnection(); InputStream URLStream = URLConn.getInputStream(); String URLOutput = IOUtils.toString(URLStream); - List<WeatherObservation> result = instance.getWeatherObservations(URLOutput); + List<WeatherObservation> result = new WeatherDataSourceUtil().getWeatherObservations(URLOutput); }catch(IOException ex) {