From a93d5d24a8acac3725cfa492893eaaccd773be60 Mon Sep 17 00:00:00 2001
From: Tor-Einar Skog <tor-einar.skog@nibio.no>
Date: Thu, 6 Oct 2022 12:46:52 +0200
Subject: [PATCH] feat:Remove WheatLeafBlotch module and GrowthStageService

---
 .../vips/logic/VIPSLogicApplication.java      |   4 -
 .../GrowthStageLocationDate.java              | 118 ------
 .../GrowthStageLocationDatePK.java            | 118 ------
 .../wheatleafblotch/ResistanceFactor.java     | 121 ------
 .../WheatLeafBlotchModelService.java          | 368 ------------------
 ...heatLeafBlotchPreparationEffectFactor.java | 113 ------
 .../modules/wheatleafblotch/YieldLoss.java    | 105 -----
 .../modules/wheatleafblotch/YieldLossPK.java  | 101 -----
 .../logic/service/GrowthStageService.java     | 251 ------------
 9 files changed, 1299 deletions(-)
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDate.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDatePK.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/ResistanceFactor.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchModelService.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchPreparationEffectFactor.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLoss.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLossPK.java
 delete mode 100644 src/main/java/no/nibio/vips/logic/service/GrowthStageService.java

diff --git a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
index 59df3b39..856d321b 100755
--- a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
+++ b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
@@ -50,7 +50,6 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.service.AuthenticationService.class);
         resources.add(no.nibio.vips.logic.service.VIPSMobileService.class);
         resources.add(no.nibio.vips.logic.modules.barleynetblotch.BarleyNetBlotchModelService.class);
-        resources.add(no.nibio.vips.logic.modules.wheatleafblotch.WheatLeafBlotchModelService.class);
         resources.add(no.nibio.vips.logic.modules.roughage.RoughageService.class);
         resources.add(no.nibio.vips.logic.modules.barkbeetle.BarkbeetleService.class);
         resources.add(no.nibio.vips.observationdata.ObservationDataService.class);
@@ -58,7 +57,6 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothService.class);
         resources.add(no.nibio.vips.logic.service.ObservationService.class);
         resources.add(no.nibio.vips.logic.service.ModelFormService.class);
-        resources.add(no.nibio.vips.logic.service.GrowthStageService.class);
         
         resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
         //resources.add(no.nibio.vips.logic.service.JSONBConfig.class);
@@ -79,9 +77,7 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.modules.barkbeetle.BarkbeetleService.class);
         resources.add(no.nibio.vips.logic.modules.barleynetblotch.BarleyNetBlotchModelService.class);
         resources.add(no.nibio.vips.logic.modules.roughage.RoughageService.class);
-        resources.add(no.nibio.vips.logic.modules.wheatleafblotch.WheatLeafBlotchModelService.class);
         resources.add(no.nibio.vips.logic.service.AuthenticationService.class);
-        resources.add(no.nibio.vips.logic.service.GrowthStageService.class);
         resources.add(no.nibio.vips.logic.service.JSONBConfig.class);
         resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
         resources.add(no.nibio.vips.logic.service.LogicService.class);
