diff --git a/pom.xml b/pom.xml
index 00f0708b6a8a797a808388fa0861573ba25e76d2..731ccfc951c5fc345dee53d5a75e9c164836f067 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,17 +9,28 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <geotools.version>13.4</geotools.version>
</properties>
<name>VIPSLogic</name>
<url>http://maven.apache.org</url>
<repositories>
+ <repository>
+ <id>jitpack.io</id>
+ <url>https://jitpack.io</url>
+</repository>
<repository>
<id>Hibernate Spatial repo</id>
<url>http://www.hibernatespatial.org/repository</url>
</repository>
+
</repositories>
<dependencies>
+ <dependency>
+ <groupId>com.github.bjornharrtell</groupId>
+ <artifactId>jts2geojson</artifactId>
+ <version>0.6.0</version>
+ </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
@@ -115,6 +126,12 @@
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <type>jar</type>
+ </dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java
index 239b18744c124a0becba1a9da96fbaffa21f75f8..8002b1a29e51b31d914e0dd38bd7675caa5ab4bd 100644
--- a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java
+++ b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java
@@ -108,8 +108,11 @@ public class ObservationController extends HttpServlet {
try
{
Integer observationId = Integer.valueOf(request.getParameter("observationId"));
- Observation observation = em.find(Observation.class, observationId);
+ Observation observation = SessionControllerGetter.getObservationBean().getObservation(observationId);//em.find(Observation.class, observationId);
request.setAttribute("observation", observation);
+ //System.out.println(observation.getGeoinfo());
+ request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+ request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
List<Organism> allOrganisms = em.createNamedQuery("Organism.findAll").getResultList();
request.setAttribute("allOrganisms", allOrganisms);
// Hierarchy categories
@@ -123,7 +126,7 @@ public class ObservationController extends HttpServlet {
}
catch(NullPointerException | NumberFormatException ex)
{
- response.sendError(500, ExceptionUtil.getStackTrace(ex));
+ response.sendError(500, ex.getMessage() + ": " + ExceptionUtil.getStackTrace(ex));
}
}
else
@@ -151,7 +154,9 @@ public class ObservationController extends HttpServlet {
observation.setTimeOfObservation(formValidation.getFormField("timeOfObservation").getValueAsTimestamp());
observation.setObservedValue(formValidation.getFormField("observedValue").getValueAsDouble());
observation.setUserId(user.getUserId());
- observation.setLocation(formValidation.getFormField("location").getValueAsPointWGS84());
+ //observation.setLocation(formValidation.getFormField("location").getValueAsPointWGS84());
+ //System.out.println(formValidation.getFormField("geoInfo").getWebValue());
+ observation.setGeoinfo(formValidation.getFormField("geoInfo").getWebValue());
observation = SessionControllerGetter.getObservationBean().storeObservation(observation);
// Redirect to form
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
index 05a157f78233dfdfd0dffee4db07c817eb856268..b03d18b7aa87e1a05f52f3ebf5aa7f6bcc789900 100644
--- a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
@@ -19,16 +19,20 @@
package no.nibio.vips.logic.controller.session;
+import com.vividsolutions.jts.geom.Geometry;
+import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import no.nibio.vips.logic.entity.Gis;
import no.nibio.vips.logic.entity.Observation;
import no.nibio.vips.logic.entity.Organization;
import no.nibio.vips.logic.entity.VipsLogicUser;
/**
- * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a>
+ * @copyright 2014-2015 <a href="http://www.nibio.no/">NIBIO</a>
* @author Tor-Einar Skog <tor-einar.skog@nibio.no>
*/
@Stateless
@@ -43,11 +47,93 @@ public class ObservationBean {
.setParameter("organizationId", organization)
.getResultList();
- return em.createNamedQuery("Observation.findAll").getResultList();
+ List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findAll").getResultList());
+
+ return retVal;
+ }
+
+ public Observation getObservation(Integer observationId)
+ {
+ Observation retVal = em.find(Observation.class, observationId);
+ if(retVal != null)
+ {
+ retVal.setGeoinfos(this.getGeoinfoForObservation(retVal));
+ }
+ return retVal;
+ }
+
+ public List<Gis> getGeoinfoForObservation(Observation obs)
+ {
+ List<Integer> gisIds = em.createNativeQuery("SELECT gis_id FROM public.gis_observation WHERE observation_id = :observationId")
+ .setParameter("observationId", obs.getObservationId())
+ .getResultList();
+
+ if(gisIds != null && ! gisIds.isEmpty())
+ {
+ return em.createNamedQuery("Gis.findByGisIds",Gis.class)
+ .setParameter("gisIds", gisIds)
+ .getResultList();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public List<Observation> getObservationsWithGeoInfo(List<Observation> observations)
+ {
+ Query q1 = em.createNamedQuery("Gis.findByGisIds",Gis.class);
+
+ Query q2 = em.createNativeQuery("SELECT gis_id FROM public.gis_observation WHERE observation_id = :observationId");
+
+ for(Observation obs:observations)
+ {
+ List<Integer> gisIds = q2.setParameter("observationId", obs.getObservationId()).getResultList();
+ if(!gisIds.isEmpty())
+ {
+ obs.setGeoinfos(q1.setParameter("gisIds", gisIds).getResultList());
+ }
+ //
+ }
+ return observations;
}
public Observation storeObservation(Observation observation) {
- return em.merge(observation);
+ Observation retVal = em.merge(observation);
+ // Store geoinfo
+ // First delete all old observations
+ em.createNativeQuery("DELETE FROM public.gis where gis_id IN (SELECT gis_id FROM public.gis_observation WHERE observation_id=:observationId)")
+ .setParameter("observationId", observation.getObservationId())
+ .executeUpdate();
+ em.createNativeQuery("DELETE FROM public.gis_observation WHERE observation_id=:observationId")
+ .setParameter("observationId", observation.getObservationId())
+ .executeUpdate();
+ // Then persist the new ones
+ if(observation.getGeoinfos() != null && ! observation.getGeoinfos().isEmpty())
+ {
+ for(Gis gis : observation.getGeoinfos())
+ {
+ em.persist(gis);
+ }
+
+ Query q = em.createNativeQuery("INSERT INTO public.gis_observation(gis_id,observation_id) VALUES(:gisId,:observationId)")
+ .setParameter("observationId", observation.getObservationId());
+ for(Gis gis:observation.getGeoinfos())
+ {
+ q.setParameter("gisId", gis.getGisId())
+ .executeUpdate();
+ }
+ }
+ /*
+ for(Geometry geom:observation.getGeometries())
+ {
+ Gis gis = new Gis();
+ gis.setGisGeom(geom);
+ em.persist(gis);
+ gises.add(gis);
+ }*/
+
+ return retVal;
}
public void deleteObservation(Integer observationId) {
diff --git a/src/main/java/no/nibio/vips/logic/entity/Gis.java b/src/main/java/no/nibio/vips/logic/entity/Gis.java
new file mode 100644
index 0000000000000000000000000000000000000000..75a7079af75caa37c7a44a77b341ea65a9ef7229
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/Gis.java
@@ -0,0 +1,110 @@
+/*
+ * 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.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.vividsolutions.jts.geom.Geometry;
+import java.io.Serializable;
+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.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.hibernate.annotations.Type;
+
+/**
+ * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "gis")
+@XmlRootElement
+@NamedQueries({
+ @NamedQuery(name = "Gis.findAll", query = "SELECT g FROM Gis g"),
+ @NamedQuery(name = "Gis.findByGisId", query = "SELECT g FROM Gis g WHERE g.gisId = :gisId"),
+ @NamedQuery(name = "Gis.findByGisIds", query = "SELECT g FROM Gis g WHERE g.gisId IN(:gisIds)")
+})
+public class Gis implements Serializable {
+ private static final long serialVersionUID = 1L;
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Basic(optional = false)
+ @Column(name = "gis_id")
+ private Integer gisId;
+ @JsonIgnore
+ @Type(type = "org.hibernate.spatial.GeometryType")
+ @Column(name = "gis_geom", columnDefinition = "Geometry")
+ private Geometry gisGeom;
+
+ public Gis() {
+ }
+
+ public Gis(Integer gisId) {
+ this.gisId = gisId;
+ }
+
+ public Integer getGisId() {
+ return gisId;
+ }
+
+ public void setGisId(Integer gisId) {
+ this.gisId = gisId;
+ }
+
+
+ public Geometry getGisGeom() {
+ return gisGeom;
+ }
+
+ public void setGisGeom(Geometry gisGeom) {
+ this.gisGeom = gisGeom;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (gisId != null ? gisId.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 Gis)) {
+ return false;
+ }
+ Gis other = (Gis) object;
+ if ((this.gisId == null && other.gisId != null) || (this.gisId != null && !this.gisId.equals(other.gisId))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "no.nibio.vips.logic.entity.Gis[ gisId=" + gisId + " ]";
+ }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java
index 6076869702e416f18c7ccdd512c0924f05aa643c..a83286c4cd4db00e9f8768f6deeb98c605975308 100644
--- a/src/main/java/no/nibio/vips/logic/entity/Observation.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java
@@ -18,8 +18,6 @@
*/
package no.nibio.vips.logic.entity;
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Point;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
@@ -39,7 +37,9 @@ import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.hibernate.annotations.Type;
+import com.vividsolutions.jts.geom.Geometry;
+import java.util.List;
+import no.nibio.vips.logic.util.GISUtil;
/**
* @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a>
@@ -63,12 +63,16 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
private Date timeOfObservation;
private Organism organism;
private Integer userId;
- private Point location;
+ //private Point location;
+ private List<Gis> geoinfo;
private Double observedValue;
private Integer denominator;
private ObservationMethod observationMethodId;
+
+ private GISUtil GISUtil;
public Observation() {
+ this.GISUtil = new GISUtil();
}
public Observation(Integer observationId) {
@@ -97,6 +101,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
@Basic(optional = false)
@Column(name = "time_of_observation")
@Temporal(TemporalType.TIMESTAMP)
+ @Override
public Date getTimeOfObservation() {
return timeOfObservation;
}
@@ -105,8 +110,9 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
this.timeOfObservation = timeOfObservation;
}
+
// Using PostGIS + Hibernate-spatial + Java Topology Suite to make this work
- @JsonIgnore
+ /*@JsonIgnore
@Type(type = "org.hibernate.spatial.GeometryType")
@Column(name = "location", columnDefinition = "Geometry")
public Point getLocation() {
@@ -115,17 +121,43 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
public void setLocation(Point location) {
this.location = location;
+ }*/
+
+ public void setGeoinfos(List<Gis> geoinfo)
+ {
+ this.geoinfo = geoinfo;
+ }
+
+ @JsonIgnore
+ @Transient
+ public List<Gis> getGeoinfos()
+ {
+ return this.geoinfo;
+ }
+
+
+ public void setGeoinfo(String json)
+ {
+ this.setGeoinfos(this.GISUtil.getGisFromGeoJSON(json));
}
@Transient
+ @Override
+ public String getGeoinfo()
+ {
+ return this.GISUtil.getGeoJSONFromGis(this.geoinfo);
+ }
+
+ /*@Transient
public Coordinate getLocationCoordinate()
{
return this.location.getCoordinate();
- }
+ }*/
@NotNull
@Basic(optional = false)
@Column(name = "observed_value")
+ @Override
public Double getObservedValue() {
return observedValue;
}
@@ -135,6 +167,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
}
@Column(name = "denominator")
+ @Override
public Integer getDenominator() {
return denominator;
}
@@ -215,6 +248,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
this.organism = organism;
}
+ /*
@Override
@Transient
public Double getLatitude() {
@@ -226,7 +260,8 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
public Double getLongitude() {
return this.getLocationCoordinate().x;
}
-
+ */
+
@Override
@Transient
public String getName() {
diff --git a/src/main/java/no/nibio/vips/logic/util/GISUtil.java b/src/main/java/no/nibio/vips/logic/util/GISUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..138ae03b8730a8c67d2139d7cb471e9f071a0fb0
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/util/GISUtil.java
@@ -0,0 +1,110 @@
+/*
+ * 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.util;
+
+import com.vividsolutions.jts.geom.Geometry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import no.nibio.vips.logic.entity.Gis;
+import org.wololo.geojson.Feature;
+import org.wololo.geojson.FeatureCollection;
+import org.wololo.geojson.GeoJSONFactory;
+import org.wololo.jts2geojson.GeoJSONReader;
+import org.wololo.jts2geojson.GeoJSONWriter;
+
+/**
+ * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class GISUtil {
+
+ /**
+ * Parses all features from GeoJSON string, returns as JTS Geometry objects
+ * @param json
+ * @return
+ */
+ public List<Geometry> getGeometriesFromGeoJSON(String json)
+ {
+ FeatureCollection featureCollection = (FeatureCollection) GeoJSONFactory.create(json);
+ GeoJSONReader reader = new GeoJSONReader();
+ List<Geometry> retVal = new ArrayList<>();
+ for(Feature feature: featureCollection.getFeatures())
+ {
+ retVal.add(reader.read(feature.getGeometry()));
+ }
+ return retVal;
+ }
+
+ public List<Gis> getGisFromGeoJSON(String json)
+ {
+ GeoJSONReader reader = new GeoJSONReader();
+ List<Gis> retVal = new ArrayList<>();
+ try
+ {
+ FeatureCollection featureCollection = (FeatureCollection) GeoJSONFactory.create(json);
+ for(Feature feature: featureCollection.getFeatures())
+ {
+ Gis gis = new Gis();
+ gis.setGisGeom(reader.read(feature.getGeometry()));
+ gis.getGisGeom().setSRID(4326);
+ retVal.add(gis);
+ }
+ }catch(NullPointerException ex) {};
+ return retVal;
+ }
+
+ public String getGeoJSONFromGis(List<Gis> geoinfo)
+ {
+ if(geoinfo == null || geoinfo.isEmpty())
+ {
+ return "";
+ }
+ List<Feature> features = new ArrayList<>();
+ Map<String, Object> properties = new HashMap<>();
+ GeoJSONWriter writer = new GeoJSONWriter();
+ for(Gis gis:geoinfo)
+ {
+ features.add(new Feature(writer.write(gis.getGisGeom()), properties));
+ }
+
+ FeatureCollection json = writer.write(features);
+ return json.toString();
+ }
+
+ public String getGeoJSONFromGeometries(List<Geometry> geometries)
+ {
+ if(geometries == null || geometries.isEmpty())
+ {
+ return "";
+ }
+ List<Feature> features = new ArrayList<>();
+ Map<String, Object> properties = new HashMap<>();
+ GeoJSONWriter writer = new GeoJSONWriter();
+ for(Geometry geometry:geometries)
+ {
+ features.add(new Feature(writer.write(geometry), properties));
+ }
+
+ FeatureCollection json = writer.write(features);
+ return json.toString();
+ }
+}
diff --git a/src/main/java/no/nibio/web/forms/FormField.java b/src/main/java/no/nibio/web/forms/FormField.java
index e5346d840ee88bf801660787a8596a8d54e710e7..888ceb1a6e361ac0c747e01e64f23a683421f22d 100644
--- a/src/main/java/no/nibio/web/forms/FormField.java
+++ b/src/main/java/no/nibio/web/forms/FormField.java
@@ -51,6 +51,7 @@ public class FormField {
public final static String DATA_TYPE_PASSWORD = "PASSWORD";
public final static String DATA_TYPE_EMAIL = "EMAIL";
public final static String DATA_TYPE_POINT_WGS84 = "POINT_WGS84";
+ public final static String DATA_TYPE_GEOJSON = "GEOJSON";
public final static String FIELD_TYPE_INPUT = "INPUT";
public final static String FIELD_TYPE_HIDDEN = "HIDDEN";
diff --git a/src/main/java/no/nibio/web/forms/FormValidator.java b/src/main/java/no/nibio/web/forms/FormValidator.java
index 0e141352f3d3583a324642f13f91d085f119f626..508ab252119453c9b4c5910b118fc8e4e56291a1 100644
--- a/src/main/java/no/nibio/web/forms/FormValidator.java
+++ b/src/main/java/no/nibio/web/forms/FormValidator.java
@@ -318,6 +318,15 @@ public class FormValidator {
}
}
}
+ // GEOJSON
+ if(field.getDataType().equals(FormField.DATA_TYPE_GEOJSON))
+ {
+ if((field.getWebValue().equals("{}") || field.getWebValue().equals(field.getNullValue())) && field.isRequired())
+ {
+ field.setValid(false);
+ field.setValidationMessage(resourceBundle.getString("fieldIsRequired"));
+ }
+ }
// SELECT FIELDS
// SINGLE SELECT
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
index 0d69b3a6c9b1230dadc50963bab808f2fe74d324..3e5c09e293b8c3bf098743ccee15f2f347418d7d 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -286,3 +286,4 @@ allCrops=All crops
rememberLogin=Remember login
task_DeleteAllExpiredUserUuidsTask_name=Delete all expired user UUIDs
task_DeleteAllExpiredUserUuidsTask_description=Cleaning up the database of UUIDs, which is used for remembering client logins
+mapDataIsRequired=Map data is required
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
index ddf8b72285bc61538ed5c5f91a6b8393b951a770..7ae7ba080e9570038d97c8c612dd54b33f7e1481 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -286,3 +286,4 @@ allCrops=All crops
rememberLogin=Remember login
task_DeleteAllExpiredUserUuidsTask_name=Delete all expired user UUIDs
task_DeleteAllExpiredUserUuidsTask_description=Cleaning up the database of UUIDs, which is used for remembering client logins
+mapDataIsRequired=Map data is required
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
index 5c746b23b42375288a890e2219dd9552fa4b77d1..8b56087dd472d1b317cc8e47fbe30eb7694b663f 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -285,3 +285,4 @@ allCrops=All crops
rememberLogin=Remember login
task_DeleteAllExpiredUserUuidsTask_name=Delete all expired user UUIDs
task_DeleteAllExpiredUserUuidsTask_description=Cleaning up the database of UUIDs, which is used for remembering client logins
+mapDataIsRequired=Map data is required
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
index 82ee56fd99c812a83b261fd4d89d4394548af80d..13b3239f3a9ae4c6163d8c9dc66c1a088c39eeaa 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -286,3 +286,4 @@ allCrops=Alle kulturer
rememberLogin=Husk innlogging
task_DeleteAllExpiredUserUuidsTask_name=Slett alle utdaterte brukerUUIDer
task_DeleteAllExpiredUserUuidsTask_description=Rydder opp i tabellen over brukerUUIDer, som brukes til \u00e5 huske klientinnlogginger
+mapDataIsRequired=Kartdata m\u00e5 registreres
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
index c72dcabeb50b7a601dac735c960bda8d5ff60b7a..9d905c280aacdc8a8f4acb1ceff760c8a3408e81 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -286,3 +286,4 @@ allCrops=All crops
rememberLogin=Remember login
task_DeleteAllExpiredUserUuidsTask_name=Delete all expired user UUIDs
task_DeleteAllExpiredUserUuidsTask_description=Cleaning up the database of UUIDs, which is used for remembering client logins
+mapDataIsRequired=Map data is required
diff --git a/src/main/webapp/formdefinitions/observationForm.json b/src/main/webapp/formdefinitions/observationForm.json
index 2050ff30a1974c848db3031361af907522ce444b..ba490d9baed297a79c40710829df4747ef73621e 100644
--- a/src/main/webapp/formdefinitions/observationForm.json
+++ b/src/main/webapp/formdefinitions/observationForm.json
@@ -38,9 +38,11 @@
"required" : true
},
{
- "name" : "location",
- "dataType" : "POINT_WGS84",
- "required" : true
+ "name": "geoInfo",
+ "dataType" : "GEOJSON",
+ "fieldType" : "HIDDEN",
+ "required" : true,
+ "nullValue" : "{\"type\":\"FeatureCollection\",\"features\":[]}"
},
{
"name" : "observedValue",
diff --git a/src/main/webapp/js/observationFormMap.js b/src/main/webapp/js/observationFormMap.js
index 9205aed0f502906e35fd7e34f7f5271f854bd6ab..bb269380137f7bf283fac32d1f9e3cb4686672aa 100755
--- a/src/main/webapp/js/observationFormMap.js
+++ b/src/main/webapp/js/observationFormMap.js
@@ -21,14 +21,16 @@
* Logic for registering location of an observation using an OpenLayers v3 map
*/
+var featureOverlay;
+
/**
*
* @param {ol.Coordinate} center - coordinates for the map's center (WGS84)
* @param {int} zoomLevel - the zoom level (1-15, 1 is world wide view, 15 is greatest zoom)
* @param {boolean} displayMarker - show observation marker in center location
+ * @param {string} drawnObjs - GeoJSON with geometries to display
* @returns {void}
*/
-
function initMap(center, zoomLevel, displayMarker, drawnObjs) {
@@ -55,16 +57,6 @@ function initMap(center, zoomLevel, displayMarker, drawnObjs) {
})
});
-
-
-
-
-
-
-
-
-
-
var fylke_layer = new ol.layer.Vector({
title: 'Fylkesgrenser',
type: 'overlay',
@@ -153,7 +145,7 @@ function initMap(center, zoomLevel, displayMarker, drawnObjs) {
// This collection is passed to the modify and also the draw
// interaction, so that both can add or modify features.
var features = new ol.Collection();
- var featureOverlay = new ol.layer.Vector({
+ featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
features: features
}),
@@ -348,4 +340,23 @@ function initMap(center, zoomLevel, displayMarker, drawnObjs) {
}, 500, function() {});
});
}
+}
+
+function getFeatures()
+{
+ var features = featureOverlay.getSource().getFeatures();
+ // create an object to write features on a output KML file
+
+ //var desimalDegrees = features[0].getGeometry().clone().transform('EPSG:4326','EPSG:3857').getCoordinates();
+//debugger;
+
+ var format = new ol.format.GeoJSON();
+ // write features to GeoJSON format using projection EPSG:4326
+
+ var result = format.writeFeatures(features, {
+ dataProjection: 'EPSG:4326',
+ featureProjection: 'EPSG:3857'
+ });
+
+ return result;
}
\ No newline at end of file
diff --git a/src/main/webapp/js/util.js b/src/main/webapp/js/util.js
new file mode 100644
index 0000000000000000000000000000000000000000..f86837a8bc52d5e8abece528208ac616782a3086
--- /dev/null
+++ b/src/main/webapp/js/util.js
@@ -0,0 +1,23 @@
+/*
+ * 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/>.
+ *
+ */
+
+function setFieldValue(theForm, fieldName, value)
+{
+ theForm[fieldName] = value;
+}
diff --git a/src/main/webapp/js/validateForm.js b/src/main/webapp/js/validateForm.js
index 64d59eaadb993295c2432dacc51795669375cea1..a9315c10d91c48ddd2e3507c2016df0ab38cd23a 100644
--- a/src/main/webapp/js/validateForm.js
+++ b/src/main/webapp/js/validateForm.js
@@ -31,9 +31,8 @@ var dataTypes = {
TYPE_TIMESTAMP: "TIMESTAMP",
TYPE_PASSWORD: "PASSWORD",
TYPE_EMAIL: "EMAIL",
- TYPE_POINT_WGS84: "POINT_WGS84"
-
-
+ TYPE_POINT_WGS84: "POINT_WGS84",
+ TYPE_GEOJSON: "GEOJSON"
};
var fieldTypes= {
@@ -420,6 +419,17 @@ function validateFieldActual(fieldEl, theForm, formDefinitionKey)
validizeField(fieldEl, theForm);
return true;
}
+ if(fieldDefinition.dataType === dataTypes.TYPE_GEOJSON)
+ {
+ // For now: Check that it's valid JSON??
+ if((webValue === "{}" || webValue === fieldDefinition.nullValue) && fieldDefinition.required === true)
+ {
+ alert(getI18nMsg("mapDataIsRequired"));
+ return false;
+ }
+ validizeField(fieldEl, theForm);
+ return true;
+ }
// Passwords are evaluated in evaluatePassword
if(fieldDefinition.dataType === dataTypes.TYPE_PASSWORD)
@@ -511,6 +521,7 @@ function invalidizeField(inputEl, theForm, message)
// Make sure we don't try to manipulate hidden fields
if(inputEl.type === "hidden")
{
+ alert(message);
return;
}
styleInvalid(theForm[inputEl.name]);
diff --git a/src/main/webapp/templates/observationForm.ftl b/src/main/webapp/templates/observationForm.ftl
index b94734a90244d15ea9d0603dbde42d3134a514e5..f1cbe9a61b4492a03a00d01533b37428684912bb 100755
--- a/src/main/webapp/templates/observationForm.ftl
+++ b/src/main/webapp/templates/observationForm.ftl
@@ -55,7 +55,8 @@
<#if observation.location?has_content>
initMap([${(observation.location.x?c)!""},${(observation.location.y?c)!""}],10,true);
<#else>
- initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},false);
+ var geoInfo = <#if observation.geoinfo?has_content>${observation.geoinfo}<#else>{}</#if>;
+ initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},false, geoInfo);
</#if>
});
</script>
@@ -72,7 +73,8 @@
<div class="row">
<div class="col-md-6">
<#assign formId = "observationForm">
- <form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="return validateForm(this);">
+ <form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="this['geoInfo'].value=getFeatures();return validateForm(this);">
+ <input type="hidden" name="geoInfo" value=""/>
<input type="hidden" name="observationId" value="${observation.observationId!"-1"}"/>
<div class="form-group">
<label for="organismId">${i18nBundle.organism}</label>
@@ -86,11 +88,11 @@
</select>
<span class="help-block" id="${formId}_organismId_validation"></span>
</div>
- <div class="form-group">
+ <!--div class="form-group">
<label for="location">${i18nBundle.location}</label>
<input type="text" class="form-control" readonly="readonly" id="location" name="location" placeholder="${i18nBundle.location}" value="${(observation.location.x?c)!""},${(observation.location.y?c)!""}" onblur="validateField(this);" />
<span class="help-block" id="${formId}_location_validation"></span>
- </div>
+ </div-->
<div class="form-group">
<label for="timeOfObservation">${i18nBundle.timeOfObservation}</label>
<input type="datetime" class="form-control" name="timeOfObservation" placeholder="${i18nBundle.timeOfObservation}" value="${(observation.timeOfObservation?string("yyyy-MM-dd HH:mmZ"))!.now?string("yyyy-MM-dd HH:mmZ")}" onblur="validateField(this);" />
diff --git a/src/test/java/no/nibio/vips/logic/entity/ObservationTest.java b/src/test/java/no/nibio/vips/logic/entity/ObservationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3fc6529922d8eee10d3063045ce7a67ed928c08
--- /dev/null
+++ b/src/test/java/no/nibio/vips/logic/entity/ObservationTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.entity;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.GeometryCollection;
+import com.vividsolutions.jts.geom.Point;
+import java.util.Date;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author treinar
+ */
+public class ObservationTest {
+
+ public ObservationTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+
+ /**
+ * Test of setGeoinfoFromJson method, of class Observation.
+ */
+ //@Test
+ public void testSetGeoinfoFromJson() {
+ System.out.println("setGeoinfoFromJson");
+ String geoinfo = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[10.669097900390623,59.753628151319106],[10.612792968749998,59.70309199431276],[10.726776123046873,59.705863076677105],[10.669097900390623,59.753628151319106]]]},\"properties\":null},{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[10.704803466796873,59.64831609639066]},\"properties\":null},{\"type\":\"Feature\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[10.649871826171871,59.67051458978321],[10.791320800781248,59.67328836837126]]},\"properties\":null}]}";
+ Observation instance = new Observation();
+ //instance.setGeoinfoFromJson(geoinfo);
+ //System.out.println(instance.getGeoinfoFromJson());
+ }
+
+ /**
+ * Test of getGeoinfoFromJson method, of class Observation.
+ */
+ //@Test
+ public void testGetGeoinfoFromJson() {
+ System.out.println("getGeoinfoFromJson");
+ Observation instance = new Observation();
+ String expResult = "";
+ //String result = instance.getGeoinfoFromJson();
+ //assertEquals(expResult, result);
+
+ }
+
+
+}
diff --git a/src/test/java/no/nibio/vips/logic/util/GISUtilTest.java b/src/test/java/no/nibio/vips/logic/util/GISUtilTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bd5c491fe948b90b23b88c285368bc96755512a
--- /dev/null
+++ b/src/test/java/no/nibio/vips/logic/util/GISUtilTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.util;
+
+import com.vividsolutions.jts.geom.Geometry;
+import java.util.List;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author treinar
+ */
+public class GISUtilTest {
+
+ public GISUtilTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of getGeometriesFromGeoJSON method, of class GISUtil.
+ */
+ @Test
+ public void testRoundtrip() {
+ System.out.println("testRoundtrip");
+ String json = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[10.669097900390623,59.753628151319106],[10.612792968749998,59.70309199431276],[10.726776123046873,59.705863076677105],[10.669097900390623,59.753628151319106]]]},\"properties\":{}},{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[10.704803466796873,59.64831609639066]},\"properties\":{}},{\"type\":\"Feature\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[10.649871826171871,59.67051458978321],[10.791320800781248,59.67328836837126]]},\"properties\":{}}]}";
+ GISUtil instance = new GISUtil();
+ //List<Geometry> expResult = null;
+ List<Geometry> geometries = instance.getGeometriesFromGeoJSON(json);
+ String result = instance.getGeoJSONFromGeometries(geometries);
+ //System.out.println(result);
+ assertEquals(json, result);
+ }
+
+
+}