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)
         {