diff --git a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDate.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDate.java
deleted file mode 100644
index 7ffcbd16..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDate.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2020 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import java.io.Serializable;
-import javax.persistence.Column;
-import javax.persistence.EmbeddedId;
-import javax.persistence.Entity;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-import javax.xml.bind.annotation.XmlRootElement;
-
-/**
- * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Entity
-@Table(name = "growth_stage_location_date", schema = "wheatleafb")
-@XmlRootElement
-@NamedQueries({
-    @NamedQuery(name = "GrowthStageLocationDate.findAll", query = "SELECT g FROM GrowthStageLocationDate g"),
-    @NamedQuery(name = "GrowthStageLocationDate.findByPointOfInterestId", query = "SELECT g FROM GrowthStageLocationDate g WHERE g.growthStageLocationDatePK.pointOfInterestId = :pointOfInterestId"),
-    @NamedQuery(name = "GrowthStageLocationDate.findByCropOrganismId", query = "SELECT g FROM GrowthStageLocationDate g WHERE g.growthStageLocationDatePK.cropOrganismId = :cropOrganismId"),
-    @NamedQuery(name = "GrowthStageLocationDate.findByCropOrganismIdAndPointOfInterestId", query = "SELECT g FROM GrowthStageLocationDate g WHERE g.growthStageLocationDatePK.cropOrganismId = :cropOrganismId AND g.growthStageLocationDatePK.pointOfInterestId = :pointOfInterestId")
-})
-public class GrowthStageLocationDate implements Serializable, Comparable {
-    private static final long serialVersionUID = 1L;
-    @EmbeddedId
-    private GrowthStageLocationDatePK growthStageLocationDatePK; 
-    @Column(name = "day_number")
-    private Integer dayNumber;
-    
-
-    public GrowthStageLocationDate() {
-    }
-
-    public GrowthStageLocationDate(GrowthStageLocationDatePK growthStateLocationPK) {
-        this.growthStageLocationDatePK = growthStateLocationPK;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 0;
-        hash += (getGrowthStageLocationDatePK() != null ? getGrowthStageLocationDatePK().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 GrowthStageLocationDate)) {
-            return false;
-        }
-        GrowthStageLocationDate other = (GrowthStageLocationDate) object;
-        if ((this.getGrowthStageLocationDatePK() == null && other.getGrowthStageLocationDatePK() != null) || (this.getGrowthStageLocationDatePK() != null && !this.growthStageLocationDatePK.equals(other.growthStageLocationDatePK))) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "no.nibio.vips.logic.modules.wheatleafblotch.GrowthStageLocationDate[ growthStageLocationDatePK=" + getGrowthStageLocationDatePK() + " ]";
-    }
-
-    /**
-     * @return the dayNumber
-     */
-    public Integer getDayNumber() {
-        return dayNumber;
-    }
-
-    /**
-     * @param dayNumber the dayNumber to set
-     */
-    public void setDayNumber(Integer dayNumber) {
-        this.dayNumber = dayNumber;
-    }
-
-    @Override
-    public int compareTo(Object t) {
-        return this.getGrowthStageLocationDatePK().getGrowthStage().compareTo(((GrowthStageLocationDate) t).getGrowthStageLocationDatePK().getGrowthStage()
-        );
-    }
-
-    /**
-     * @return the growthStageLocationDatePK
-     */
-    public GrowthStageLocationDatePK getGrowthStageLocationDatePK() {
-        return growthStageLocationDatePK;
-    }
-
-    /**
-     * @param growthStageLocationDatePK the growthStageLocationDatePK to set
-     */
-    public void setGrowthStageLocationDatePK(GrowthStageLocationDatePK growthStageLocationDatePK) {
-        this.growthStageLocationDatePK = growthStageLocationDatePK;
-    }
-
-}
diff --git a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDatePK.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDatePK.java
deleted file mode 100644
index d5c69872..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/GrowthStageLocationDatePK.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2020 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import java.io.Serializable;
-import javax.persistence.Basic;
-import javax.persistence.Column;
-import javax.persistence.Embeddable;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.validation.constraints.NotNull;
-import no.nibio.vips.logic.entity.Organism;
-import no.nibio.vips.logic.entity.PointOfInterest;
-
-/**
- * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Embeddable
-public class GrowthStageLocationDatePK implements Serializable {
-
-    @Basic(optional = false)
-    @NotNull
-    @JoinColumn(name = "crop_organism_id", referencedColumnName = "organism_id")
-    @ManyToOne
-    private Organism cropOrganismId;
-    @Basic(optional = false)
-    @NotNull
-    @JoinColumn(name = "point_of_interest_id", referencedColumnName = "point_of_interest_id")
-    @ManyToOne
-    private PointOfInterest pointOfInterestId;
-    @Column(name = "growth_stage")
-    private Integer growthStage;
-    
-
-    public GrowthStageLocationDatePK() {
-    }
-
-    public GrowthStageLocationDatePK(Organism organism, PointOfInterest pointOfInterestId) {
-        this.cropOrganismId = organism;
-        this.pointOfInterestId = pointOfInterestId;
-    }
-
-    public Organism getCropOrganismId() {
-        return cropOrganismId;
-    }
-
-    public void setCropOrganismId(Organism cropOrganismId) {
-        this.cropOrganismId = cropOrganismId;
-    }
-
-    public PointOfInterest getPointOfInterestId() {
-        return pointOfInterestId;
-    }
-
-    public void setPointOfInterestId(PointOfInterest pointOfInterestId) {
-        this.pointOfInterestId = pointOfInterestId;
-    }
-    
-    public Integer getGrowthStage() {
-        return growthStage;
-    }
-
-    public void setGrowthStage(Integer growthStage) {
-        this.growthStage = growthStage;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 0;
-        hash += (int) cropOrganismId.getOrganismId();
-        hash += (int) pointOfInterestId.getPointOfInterestId();
-        hash += (int) growthStage;
-        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 GrowthStageLocationDatePK)) {
-            return false;
-        }
-        GrowthStageLocationDatePK other = (GrowthStageLocationDatePK) object;
-        if (this.cropOrganismId != other.cropOrganismId) {
-            return false;
-        }
-        if (this.pointOfInterestId != other.pointOfInterestId) {
-            return false;
-        }
-        if(! this.growthStage.equals(other.growthStage)){
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "no.nibio.vips.logic.modules.wheatleafblotch.YieldLossPK[ organism=" + cropOrganismId + ", pointOfInterestId=" + pointOfInterestId + " ]";
-    }
-
-}
diff --git a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/ResistanceFactor.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/ResistanceFactor.java
deleted file mode 100644
index 175f13c9..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/ResistanceFactor.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.nibio.vips.logic.modules.wheatleafblotch;
-
-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 2018 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Entity
-@Table(name = "resistance_factor", schema = "wheatleafb")
-@XmlRootElement
-@NamedQueries({
-    @NamedQuery(name = "ResistanceFactor.findAll", query = "SELECT f FROM Factors f"),
-    @NamedQuery(name = "ResistanceFactor.findByOrganizationId", query = "SELECT f FROM ResistanceFactor f where f.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o = :organizationId OR o.parentOrganizationId = :organizationId)"),
-    @NamedQuery(name = "ResistanceFactor.findByCropOrganismId", query = "SELECT f FROM ResistanceFactor f WHERE f.cropOrganismId = :cropOrganismId"),
-    @NamedQuery(name = "ResistanceFactor.findByResistanceFactor", query = "SELECT f FROM ResistanceFactor f WHERE f.resistanceFactor = :resistanceFactor")
-})
-public class ResistanceFactor 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;
-
-    public ResistanceFactor() {
-    }
-
-    public ResistanceFactor(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;
-    }
-
-    @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 ResistanceFactor)) {
-            return false;
-        }
-        ResistanceFactor other = (ResistanceFactor) 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.nibio.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/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchModelService.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchModelService.java
deleted file mode 100644
index 77208990..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchModelService.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import com.webcohesion.enunciate.metadata.Facet;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.TimeZone;
-import javax.ejb.EJB;
-import javax.persistence.EntityManager;
-import javax.persistence.NoResultException;
-import javax.persistence.PersistenceContext;
-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.core.Response;
-import no.nibio.vips.entity.ModelConfiguration;
-import no.nibio.vips.entity.Result;
-import no.nibio.vips.entity.WeatherObservation;
-import no.nibio.vips.logic.controller.session.ForecastBean;
-import no.nibio.vips.logic.entity.Organism;
-import no.nibio.vips.logic.entity.Organization;
-import no.nibio.vips.logic.entity.PointOfInterestWeatherStation;
-import no.nibio.vips.logic.entity.Preparation;
-import no.nibio.vips.logic.util.RunModelException;
-import no.nibio.vips.logic.util.SystemTime;
-import no.nibio.vips.observation.ObservationImpl;
-import no.nibio.vips.pestmanagement.SprayingImpl;
-import no.nibio.vips.util.ParseRESTParamUtil;
-import no.nibio.vips.util.WeatherElements;
-import no.nibio.vips.util.weather.WeatherDataSourceException;
-import no.nibio.vips.util.weather.WeatherDataSourceUtil;
-
-/**
- * @copyright 2018-2022 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Path("rest/wheatleafblotchmodel")
-@Facet("restricted")
-public class WheatLeafBlotchModelService {
-    private final static String VIPSCOREMANAGER_URL = System.getProperty("no.nibio.vips.logic.VIPSCOREMANAGER_URL");
-    
-    @PersistenceContext(unitName="VIPSLogic-PU")
-    EntityManager em;
-    
-    @EJB
-    ForecastBean forecastBean;
-
-    @GET
-    @Path("wheatvarieties/{organizationId}")
-    @Produces("application/json;charset=UTF-8")
-    public Response getWheatVarieties(@PathParam("organizationId") Integer organizationId)
-    {
-        try
-        {
-            Organization o = em.find(Organization.class, organizationId);
-            List<ResistanceFactor> resistanceFactors = em.createNamedQuery("ResistanceFactor.findByOrganizationId")
-                .setParameter("organizationId", o).getResultList();
-            
-            List<Organism> wheatTypes = em.createNativeQuery("SELECT * FROM public.organism WHERE parent_organism_id IN ("
-                    + "SELECT organism_id FROM public.organism WHERE latin_name='Triticum'"
-                    + ")", Organism.class).getResultList();
-            
-            List<Integer> varietyIds = new ArrayList<>();
-            for(ResistanceFactor f:resistanceFactors)
-            {
-                varietyIds.add(f.getCropOrganismId());
-            }
-            
-            List<Organism> wheatVarieties = new ArrayList<>();
-            
-            if(varietyIds.size() > 0)
-            {
-                wheatVarieties = em.createNamedQuery("Organism.findByOrganismIds")
-                        .setParameter("organismIds", varietyIds).getResultList();
-                for(Organism variety:wheatVarieties)
-                {
-                    for(ResistanceFactor f:resistanceFactors)
-                    {
-                        if(f.getCropOrganismId().equals(variety.getOrganismId()))
-                        {
-                            variety.getExtraProperties().put("factors", f);
-                        }
-                    }
-                    for(Organism type:wheatTypes)
-                    {
-                        if(variety.getParentOrganismId().equals(type.getOrganismId()))
-                        {
-                            variety.getExtraProperties().put("type", type);
-                        }
-                    }
-                }
-            }
-            return Response.ok().entity(wheatVarieties).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 wheatleafb.wheatleafblotch_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();
-        }
-    }
-    
-    /**
-     * Returns the yield loss from Septoria in wheat(?)
-     * @param organizationId
-     * @param season
-     * @return 
-     */
-    @GET
-    @Path("yieldloss/septoria/{organizationId}/{season}")
-    @Produces("application/json;charset=UTF-8")
-    public Response getYieldLoss(
-            @PathParam("organizationId") Integer organizationId,
-            @PathParam("season") Integer season
-    )
-    {
-        List<YieldLoss> retVal;
-        if(organizationId <= 0)
-        {
-            retVal = em.createNamedQuery("YieldLoss.findBySeason")
-                    .setParameter("season", season)
-                    .getResultList();
-        }
-        else
-        {
-            retVal = em.createNativeQuery("SELECT * FROM wheatleafb.yield_loss \n" +
-                    "WHERE season = :season\n" +
-                    "AND point_of_interest_id IN (\n" +
-                    "	SELECT point_of_interest_id FROM point_of_interest\n" +
-                    "	WHERE user_id IN (SELECT user_id FROM vips_logic_user WHERE organization_id = :organizationId" +
-                    "       )\n" +
-                    ")"
-                    , 
-                    YieldLoss.class
-                    )
-                    .setParameter("organizationId", organizationId)
-                    .setParameter("season", season)
-                    .getResultList();
-        }
-        return Response.ok().entity(retVal).build();
-    }
-    
-    @GET
-    @Path("runmodel/{organizationId}")
-    @Produces("application/json;charset=UTF-8")
-    public Response runModel(
-            @PathParam("organizationId") Integer organizationId,
-            @QueryParam("wheatType") Integer wheatType,
-            @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("preparationId1") String preparationId1Str,
-            @QueryParam("preparationDose1") String preparationDose1Str,
-            @QueryParam("preparationId2") String preparationId2Str,
-            @QueryParam("preparationDose2") String preparationDose2Str,
-            @QueryParam("preparationId3") String preparationId3Str,
-            @QueryParam("preparationDose3") String preparationDose3Str
-    )
-    {
-        // Some parsing needed...
-        ParseRESTParamUtil parseUtil = new ParseRESTParamUtil();
-        TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
-        Date sowingDate = parseUtil.parseISODate(sowingDateStr, timeZone);
-        Date observationDate = parseUtil.parseISODateTime(observationDateStr, timeZone);
-        // In case it's just a date string
-        if(observationDate == null)
-        {
-            observationDate = parseUtil.parseISODate(observationDateStr, timeZone);
-        }
-        Double observationValue = parseUtil.parseDouble(observationValueStr);
-        Boolean sameCropAsLastSeason = parseUtil.parseCheckbox(sameCropAsLastSeasonStr);
-        Boolean plowed =  parseUtil.parseCheckbox(plowedStr);
-        Date sprayingDate = parseUtil.parseISODate(sprayingDateStr, timeZone);
-        Integer preparationId1 = parseUtil.parseInteger(preparationId1Str);
-        Double preparationDose1 = parseUtil.parseDouble(preparationDose1Str);
-        Integer preparationId2 = parseUtil.parseInteger(preparationId2Str);
-        Double preparationDose2 = parseUtil.parseDouble(preparationDose2Str);
-        Integer preparationId3 = parseUtil.parseInteger(preparationId3Str);
-        Double preparationDose3 = parseUtil.parseDouble(preparationDose3Str);
-        
-        // Build model configuration
-        ModelConfiguration config = new ModelConfiguration();
-        config.setModelId("WLEAFBLTCH");
-        // Get weather data from weather station
-        PointOfInterestWeatherStation weatherStation = em.find(PointOfInterestWeatherStation.class, weatherStationId);
-        WeatherDataSourceUtil wsdUtil = new WeatherDataSourceUtil();
-        
-        String[] parameterList;
-        
-        // End date for weather data depends on season
-        // We try to add 5 months to the sowing date. If that's in the future,
-        // We add 10 days to today
-        Date dateOfFirstWeatherData;
-        Date dateOfLastWeatherData;
-        Calendar cal = Calendar.getInstance(timeZone);
-        cal.setTime(sowingDate);
-        // If winter wheat, the sowing date is after August 1st. We get weather 
-        // data from March 1st the following year. And we need soil temperature
-        if(cal.get(Calendar.MONTH) > Calendar.JULY)
-        {
-            cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 1);
-            cal.set(Calendar.MONTH, Calendar.MARCH);
-            cal.set(Calendar.DATE, 1);
-            parameterList = new String[]{
-                        WeatherElements.TEMPERATURE_MEAN,
-                        WeatherElements.PRECIPITATION,
-                        WeatherElements.SOIL_TEMPERATURE_10CM_MEAN
-                    };
-        }
-        else
-        {
-            cal.add(Calendar.MONTH, -1);
-            parameterList = new String[]{
-                        WeatherElements.TEMPERATURE_MEAN,
-                        WeatherElements.PRECIPITATION
-                    };
-        }
-        dateOfFirstWeatherData = cal.getTime();
-        cal.add(Calendar.MONTH, 6);
-        Date fiveMonthsAfterSowingDate = cal.getTime();
-        if(fiveMonthsAfterSowingDate.after(SystemTime.getSystemTime()))
-        {
-            cal.setTime(SystemTime.getSystemTime());
-            cal.add(Calendar.DATE, 10);
-            dateOfLastWeatherData = cal.getTime();
-        }
-        else
-        {
-            dateOfLastWeatherData = fiveMonthsAfterSowingDate;
-        }
-
-        List<WeatherObservation> observations;
-        try {
-             observations = wsdUtil.getWeatherObservations(
-                    weatherStation,
-                    WeatherObservation.LOG_INTERVAL_ID_1H,
-                    parameterList,
-                    dateOfFirstWeatherData, 
-                    dateOfLastWeatherData
-            );
-        } 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("wheatType", wheatType);
-        config.setConfigParameter("observations", observations);
-        config.setConfigParameter("timeZone", timeZone.getID());
-        config.setConfigParameter("sowingDate", sowingDateStr);
-        config.setConfigParameter("plowed", plowed);
-        config.setConfigParameter("previousSeasonCropType", sameCropAsLastSeason ? 1 : 2 );
-        // Optional parameters
-        if(observationDate != null && observationValue != null)
-        {
-            ObservationImpl observation = new ObservationImpl();
-            observation.setName("Septoria tritici");
-            observation.setObservationData("{\"percentInfectedLeaves\": " + observationValue + "}");
-            observation.setTimeOfObservation(observationDate);
-            config.setConfigParameter("observation", observation);
-        }
-        if(sprayingDate != null && preparationId1 != null && preparationDose1 != null)
-        {
-            SprayingImpl spraying = new SprayingImpl();
-            spraying.setSprayingDate(sprayingDate);
-            WheatLeafBlotchPreparationEffectFactor preparationEffectFactor1 = em.createNamedQuery("WheatLeafBlotchPreparationEffectFactor.findByPreparationId", WheatLeafBlotchPreparationEffectFactor.class)
-                    .setParameter("preparationId", preparationId1).getSingleResult();
-            WheatLeafBlotchPreparationEffectFactor preparationEffectFactor2 = null;
-            WheatLeafBlotchPreparationEffectFactor preparationEffectFactor3 = null;
-            Integer denominator = 1;
-            if(preparationId2 != null && preparationDose2 != null)
-            {
-                preparationEffectFactor2 = em.createNamedQuery("WheatLeafBlotchPreparationEffectFactor.findByPreparationId", WheatLeafBlotchPreparationEffectFactor.class)
-                    .setParameter("preparationId", preparationId2).getSingleResult();
-                denominator++;
-            }
-            if(preparationId3 != null && preparationDose3 != null)
-            {
-                preparationEffectFactor3 = em.createNamedQuery("WheatLeafBlotchPreparationEffectFactor.findByPreparationId", WheatLeafBlotchPreparationEffectFactor.class)
-                    .setParameter("preparationId", preparationId3).getSingleResult();
-                denominator++;
-            }
-            spraying.setSprayingEffectFactor(
-                    (1 - (preparationDose1 * preparationEffectFactor1.getFactorValue() / preparationEffectFactor1.getFullDosisMlDaa())
-                    + (preparationEffectFactor2 != null ? (1 - (preparationDose2 * preparationEffectFactor2.getFactorValue() / preparationEffectFactor2.getFullDosisMlDaa())) : 0.0 )
-                    + (preparationEffectFactor3 != null ? (1 - (preparationDose3 * preparationEffectFactor3.getFactorValue() / preparationEffectFactor3.getFullDosisMlDaa())) : 0.0)
-                    ) / denominator
-            );
-            //System.out.println("sprayingEffectFactor=" + spraying.getSprayingEffectFactor());
-            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 = forecastBean.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/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchPreparationEffectFactor.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchPreparationEffectFactor.java
deleted file mode 100644
index d0e53006..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/WheatLeafBlotchPreparationEffectFactor.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import java.io.Serializable;
-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 2018 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Entity
-@Table(name = "wheatleafblotch_preparation_effect_factor", schema = "wheatleafb")
-@XmlRootElement
-@NamedQueries({
-    @NamedQuery(name = "WheatLeafBlotchPreparationEffectFactor.findAll", query = "SELECT p FROM WheatLeafBlotchPreparationEffectFactor p"),
-    @NamedQuery(name = "WheatLeafBlotchPreparationEffectFactor.findByPreparationId", query = "SELECT p FROM WheatLeafBlotchPreparationEffectFactor p WHERE p.preparationId = :preparationId"),
-    @NamedQuery(name = "WheatLeafBlotchPreparationEffectFactor.findByFullDosisMlDaa", query = "SELECT p FROM WheatLeafBlotchPreparationEffectFactor p WHERE p.fullDosisMlDaa = :fullDosisMlDaa"),
-    @NamedQuery(name = "WheatLeafBlotchPreparationEffectFactor.findByFactorValue", query = "SELECT p FROM WheatLeafBlotchPreparationEffectFactor p WHERE p.factorValue = :factorValue")})
-public class WheatLeafBlotchPreparationEffectFactor 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 Double fullDosisMlDaa;
-    @Column(name = "factor_value")
-    private Double factorValue;
-
-    public WheatLeafBlotchPreparationEffectFactor() {
-    }
-
-    public WheatLeafBlotchPreparationEffectFactor(Integer preparationId) {
-        this.preparationId = preparationId;
-    }
-
-    public Integer getPreparationId() {
-        return preparationId;
-    }
-
-    public void setPreparationId(Integer preparationId) {
-        this.preparationId = preparationId;
-    }
-
-    public Double getFullDosisMlDaa() {
-        return fullDosisMlDaa;
-    }
-
-    public void setFullDosisMlDaa(Double fullDosisMlDaa) {
-        this.fullDosisMlDaa = fullDosisMlDaa;
-    }
-
-    public Double getFactorValue() {
-        return factorValue;
-    }
-
-    public void setFactorValue(Double 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 WheatLeafBlotchPreparationEffectFactor)) {
-            return false;
-        }
-        WheatLeafBlotchPreparationEffectFactor other = (WheatLeafBlotchPreparationEffectFactor) 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.nibio.vips.logic.modules.barleynetblotch.PreparationEffectFactor[ preparationId=" + preparationId + " ]";
-    }
-
-}
diff --git a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLoss.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLoss.java
deleted file mode 100644
index 461c35fc..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLoss.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2019 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import java.io.Serializable;
-import javax.persistence.Column;
-import javax.persistence.EmbeddedId;
-import javax.persistence.Entity;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-import javax.xml.bind.annotation.XmlRootElement;
-import no.nibio.vips.logic.entity.PointOfInterest;
-
-/**
- * @copyright 2019 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Entity
-@Table(name = "yield_loss", schema = "wheatleafb")
-@XmlRootElement
-@NamedQueries({
-    @NamedQuery(name = "YieldLoss.findAll", query = "SELECT y FROM YieldLoss y"),
-    @NamedQuery(name = "YieldLoss.findBySeason", query = "SELECT y FROM YieldLoss y WHERE y.yieldLossPK.season = :season"),
-    @NamedQuery(name = "YieldLoss.findByPointOfInterestId", query = "SELECT y FROM YieldLoss y WHERE y.yieldLossPK.pointOfInterestId = :pointOfInterestId"),
-    @NamedQuery(name = "YieldLoss.findByYieldLoss", query = "SELECT y FROM YieldLoss y WHERE y.yieldLoss = :yieldLoss")
-})
-public class YieldLoss implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-    @EmbeddedId
-    protected YieldLossPK yieldLossPK;
-    @Column(name = "yield_loss")
-    private Double yieldLoss;
-
-    public YieldLoss() {
-    }
-
-    public YieldLoss(YieldLossPK yieldLossPK) {
-        this.yieldLossPK = yieldLossPK;
-    }
-
-    public YieldLoss(int season, PointOfInterest pointOfInterestId) {
-        this.yieldLossPK = new YieldLossPK(season, pointOfInterestId);
-    }
-
-    public YieldLossPK getYieldLossPK() {
-        return yieldLossPK;
-    }
-
-    public void setYieldLossPK(YieldLossPK yieldLossPK) {
-        this.yieldLossPK = yieldLossPK;
-    }
-
-    public Double getYieldLoss() {
-        return yieldLoss;
-    }
-
-    public void setYieldLoss(Double yieldLoss) {
-        this.yieldLoss = yieldLoss;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 0;
-        hash += (yieldLossPK != null ? yieldLossPK.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 YieldLoss)) {
-            return false;
-        }
-        YieldLoss other = (YieldLoss) object;
-        if ((this.yieldLossPK == null && other.yieldLossPK != null) || (this.yieldLossPK != null && !this.yieldLossPK.equals(other.yieldLossPK))) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "no.nibio.vips.logic.modules.wheatleafblotch.YieldLoss[ yieldLossPK=" + yieldLossPK + " ]";
-    }
-
-}
diff --git a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLossPK.java b/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLossPK.java
deleted file mode 100644
index c79cddca..00000000
--- a/src/main/java/no/nibio/vips/logic/modules/wheatleafblotch/YieldLossPK.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2019 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.nibio.vips.logic.modules.wheatleafblotch;
-
-import java.io.Serializable;
-import javax.persistence.Basic;
-import javax.persistence.Column;
-import javax.persistence.Embeddable;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.validation.constraints.NotNull;
-import no.nibio.vips.logic.entity.PointOfInterest;
-
-/**
- * @copyright 2019 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Embeddable
-public class YieldLossPK implements Serializable {
-
-    @Basic(optional = false)
-    @NotNull
-    @Column(name = "season")
-    private int season;
-    @Basic(optional = false)
-    @NotNull
-    @JoinColumn(name = "point_of_interest_id", referencedColumnName = "point_of_interest_id")
-    @ManyToOne
-    private PointOfInterest pointOfInterestId;
-
-    public YieldLossPK() {
-    }
-
-    public YieldLossPK(int season, PointOfInterest pointOfInterestId) {
-        this.season = season;
-        this.pointOfInterestId = pointOfInterestId;
-    }
-
-    public int getSeason() {
-        return season;
-    }
-
-    public void setSeason(int season) {
-        this.season = season;
-    }
-
-    public PointOfInterest getPointOfInterestId() {
-        return pointOfInterestId;
-    }
-
-    public void setPointOfInterestId(PointOfInterest pointOfInterestId) {
-        this.pointOfInterestId = pointOfInterestId;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 0;
-        hash += (int) season;
-        hash += (int) pointOfInterestId.getPointOfInterestId();
-        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 YieldLossPK)) {
-            return false;
-        }
-        YieldLossPK other = (YieldLossPK) object;
-        if (this.season != other.season) {
-            return false;
-        }
-        if (this.pointOfInterestId != other.pointOfInterestId) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "no.nibio.vips.logic.modules.wheatleafblotch.YieldLossPK[ season=" + season + ", pointOfInterestId=" + pointOfInterestId + " ]";
-    }
-
-}
diff --git a/src/main/java/no/nibio/vips/logic/service/GrowthStageService.java b/src/main/java/no/nibio/vips/logic/service/GrowthStageService.java
deleted file mode 100644
index d4954d2d..00000000
--- a/src/main/java/no/nibio/vips/logic/service/GrowthStageService.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (c) 2020 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.nibio.vips.logic.service;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.ejb.EJB;
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
-import javax.servlet.http.HttpServletRequest;
-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.core.Context;
-import javax.ws.rs.core.Response;
-import no.nibio.vips.logic.controller.session.PointOfInterestBean;
-import no.nibio.vips.logic.entity.Organism;
-import no.nibio.vips.logic.entity.PointOfInterestWeatherStation;
-import no.nibio.vips.logic.modules.wheatleafblotch.GrowthStageLocationDate;
-
-/**
- * @copyright 2020-2022 <a href="http://www.nibio.no/">NIBIO</a>
- * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
- */
-@Path("rest/gs")
-public class GrowthStageService {
-    @Context
-    private HttpServletRequest httpServletRequest;
-    @PersistenceContext(unitName="VIPSLogic-PU")
-    EntityManager em;
-    
-    @EJB
-    PointOfInterestBean pointOfInterestBean;
-    
-    /**
-     * TODO Add response example
-     * At what dates can we expect the given crop to be at the given growth stages
-     * at the given location?
-     * @param organismId
-     * @param growthStagesStr
-     * @param location
-     * @param season
-     * @return 
-     */
-    @GET
-    @Path("date/{growthStages}/{organismId}")
-    @Produces("application/json;charset=UTF-8")
-    public Response getDateForGrowthStage(
-            @PathParam("organismId") Integer organismId,
-            @PathParam("growthStages") String growthStagesStr,
-            @QueryParam("location") String location,
-            @QueryParam("season") Integer season
-    )
-    {
-        List<GrowthStageLocationDate> growthStageDatesForLocationAndCrop = this.getGrowthStageDatesForLocationAndCrop(location, organismId);
-        //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        //format.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // TODO get from param or default is UTC
-        List<Map<Integer,LocalDate>> retVal = new ArrayList<>();
-        List<Integer> growthStages = Arrays.stream(growthStagesStr.split(",")).map(str->Integer.valueOf(str)).collect(Collectors.toList());
-        growthStages.stream().map((growthStage) -> {
-            Map<Integer, LocalDate> gsDate = new HashMap<>();
-            gsDate.put(growthStage, this.getDateForGrowthStage(growthStageDatesForLocationAndCrop, growthStage, season));
-            return gsDate;
-        }).forEachOrdered((gsDate) -> {
-            retVal.add(gsDate);
-        });        
-        return Response.ok().entity(retVal).build();
-    }
-    
-    /**
-     * TODO Add response example
-     * At what GS is the given organism at the given date and location?
-     * @param organismId
-     * @param dateStr
-     * @param location
-     * @return 
-     */
-    @GET
-    @Path("gs/{date}/{organismId}")
-    @Produces("application/json;charset=UTF-8")
-    public Response getGrowthStageForDate(
-            @PathParam("organismId") Integer organismId,
-            @PathParam("date") String dateStr,
-            @QueryParam("location") String location
-    )
-    {
-        
-        
-        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
-        LocalDate date = LocalDate.parse(dateStr, formatter);
-        List<GrowthStageLocationDate> growthStageDatesForLocationAndCrop = this.getGrowthStageDatesForLocationAndCrop(location, organismId);
-        //Integer[] retVal = {this.getGrowthStageForDate(growthStageDatesForLocationAndCrop, date)};
-        List<Map<LocalDate,Integer>> retVal = new ArrayList<>();
-        Map<LocalDate,Integer> actualRetVal = new HashMap<>();
-        actualRetVal.put(date, this.getGrowthStageForDate(growthStageDatesForLocationAndCrop, date));
-        retVal.add(actualRetVal);
-        return Response.ok().entity(retVal).build();
-    }
-
-    /**
-     * 
-     * @param location
-     * @return 
-     */
-    private Coordinate getLocationCoordinate(String location)
-    {
-        String[] lonLat = location.split(",");
-        Double longitude = Double.valueOf(lonLat[0]);
-        Double latitude = Double.valueOf(lonLat[1]);
-        Coordinate retVal = new Coordinate(longitude, latitude);
-        return retVal;
-    }
-    
-    /**
-     * 
-     * @param datesForGrowthStages
-     * @param date
-     * @return 
-     */
-    private Integer getGrowthStageForDate(List<GrowthStageLocationDate> datesForGrowthStages, LocalDate date)
-    {
-        Integer dateDayNum = date.getDayOfYear();
-        Collections.sort(datesForGrowthStages);
-        for(int i=0;i<datesForGrowthStages.size();i++)
-        {
-            Integer gsDayNum1 = datesForGrowthStages.get(i).getDayNumber();
-            // Case 1: Date is before the earliest registered GSDate in DB
-            // Case 2: Date is after the latest registered GSDate in DB
-            if((i==0 && dateDayNum < gsDayNum1 ) || (i == datesForGrowthStages.size()-1 && dateDayNum > gsDayNum1))
-            {
-                return null;
-            }
-            // Case 3: date equals the current list item GSDate: Return as is
-            if(dateDayNum.equals(gsDayNum1))
-            {
-                return datesForGrowthStages.get(i).getGrowthStageLocationDatePK().getGrowthStage();
-            }
-            
-            Integer gsDayNum2 = datesForGrowthStages.get(i+1).getDayNumber();
-            // Case 4 date is between current and next GSDate
-            if(dateDayNum > gsDayNum1 && dateDayNum < gsDayNum2)
-            {
-                // We do linear interpolation to find the gs
-                Float deltaGS = (float) (datesForGrowthStages.get(i+1).getGrowthStageLocationDatePK().getGrowthStage() - datesForGrowthStages.get(i).getGrowthStageLocationDatePK().getGrowthStage()) 
-                        / (gsDayNum2 - gsDayNum1);
-                // How many days per gs between the two items?
-                //Float deltaDay = (float) (datesForGrowthStages.get(i+1).getDayNumber() - datesForGrowthStages.get(i).getDayNumber()) / (gs2-gs1);
-                Integer addedGS = Math.round((dateDayNum - gsDayNum1) * deltaGS);
-                return datesForGrowthStages.get(i).getGrowthStageLocationDatePK().getGrowthStage() + addedGS;
-            }
-            // How many gs per day between the two items?
-            //Double deltaGS = (double) (gs2-gs1) / (datesForGrowthStages.get(i+1).getDayNumber() - datesForGrowthStages.get(i).getDayNumber());
-        }
-        return null;
-    }
-    
-    /**
-     * 
-     * @param datesForGrowthStages
-     * @param growthStage
-     * @param season
-     * @return 
-     */
-    private LocalDate getDateForGrowthStage(List<GrowthStageLocationDate> datesForGrowthStages, Integer growthStage, Integer season)
-    {
-        Collections.sort(datesForGrowthStages);
-        for(int i=0;i<datesForGrowthStages.size();i++)
-        {
-            Integer gs1 = datesForGrowthStages.get(i).getGrowthStageLocationDatePK().getGrowthStage();
-            // Case 1: GS is lower than the lowest registered stage in DB
-            // Case 2: GS is higher than the highest registered stage in DB
-            if((i==0 && growthStage < gs1) || (i == datesForGrowthStages.size()-1 && growthStage > gs1))
-            {
-                return null;
-            }
-            // Case 3: GS equals the current list item GS: Return as is
-            if(growthStage.equals(gs1))
-            {
-                return LocalDate.ofYearDay(season, datesForGrowthStages.get(i).getDayNumber());
-            }
-            
-            Integer gs2 = datesForGrowthStages.get(i+1).getGrowthStageLocationDatePK().getGrowthStage();
-            // Case 4 GS is between current and next GS
-            if(growthStage > gs1 && growthStage < gs2)
-            {
-                // We do linear interpolation to find the date
-            
-                // How many days per gs between the two items?
-                Float deltaDay = (float) (datesForGrowthStages.get(i+1).getDayNumber() - datesForGrowthStages.get(i).getDayNumber()) / (gs2-gs1);
-                Integer addedDays = Math.round((growthStage - gs1) * deltaDay);
-                return LocalDate.ofYearDay(season, datesForGrowthStages.get(i).getDayNumber() + addedDays);
-            }
-            // How many gs per day between the two items?
-            //Double deltaGS = (double) (gs2-gs1) / (datesForGrowthStages.get(i+1).getDayNumber() - datesForGrowthStages.get(i).getDayNumber());
-        }
-        return null;
-    }
-    
-    /**
-     * 
-     * @param location
-     * @param organismId
-     * @return 
-     */
-    private List<GrowthStageLocationDate> getGrowthStageDatesForLocationAndCrop(String location, Integer organismId)
-    {
-        List<PointOfInterestWeatherStation> stationsWithGrowthStageInfoForCrop = em.createNativeQuery(
-        "SELECT poi.*, poiws.* FROM public.point_of_interest_weather_station poiws, public.point_of_interest poi "
-        + "WHERE poi.point_of_interest_id IN("
-        + "     SELECT point_of_interest_id FROM wheatleafb.growth_stage_location_date "
-        + "     WHERE crop_organism_id = :cropOrganismId "
-        + ")"
-        + "AND poiws.point_of_interest_id = poi.point_of_interest_id", 
-        PointOfInterestWeatherStation.class)
-        .setParameter("cropOrganismId", organismId)
-        .getResultList();
-        
-        PointOfInterestWeatherStation closestStation = pointOfInterestBean.findClosestWeatherStation(this.getLocationCoordinate(location), stationsWithGrowthStageInfoForCrop);
-        return em.createNamedQuery("GrowthStageLocationDate.findByCropOrganismIdAndPointOfInterestId")
-                .setParameter("cropOrganismId", em.find(Organism.class, organismId))
-                .setParameter("pointOfInterestId", closestStation)
-                .getResultList();
-    }
-}
-- 
GitLab