diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..a48a60f8a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,52 @@
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+
+# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
+!/.mvn/wrapper/maven-wrapper.jar
+
+#logs ws
+logs/*
+
+#target
+phis2-ws/target/
diff --git a/phis2-ws/licenseheader.txt b/phis2-ws/licenseheader.txt
new file mode 100644
index 000000000..674d69ab0
--- /dev/null
+++ b/phis2-ws/licenseheader.txt
@@ -0,0 +1,11 @@
+//**********************************************************************************************
+// XXX.java
+//
+// Author(s): Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: XX 2017
+// Contact: morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: XX, 2017
+// Subject: XX
+//***********************************************************************************************
diff --git a/phis2-ws/nb-configuration.xml b/phis2-ws/nb-configuration.xml
new file mode 100644
index 000000000..15c52c535
--- /dev/null
+++ b/phis2-ws/nb-configuration.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ 1.7-web
+ Tomcat
+ ide
+ none
+ ${project.basedir}/licenseheader.txt
+
+
diff --git a/phis2-ws/pom.xml b/phis2-ws/pom.xml
new file mode 100644
index 000000000..2b97bc7f6
--- /dev/null
+++ b/phis2-ws/pom.xml
@@ -0,0 +1,216 @@
+
+
+ 4.0.0
+
+ com.mycompany
+ phis2ws
+ v0.1
+ war
+ phis2ws
+
+
+ ${project.build.directory}/endorsed
+ UTF-8
+ 1.1.7
+
+
+
+
+
+ spring-milestones
+ http://repo.spring.io/libs-milestone/
+
+
+
+
+
+ org.apache.tomcat
+ tomcat-jdbc
+ 9.0.0.M6
+ jar
+
+
+ org.mongodb
+ mongodb-driver
+ 3.2.2
+ jar
+
+
+ org.eclipse.rdf4j
+ rdf4j-runtime
+ 2.2
+
+
+ org.eclipse.rdf4j
+ rdf4j-repository-api
+ 2.2
+
+
+ com.jcraft
+ jsch
+ 0.1.53
+ jar
+
+
+ com.google.code.gson
+ gson
+ 2.7
+ jar
+
+
+ com.nimbusds
+ nimbus-jose-jwt
+ 4.22
+ jar
+
+
+ commons-codec
+ commons-codec
+ 1.10
+ jar
+
+
+ com.twmacinta
+ fast-md5
+ 2.7.1
+ jar
+
+
+ javax
+ javaee-web-api
+ 7.0
+ provided
+
+
+ org.glassfish.jersey.core
+ jersey-server
+ 2.25
+
+
+ org.glassfish.jersey.core
+ jersey-client
+ 2.25
+
+
+ org.glassfish.jersey.core
+ jersey-common
+ 2.25
+
+
+ org.glassfish.jersey.containers
+ jersey-container-servlet
+ 2.25
+
+
+ io.swagger
+ swagger-jersey2-jaxrs
+ 1.5.13
+
+
+ org.glassfish.jersey.media
+ jersey-media-moxy
+ 2.25
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback-version}
+
+
+ ch.qos.logback
+ logback-core
+ ${logback-version}
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.21
+
+
+
+ org.codehaus.janino
+ janino
+ 2.5.16
+
+
+ org.postgis
+ postgis-jdbc
+ 1.3.3
+
+
+
+ org.postgresql
+ postgresql
+ 9.4.1212.jre7
+
+
+ commons-logging
+ commons-logging
+ 1.1.1
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.9.0.pr1
+
+
+ joda-time
+ joda-time
+ 2.9.9
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 1.7
+ 1.7
+
+ ${endorsed.dir}
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 2.3
+
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.6
+
+
+ validate
+
+ copy
+
+
+ ${endorsed.dir}
+ true
+
+
+ javax
+ javaee-endorsed-api
+ 7.0
+ jar
+
+
+
+
+
+
+
+
+
diff --git a/phis2-ws/src/main/java/phis2ws/service/ApplicationInitConfig.java b/phis2-ws/src/main/java/phis2ws/service/ApplicationInitConfig.java
new file mode 100644
index 000000000..cc4c9a201
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/ApplicationInitConfig.java
@@ -0,0 +1,96 @@
+//**********************************************************************************************
+// ApplicationInitConfig.java
+//
+// Author(s): Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: january 2017
+// Contact:morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: January, 2017
+// Subject: Configuration of the webservice
+//***********************************************************************************************
+
+package phis2ws.service;
+
+import io.swagger.jaxrs.config.BeanConfig;
+import java.io.File;
+import javax.annotation.PostConstruct;
+import javax.inject.Singleton;
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.glassfish.hk2.api.InjectionResolver;
+import org.glassfish.hk2.api.TypeLiteral;
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.authentication.Session;
+import phis2ws.service.authentication.TokenManager;
+import phis2ws.service.dao.phis.SessionDaoPhisBrapi;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.injection.SessionFactory;
+import phis2ws.service.injection.SessionInject;
+import phis2ws.service.injection.SessionInjectResolver;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.brapi.form.ResponseFormPOST;
+
+@ApplicationPath("/rest")
+public class ApplicationInitConfig extends ResourceConfig {
+
+ final static String PROPERTY_FILE_NAME = "service";
+ final static Logger logger = LoggerFactory.getLogger(ApplicationInitConfig.class);
+
+
+ public ApplicationInitConfig() {
+ packages("io.swagger.jaxrs.listing;"
+ + "wsphisfield.service.resources;"
+ + "wsphisfield.service.json;"
+ + "wsphisfield.service.resources.request.filters");
+
+ //Swagger
+ BeanConfig beanConfig = new BeanConfig();
+ beanConfig.setVersion("1.0.2");
+ beanConfig.setSchemes(new String[]{"http"});
+
+ beanConfig.setHost(PropertiesFileManager.getConfigFileProperty("service", "host"));
+ beanConfig.setBasePath(PropertiesFileManager.getConfigFileProperty("service", "basePath"));
+
+ beanConfig.setResourcePackage("wsphisfield.service.resources");
+ beanConfig.setScan(true);
+ // Annotation SessionInject pour obtenir la session en cours et l'utilisateur
+ // Liaison entre le createur d'objet a partir de la requete du client et l'application
+// @see https://jersey.java.net/documentation/latest/ioc.html
+ register(new AbstractBinder() {
+ @Override
+ protected void configure() {
+ // cree la session a partir du sessionId reçu
+ bindFactory(SessionFactory.class).to(Session.class);
+ // Injection de la session grace au type definit dans SessionInjectResolver
+ bind(SessionInjectResolver.class)
+ .to(new TypeLiteral>() {
+ })
+ .in(Singleton.class);
+ }
+ });
+ }
+
+ @PostConstruct
+ public static void initialize() {
+ final String logDirectory = PropertiesFileManager.getConfigFileProperty("service", "logDirectory");
+ if (logDirectory != null) {
+ File logDir = new File(logDirectory);
+ if (!logDir.isDirectory()) {
+ if (!logDir.mkdirs()) {
+ logger.error("Can't create log directory");
+ throw new WebApplicationException(
+ Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity(new ResponseFormPOST(new Status("Can't create log directory", StatusCodeMsg.ERR, null))).build());
+ }
+ }
+ }
+ TokenManager.Instance();
+ SessionDaoPhisBrapi sessionDao = new SessionDaoPhisBrapi();
+// sessionDao.reloadActiveSession();
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/PropertiesFileManager.java b/phis2-ws/src/main/java/phis2ws/service/PropertiesFileManager.java
new file mode 100644
index 000000000..91e7f77f0
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/PropertiesFileManager.java
@@ -0,0 +1,244 @@
+//**********************************************************************************************
+// PropertiesFileManager.java
+//
+// Author(s): Arnaud CHARLEROY, Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr,
+// morgane.vidal@inra.fr
+// Last modification date: January, 2017
+// Subject: Read properties file
+//***********************************************************************************************
+package phis2ws.service;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Objects;
+import java.util.Properties;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Gère les méthodes appelant tous types de propriétés à partir de fichier de
+ * configuration Les fichiers sont disponible dans /src/main/resources par
+ * défaut dans un projet Maven
+ *
+ * @date 05/2016
+ * @author Arnaud CHARLEROY
+ */
+public class PropertiesFileManager {
+
+ final static Logger logger = LoggerFactory.getLogger(PropertiesFileManager.class.getName());
+
+ /**
+ * Lit le fichier de configuration et retourne un objet Proprietes
+ *
+ * @param fileName nom du fichier à lire
+ * @return null | Properties
+ */
+ public static Properties parseFile(String fileName) {
+ InputStream inputStream = null;
+ final Properties props = new Properties();
+ //property is in /src/main/resources By default in maven project
+
+ final String filePath = "/" + fileName + ".properties";
+// System.err.println(filePath);
+
+ try {
+ inputStream = PropertiesFileManager.class.getResourceAsStream(filePath);
+ props.load(inputStream);
+ } catch (IOException | NullPointerException ex) {
+ logger.error(ex.getMessage(), ex);
+ // Si les paramètres ne sont pas récupérés le web service propage une exception INTERNAL_SERVER_ERROR
+ throw new WebApplicationException(Response
+ .status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity("Error : Cannot find " + fileName + " configuration file for the wanted database\n" + ex.getMessage()).build());
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException ex) {
+ logger.error(ex.getMessage(), ex);
+ }
+ }
+ }
+ return props;
+ }
+
+ public static RSAPublicKey parseBinaryPublicKey(String fileName) {
+ //property is in /src/main/resources By default in maven project
+ RSAPublicKey generatedRSAPublicKey = null;
+ DataInputStream dataInputStream = null;
+ try {
+ URL resource = PropertiesFileManager.class.getResource("/" + fileName + ".der");
+ File publicKeyFile = new File(resource.getPath());
+ dataInputStream = new DataInputStream(new FileInputStream(publicKeyFile));
+ byte[] keyBytes = new byte[(int) publicKeyFile.length()];
+ dataInputStream.readFully(keyBytes);
+ dataInputStream.close();
+
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ generatedRSAPublicKey = (RSAPublicKey) kf.generatePublic(spec);
+
+ } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ logger.error(ex.getMessage(), ex);
+ // Si les paramètres ne sont pas récupérés le web service propage une exception INTERNAL_SERVER_ERROR
+ throw new WebApplicationException(Response
+ .status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity("Can't process JWT Token" + ex.getMessage()).build());
+ } finally {
+ if (dataInputStream != null) {
+ try {
+ dataInputStream.close();
+ } catch (IOException ex) {
+ logger.error(ex.getMessage(), ex);
+ }
+ }
+ }
+ return generatedRSAPublicKey;
+ }
+
+ /**
+ * Lit un fichier de configuration et retourne d'un attribut spécifique
+ *
+ * @param fileName nom du fichier à lire
+ * @param prop nom de lattribut
+ * @return null | Properties
+ */
+ public static String getConfigFileProperty(String fileName, String prop) {
+ try {
+ final Properties sqlProps = parseFile(fileName);
+ final StringBuilder strBuilder = new StringBuilder();
+ strBuilder.append(sqlProps.getProperty(prop));
+ return strBuilder.toString();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage(), ex);
+ ex.printStackTrace();
+ // Si les paramètres ne sont pas récupérés le web service propage une exception INTERNAL_SERVER_ERROR
+ throw new WebApplicationException(Response
+ .status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity("Error : Cannot find properties in the configuration file " + fileName + " for the wanted database\n" + ex.getMessage()).build());
+ }
+ }
+
+ /**
+ * Lit un fichier de configuration et retourne l'url pour une base de donnée
+ * SQL contenant le nom, l'utilisateur et le serveur
+ *
+ * @param fileName nom du fichier à lire
+ * @return null | Properties
+ */
+ public static String getSQLConnectionUrl(String fileName) {
+ try {
+ final Properties sqlProps = parseFile(fileName);
+ final StringBuilder strBuilder = new StringBuilder();
+ strBuilder.append(sqlProps.getProperty("url"))
+ .append("?")
+ .append("user=").append(sqlProps.getProperty("username"))
+ .append("&")
+ .append("password=").append(sqlProps.getProperty("password"));
+ return strBuilder.toString();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage(), ex);
+ // Si les paramètres ne sont pas récupérés le web service propage une exception INTERNAL_SERVER_ERROR
+ throw new WebApplicationException(Response
+ .status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity("Error : Cannot find " + fileName + " configuration file for the wanted database\n" + ex.getMessage()).build());
+ }
+ }
+
+ /**
+ * Lit un fichier de configuration et un objet PoolPropreties permettant de
+ * configurer un jeu de connexion de base de donnée relationelle
+ *
+ * @see https://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html
+ * @param fileName nom du fichier à lire
+ * @return null | Properties
+ */
+ public static PoolProperties getSQLPoolDataSourceProperties(String fileName) {
+ try {
+ final PoolProperties p = new PoolProperties();
+ // minimal configuration
+ p.setUrl(getConfigFileProperty(fileName, "url"));
+ p.setDriverClassName(getConfigFileProperty(fileName, "driver"));
+ p.setUsername(getConfigFileProperty(fileName, "username"));
+ p.setPassword(getConfigFileProperty(fileName, "password"));
+ // Optional
+ if (!Objects.equals(getConfigFileProperty(fileName, "jmxEnabled"), "null")) {
+ p.setJmxEnabled(Boolean.valueOf(getConfigFileProperty(fileName, "jmxEnabled")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "defaultAutoCommit"), "null")) {
+ p.setDefaultAutoCommit(Boolean.valueOf(getConfigFileProperty(fileName, "defaultAutoCommit")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "testWhileIdle"), "null")) {
+ p.setTestWhileIdle(Boolean.valueOf(getConfigFileProperty(fileName, "testWhileIdle")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "testOnBorrow"), "null")) {
+ p.setTestOnBorrow(Boolean.valueOf(getConfigFileProperty(fileName, "testOnBorrow")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "validationQuery"), "null")) {
+ p.setValidationQuery(getConfigFileProperty(fileName, "validationQuery"));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "testOnReturn"), "null")) {
+ p.setTestOnReturn(Boolean.valueOf(getConfigFileProperty(fileName, "testOnReturn")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "validationInterval"), "null")) {
+ p.setValidationInterval(Long.valueOf(getConfigFileProperty(fileName, "validationInterval")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "timeBetweenEvictionRunsMillis"), "null")) {
+ p.setTimeBetweenEvictionRunsMillis(Integer.valueOf(getConfigFileProperty(fileName, "timeBetweenEvictionRunsMillis")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "maxActive"), "null")) {
+ p.setMaxActive(Integer.valueOf(getConfigFileProperty(fileName, "maxActive")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "minIdle"), "null")) {
+ p.setMinIdle(Integer.valueOf(getConfigFileProperty(fileName, "minIdle")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "maxIdle"), "null")) {
+ p.setMaxIdle(Integer.valueOf(getConfigFileProperty(fileName, "maxIdle")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "initialSize"), "null")) {
+ p.setInitialSize(Integer.valueOf(getConfigFileProperty(fileName, "initialSize")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "maxWait"), "null")) {
+ p.setMaxWait(Integer.valueOf(getConfigFileProperty(fileName, "maxWait")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "removeAbandonedTimeout"), "null")) {
+ p.setRemoveAbandonedTimeout(Integer.valueOf(getConfigFileProperty(fileName, "removeAbandonedTimeout")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "maxAge"), "null")) {
+ p.setMaxAge(Long.valueOf(getConfigFileProperty(fileName, "maxAge")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "logAbandoned"), "null")) {
+ p.setLogAbandoned(Boolean.valueOf(getConfigFileProperty(fileName, "logAbandoned")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "removeAbandoned"), "null")) {
+ p.setRemoveAbandoned(Boolean.valueOf(getConfigFileProperty(fileName, "removeAbandoned")));
+ }
+ if (!Objects.equals(getConfigFileProperty(fileName, "jdbcInterceptors"), "null")) {
+ p.setJdbcInterceptors(getConfigFileProperty(fileName, "jdbcInterceptors"));
+ }
+
+ return p;
+
+ } catch (Exception ex) {
+ logger.error("Error : Cannot find " + fileName + " configuration file \n", ex);
+ return null;
+ }
+ }
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/authentication/DataTable.java b/phis2-ws/src/main/java/phis2ws/service/authentication/DataTable.java
new file mode 100644
index 000000000..f179671ff
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/authentication/DataTable.java
@@ -0,0 +1,141 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package phis2ws.service.authentication;
+
+/**
+ *
+ * @author cherimon
+ * @Update AC 05/16 Mise à jour de la connexion aux données
+ */
+public class DataTable {
+
+ private String instanceNumber, observationVariableId, observationVariableDbId, season, observationValue, observationTimeStamp, collectionFacilityLabel, collector;
+
+ public DataTable() {
+ }
+
+ public DataTable(String instanceNumber, String observationVariableId, String observationVariableDbId, String season, String observationValue, String observationTimeStamp, String collectionFacilityLabel, String collector) {
+ this.instanceNumber = instanceNumber;
+ this.observationVariableId = observationVariableId;
+ this.observationVariableDbId = observationVariableDbId;
+ this.season = season;
+ this.observationValue = observationValue;
+ this.observationTimeStamp = observationTimeStamp;
+ this.collectionFacilityLabel = collectionFacilityLabel;
+ this.collector = collector;
+ }
+
+ public void setInstanceNumber(String instanceNumber) {
+ if (instanceNumber != null) {
+ this.instanceNumber = instanceNumber;
+ } else {
+ this.instanceNumber = "";
+ }
+ }
+
+ public void setObservationVariableId(String observationVariableId) {
+ if (observationVariableId != null) {
+ this.observationVariableId = observationVariableId;
+ } else {
+ this.observationVariableId = "";
+ }
+ }
+
+ public void setObservationVariableDbId(String observationVariableDbId) {
+ if (observationVariableDbId != null) {
+ this.observationVariableDbId = observationVariableDbId;
+ } else {
+ this.observationVariableDbId = "";
+ }
+ }
+
+ public void setSeason(String season) {
+ if (season != null) {
+ this.season = season;
+ } else {
+ this.season = "";
+ }
+ }
+
+ public void setObservationValue(String observationValue) {
+ if (observationValue != null) {
+ this.observationValue = observationValue;
+ } else {
+ this.observationValue = "";
+ }
+ }
+
+ public void setObservationTimeStamp(String observationTimeStamp) {
+ if (observationTimeStamp != null) {
+ this.observationTimeStamp = observationTimeStamp;
+ } else {
+ this.observationTimeStamp = "";
+ }
+ }
+
+ public void setCollectionFacilityLabel(String collectionFacilityLabel) {
+ if (collectionFacilityLabel != null) {
+ this.collectionFacilityLabel = collectionFacilityLabel;
+ } else {
+ this.collectionFacilityLabel = "";
+ }
+ }
+
+ public void setCollector(String collector) {
+ if (collector != null) {
+ this.collector = collector;
+ } else {
+ this.collector = "";
+ }
+ }
+
+ public String getInstanceNumber() {
+ return instanceNumber;
+ }
+
+ public String getObservationVariableId() {
+ return observationVariableId;
+ }
+
+ public String getObservationVariableDbId() {
+ return observationVariableDbId;
+ }
+
+ public String getSeason() {
+ return season;
+ }
+
+ public String getObservationValue() {
+ return observationValue;
+ }
+
+ public String getObservationTimeStamp() {
+ return observationTimeStamp;
+ }
+
+ public String getCollectionFacilityLabel() {
+ return collectionFacilityLabel;
+ }
+
+ public String getCollector() {
+ return collector;
+ }
+
+
+
+
+
+// public void fillDataTable(ResultSet resultat) throws SQLException {
+// setInstanceNumber(resultat.getString("date") + ":" + resultat.getString("sensor") + ":" + resultat.getString("codeVariable"));
+// setObservationVariableId(resultat.getString("codeVariable"));
+// setObservationVariableDbId(resultat.getString("codeVariable"));
+// setSeason(resultat.getString("season"));
+// setObservationValue(resultat.getString("value"));
+// setObservationTimeStamp(resultat.getString("date"));
+// setCollectionFacilityLabel(resultat.getString("site"));
+// setCollector(resultat.getString("sensor"));
+// }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/authentication/Session.java b/phis2-ws/src/main/java/phis2ws/service/authentication/Session.java
new file mode 100644
index 000000000..80ae7291a
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/authentication/Session.java
@@ -0,0 +1,144 @@
+package phis2ws.service.authentication;
+
+import phis2ws.service.model.User;
+
+/**
+ * Session - Permet de créer des objets correspondant aux différentes sessions
+ * utilisateur
+ *
+ * @version1.0
+ *
+ * @author Samuël Chérimont
+ * @date 25/11/2015
+ * @note Les champs dateStart et dateEnd ne sont pas utilisés pour le moment
+ * @update Anraud CHARLEROY Définir SQLDBModel et les cahmps uniques dans
+ * Session
+ */
+public class Session {
+
+ private String dateStart;
+ private String dateEnd;
+ private String id;
+ private String name;
+ private User user;
+
+ public Session() {
+ }
+
+ public Session(String dateStart, String dateEnd, String id, String name) {
+ this.dateStart = dateStart;
+ this.dateEnd = dateEnd;
+ this.id = id;
+ this.name = name;
+ this.user = new User(name);
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public String getDateStart() {
+ return dateStart;
+ }
+
+ public String getDateEnd() {
+ return dateEnd;
+ }
+
+
+ /**
+ * Session() - Initialise tous les champs de l'objet Session
+ *
+ * @param id Identifiant de session
+ * @param name Nom de l'utilisateur
+ *
+ * @see setDateStart(),setDateEnd(), setFamilyName(), setId()
+ * @date 25/11/2015
+ * @update AC 07/16 Modification utilisation des attributs privés plutôt que
+ * de passer par des setters publiques
+ */
+ public Session(String id, String name) {
+ this.dateStart = null;
+ this.dateEnd = null;
+ this.name = name;
+ this.id = id;
+ this.user = new User(name);
+ }
+
+ public Session(String id, String name, User u) {
+ this.dateStart = null;
+ this.dateEnd = null;
+ this.name = name;
+ this.id = id;
+ this.user = u;
+ }
+
+ /**
+ * getId() - Récupère l'identifiant ed la session
+ *
+ * @return l'identifiant de session
+ * @date 25/11/2015
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * getFamilyName() - Récupère le nom de l'utilisateur correspondant à la session
+ représentée par l'instanec de Session
+ *
+ * @return le nom de l'utilisateur
+ * @date 25/11/2015
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * setDateStart() - Initialise le champ dateStart d'une instance de session
+ * avec la date de connection de l'utilisateur
+ *
+ * @param dateStart Date de connection
+ *
+ * @date 25/11/2015
+ * @note Inutilisée pour le moment
+ */
+ public void setDateStart(String dateStart) {
+ this.dateStart = dateStart;
+ }
+
+ /**
+ * setDateEnd() - Initialise le champ dateEnd d'une instance de Session avec
+ * la date de fin de connection de l'utilisateur
+ *
+ * @param dateEnd date de fin de session
+ *
+ * @date 25/11/2015
+ * @note Inutilisée pour le moment
+ */
+ public void setDateEnd(String dateEnd) {
+ this.dateEnd = dateEnd;
+ }
+
+ /**
+ * setid() - Initialise le champ id d'une instance de Session avec un
+ * identifiant de session
+ *
+ * @param id identifiant de session
+ * @date 25/11/2015
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * setFamilyName() - Initialise le champ name d'une instance de Session
+ *
+ * @param name Nom d'utilisateur
+ * @date 25/11/2015
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/authentication/SessionThread.java b/phis2-ws/src/main/java/phis2ws/service/authentication/SessionThread.java
new file mode 100644
index 000000000..fc7fb357c
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/authentication/SessionThread.java
@@ -0,0 +1,97 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package phis2ws.service.authentication;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.PropertiesFileManager;
+
+/**
+ * SessionThread - Extension de la classe Thread Prend en charge la gestion du temps
+ de connection d'une session
+ *
+ * @version1.0
+ *
+ * @author Samuël Chérimont
+ * @see DbConnector
+ * @date 25/11/2015
+ * @update AC 05/2016 Ajout TokenDAO, log et modification des fichiers de propriétés
+ */
+public class SessionThread extends Thread {
+ private static final String propsFileName = "service";
+ final static Logger logger = LoggerFactory.getLogger(SessionThread.class);
+
+ private final String id, username;
+ private boolean cmp;
+ private Integer sessionTime; //sleep en millisecond
+
+ public SessionThread(String id, String username) {
+ this.id = id;
+ this.username = username;
+ cmp = true;
+ this.setTimeSession();
+ }
+
+ /**
+ * Update 20/06/14 Temps en seconde *1000
+ */
+ private void setTimeSession(){
+ try {
+ this.sessionTime = Integer.valueOf(PropertiesFileManager.getConfigFileProperty(propsFileName, "sessionTime")) * 1000;
+ } catch (NumberFormatException e) {
+ logger.error("Error : No session time defined or file parsing error for "+ propsFileName +" properties file", e);
+ }
+ }
+
+ /**
+ * run() - Execution du thread actuel Le thread est mis en pause un certain
+ * temps, qui peut etre allongé en fonction du comportement de
+ * l'utilisateur et
+ * supprime l'objet Session correspondant de la liste des sessions actives
+ *
+ * @see phenomeapi.service.model.brapi.authentication.TokenDaoPhisBraphi,TokenManager.removeSession()
+ * @date 25/11/2015
+ * @update 09/02/2016 AT : ne met plus la bd à jour, déplacé dans le manager + properties du temps de session
+ *
+ */
+ @Override
+ public void run() {
+ try {
+ while (cmp != false) {
+ cmp = false;
+ SessionThread.sleep(this.sessionTime);
+ }
+ } catch (InterruptedException ex) {
+ logger.info("The session was interrupted", ex);
+ }
+ TokenManager.Instance().removeSession(this.id);
+ this.interrupt();
+ }
+
+ /**
+ * addTime - Permet d'augmenter le temps de connection d'un utilisateur
+ * Replace le compteur utilisé dans run() sur true ce qui met le thread sur
+ * pause plus longtemps et donc retarde la fin de la session correspondante
+ *
+ * @see run()
+ * @date 25/11/2015
+ */
+ public void addTime() {
+ this.cmp = true;
+ }
+
+ /**
+ * getSessionId - Récupère l'identifiant de la session gérée par cette
+ instance de SessionThread
+ *
+ * @return l'identifiant de de la session
+ *
+ * @date 25/11/2015
+ */
+ public String getSessionId() {
+ return this.id;
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/authentication/TokenManager.java b/phis2-ws/src/main/java/phis2ws/service/authentication/TokenManager.java
new file mode 100644
index 000000000..af35e60e4
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/authentication/TokenManager.java
@@ -0,0 +1,295 @@
+package phis2ws.service.authentication;
+
+import phis2ws.service.dao.phis.UserDaoPhisBrapi;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.dao.phis.SessionDaoPhisBrapi;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.brapi.form.ResponseFormGET;
+
+/**
+ * Connection Manager - Permet la gestion de toutes les sessions et
+ * authentification par l'intermédiaire d'une seule instance de cette classe
+ *
+ * @version1.0
+ * @author Samuël Chérimont
+ * @date 25/11/2015
+ */
+public class TokenManager {
+
+ static final Logger logger = LoggerFactory.getLogger(TokenManager.class);
+ private ArrayList listSession;
+ private ArrayList listThread;
+ private static TokenManager _instance = null;
+
+ /**
+ * Instance() - Méthode de classe permettant de créer une instance unique de
+ * TokenManager Cette méthode doit être appelée à la place du constructeur
+ * de la classe TokenManager
+ *
+ * exemple ConnectionManger instance = TokenManager.Instance();
+ *
+ * @return une instance unique de TokenManager
+ * @date 26/11/2015
+ */
+ public static TokenManager Instance() {
+ if (_instance == null) {
+ _instance = new TokenManager();
+ }
+ return _instance;
+ }
+
+ /**
+ * addThread() - Méthode privée appelée dans createToken() Crée un objet
+ * SessionThread pour chaque nouvel utilisateur qui se connecte, l'ajoute à
+ * une liste d'où il sera accessible et lance le nouveau thread
+ *
+ * @param id Identifiant de session
+ * @param username Nom de l'utilisateur
+ *
+ * @see SessionThreadcreateToken()
+ * @date 26/11/2015
+ */
+ private void addThread(String id, String username) {
+ if (this.listThread == null) {
+ this.listThread = new ArrayList();
+ }
+ this.removeEmptyThread();
+ SessionThread newThread = new SessionThread(id, username);
+ listThread.add(newThread);
+ newThread.start();
+ }
+
+
+ private void removeThread(String id) {
+ int i = 0;
+ boolean interrupted = false;
+ while (i < listThread.size() && !interrupted) {
+ if (listThread.get(i).getSessionId().equals(id)) {
+ listThread.get(i).interrupt();
+ listThread.remove(listThread.get(i));
+ interrupted = true;
+ }
+ i++;
+ }
+ }
+ /**
+ * reloadToken() - Rajoute du temps de connection à un utilisateur identifié
+ * par son id
+ *
+ * @param id Identifiant de connection de l'utilisateur
+ *
+ * @see SessionThread
+ * @date 26/11/2015
+ */
+ public void reloadToken(String id) {
+ if (id != null && (listThread != null && !listThread.isEmpty())) {
+ int i = 0;
+ while (i < listThread.size()) {
+ if (this.listThread.get(i).getSessionId().equals(id)) {
+ this.listThread.get(i).addTime();
+ return;
+ }
+ i++;
+ }
+ }
+ }
+
+ /**
+ * removeEmptyThread - Supprime tout objet SessionThread ayant terminé son
+ * execution de la liste de threads
+ *
+ * @date 26/11/2015
+ */
+ private void removeEmptyThread() {
+ int i = 0;
+ while (i < listThread.size()) {
+ if (!listThread.get(i).isAlive()) {
+ listThread.remove(listThread.get(i));
+ }
+ i++;
+ }
+ }
+
+ /**
+ * searchSession() - Méthode appelée au moment de l'authentification
+ * Recherche si l'utilisateur identifié par name est présent dans la liste
+ * des sessions actives
+ *
+ * @param name Nom de l'utilisateur
+ * @return une String correspondant a l'identifiant de session de
+ * l'utilisateur ou null si aucune session n'est active pour cet utilisateur
+ *
+ * @see Token.getConnection()
+ * @date 26/11/2015
+ */
+ public String searchSession(String name) {
+ if (listSession != null && !listSession.isEmpty()) {
+ int i = 0;
+ while (i < listSession.size()) {
+ if (name.equals(listSession.get(i).getName())) {
+ return listSession.get(i).getId();
+ }
+ i++;
+ }
+ }
+ return null;
+ }
+
+ public Session getSession(String id) {
+ if (listSession != null && !listSession.isEmpty()) {
+ int i = 0;
+ while (i < listSession.size()) {
+ if (id.equals(listSession.get(i).getId())) {
+ return listSession.get(i);
+ }
+ i++;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * addSession() - Méthode appelée par createToken() Ajoute un objet Session
+ * à la liste des sessions actives
+ *
+ * @param session Un objet Session représentant une nouvelle session active
+ *
+ * @see createSession()
+ * @date 25/11/2015
+ * @note L'accès a cette méthode peut être remplacée par private, dans ce
+ * cas il faut changer le test unitaire de checkAuthentification()
+ *
+ * @update 09/02/2016
+ * @info AT, ajout d'une session au manager = ajout dans la bd, voir plus
+ * tard dao
+ */
+ public void addSession(Session session) {
+ if (this.listSession == null) {
+ this.listSession = new ArrayList();
+ }
+ this.listSession.add(session);
+// logger.debug(this.listSession.toString());
+ //BD
+ SessionDaoPhisBrapi sessionDao = new SessionDaoPhisBrapi();
+ try {
+ session.setDateStart(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
+ sessionDao.insertOrUpdateOrDeleteQueryFromDAO("INSERT INTO session (email, id, date) VALUES ('" + session.getName() + "', '" + session.getId() + "', now())");
+ } catch (SQLException ex) {
+ final Status status = new Status("Can't create session token", StatusCodeMsg.ERR, ex.getMessage());
+ throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new ResponseFormGET(status)).build());
+ } finally {
+ }
+ }
+
+ /**
+ * removeSession - Méthode appelée à la fin de l'execution d'un
+ * SessionThread Supprime un objet Session de la liste des sessions actives
+ * et met a jour la bd en ajoutant la date de fin de validité de la session
+ *
+ * @param id Identifiant de session
+ *
+ * @see MyThread.run()
+ * @date 25/11/2015
+ *
+ * @update 09/02/2016
+ * @info AT lien bd pour invalider la session, déplacé ici
+ */
+ public void removeSession(String id) {
+ if (listSession == null || listSession.isEmpty()) {
+ return;
+ }
+ SessionDaoPhisBrapi sessionDao = new SessionDaoPhisBrapi();
+ int i = 0;
+ boolean find = false;
+ while (i < listSession.size() && !find) {
+ String sessionid = listSession.get(i).getId();
+ if (id.equals(sessionid)) {
+ sessionDao.endSession(sessionid);
+ listSession.remove(i);
+ find = true;
+ }
+ i++;
+ }
+ this.removeThread(id);
+ }
+
+ /**
+ * createToken() - Méthode appelée à chaque nouvelle authentification
+ * réussie Ajoute une session a la liste des sessions actives et crée un
+ * nouveau thread qui va gérer cette session
+ *
+ * @param session Un objet Session représentant une nouvelle session active
+ *
+ * @see addSession(), addThread(), DbConnector.getConnection()
+ * @date 25/11/2015
+ */
+ public void createToken(Session session) {
+ this.addSession(session);
+ this.addThread(session.getId(), session.getName());
+ }
+
+
+ /**
+ * createTokenFromBD() - Méthode appelée à chaque nouvelle authentification
+ * réussie Ajoute une ancienne session a la liste des sessions actives et crée un
+ * nouveau thread qui va gérer cette session
+ *
+ * @param session Un objet Session représentant une nouvelle session active
+ *
+ * @see addSession(), addThread(), DbConnector.getConnection()
+ * @date 25/11/2015
+ */
+ public void createTokenFromBD(Session session) {
+ if (this.listSession == null) {
+ this.listSession = new ArrayList();
+ }
+ this.listSession.add(session);
+ this.addThread(session.getId(), session.getName());
+// logger.debug(JsonConverter.ConvertToJson(this.listSession));
+ }
+
+ /**
+ * checkAuthentification() - Vérifie que la session déterminée par son id
+ * est encore valable et rajoute du temps de connection si la session est
+ * valide
+ *
+ * @param id L'identifiant de la session
+ * @return true si la session est valide ou false si elle ne l'est pas
+ *
+ * @see reloadToken()
+ * @date 25/11/2015
+ */
+ public boolean checkAuthentification(String id) {
+ if (id != null && (this.listSession != null && !this.listSession.isEmpty())) {
+ int i = 0;
+ while (i < listSession.size()) {
+ if (id.equals(listSession.get(i).getId())) {
+// this.reloadToken(id);
+ return true;
+ }
+ i++;
+ }
+ }
+ return false;
+ }
+
+ public void shutdown() {
+ if (this.listSession != null && !this.listSession.isEmpty() && listThread != null && !listThread.isEmpty()) {
+ int i = 0;
+ while (i < listThread.size()) {
+ this.removeSession(listThread.get(i).getSessionId());
+ listThread.get(i).interrupt();
+ listThread.remove(listThread.get(i));
+ }
+ listThread = null;
+ }
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/authentication/TokenResponseStructure.java b/phis2-ws/src/main/java/phis2ws/service/authentication/TokenResponseStructure.java
new file mode 100644
index 000000000..86f8ba102
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/authentication/TokenResponseStructure.java
@@ -0,0 +1,52 @@
+package phis2ws.service.authentication;
+
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.view.brapi.Metadata;
+
+/**
+ * TokenResponseStructure - Prépare le résultat final pour qu'il soit conforme
+ * au modèle de la Plant breeding API
+ *
+ * @version1.0
+ *
+ * @author Samuël Chérimont
+ * @date 25/11/2015
+ * @note session_token n'est pas conforme aux norme de nomination Java
+ */
+public class TokenResponseStructure {
+
+ private final Metadata metadata;
+ private final String userDisplayName;
+ private final String access_token;
+ private final String expires_in;
+
+ /**
+ * ResultForm() - Prepare l'objet métadata vide et associe l'identifiant de
+ * session à la variable session_token
+ *
+ * @param id L'identifiant de session
+ * @param userDisplayName nom et prénome de l'utilisateur
+ *
+ * @see result_output.Metadata
+ * @date 25/11/2015
+ * @update 08/2016
+ */
+ public TokenResponseStructure(String id, String userDisplayName) {
+ this.metadata = new Metadata(0, 0, 1);
+ this.userDisplayName = userDisplayName;
+ this.access_token = id;
+ this.expires_in = PropertiesFileManager.getConfigFileProperty("service", "sessionTime");
+ }
+
+ public TokenResponseStructure(String id, String userDisplayName, String expires_in) {
+ this.metadata = new Metadata(0, 0, 1);
+ this.userDisplayName = userDisplayName;
+ this.access_token = id;
+ if (expires_in == null) {
+ this.expires_in = PropertiesFileManager.getConfigFileProperty("service", "sessionTime");
+ } else {
+ this.expires_in = expires_in;
+ }
+ }
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/configuration/DateFormats.java b/phis2-ws/src/main/java/phis2ws/service/configuration/DateFormats.java
new file mode 100644
index 000000000..86c290c0a
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/configuration/DateFormats.java
@@ -0,0 +1,37 @@
+//**********************************************************************************************
+// DateFormats.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: Dates formats used in the WS
+//***********************************************************************************************
+package phis2ws.service.configuration;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Regroupe les formats de date utilisées dans tout le webService
+ * @date 08/16
+ * @author A. CHARLEROY
+ */
+public final class DateFormats {
+
+
+ public final static String DATETIME_MONGO_MEASURE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSZZ";
+ public final static String DATETIME_JSON_SERIALISATION_FORMAT = "yyyy-MM-dd HH:mm:ssZZ";
+ public final static String DATETIME_METEO_DB_FORMAT = "yyyy-MM-dd HH:mm:ssZZ";
+ public final static String DATETIME_SPARQL_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZ";
+ public final static List DATETIME_MONGO_FORMAT = Arrays.asList("yyyy-MM-dd HH:mm:ss.SSSZZ", "yyyy-MM-dd HH:mm:ss.SSSSSS", "yyyy-MM-dd HH:mm:ss.SSSSSSZZ", "yyyy-MM-dd HH:mm:ssZZ");
+
+ public final static List AUTHORIZED_DATE_FORMATS = Arrays.asList("yyyy-MM-dd HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ssZZ", "yyyy-MM-dd");
+ public final static List AUTHORIZED_USER_METEO_DATE_FORMATS = Arrays.asList("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ssZZ");
+ public final static List AUTHORIZED_USER_SPARQL_DATE_FORMATS = Arrays.asList("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ssZZ");
+ public final static List AUTHORIZED_USER_MONGO_DATE_FORMATS = Arrays.asList("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ssZZ", "yyyy-MM-dd HH:mm:ss.SSSZZ");
+
+ public final static String DATETIME_YMD_FORMAT = "yyyy-MM-dd";
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/configuration/DefaultBrapiPaginationValues.java b/phis2-ws/src/main/java/phis2ws/service/configuration/DefaultBrapiPaginationValues.java
new file mode 100644
index 000000000..5f0ec2798
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/configuration/DefaultBrapiPaginationValues.java
@@ -0,0 +1,24 @@
+//**********************************************************************************************
+// DefaultBrapiPaginationValues.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: Give BRAPI parameters defaut values
+//***********************************************************************************************
+package phis2ws.service.configuration;
+
+/**
+ * Défini les valeurs par défaut du WebService selon la Plant Breeding API
+ * 06/16
+ * @author Arnaud CHARLEROY
+ * @see http://docs.brapi.apiary.io/#
+ */
+public final class DefaultBrapiPaginationValues {
+
+ public final static String PAGE_SIZE = "20";
+ public final static String PAGE = "0";
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/configuration/GlobalWebserviceValues.java b/phis2-ws/src/main/java/phis2ws/service/configuration/GlobalWebserviceValues.java
new file mode 100644
index 000000000..f56528cdf
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/configuration/GlobalWebserviceValues.java
@@ -0,0 +1,35 @@
+//**********************************************************************************************
+// GlobalWebserviceValues.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: Recognize sessionInject utilisation in jersey resources
+//***********************************************************************************************
+package phis2ws.service.configuration;
+
+import phis2ws.service.documentation.StatusCodeMsg;
+import javax.ws.rs.core.Response;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.brapi.form.ResponseFormGET;
+
+/**
+ * Définit des réponse qui seront utilisées par défaut dans le
+ * WebService
+ * @date 07/16
+ * @author Arnaud CHARLEROY
+ */
+public final class GlobalWebserviceValues {
+
+// BRAPI V1
+ public static final String AUTHORIZATION_PROPERTY = "Authorization";
+ public static final String AUTHENTICATION_SCHEME = "Bearer";
+ public static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED)
+ .entity(new ResponseFormGET(new Status("Access error",StatusCodeMsg.ERR, "You cannot access this resource"))).build();
+ public static final Response ACCESS_FORBIDDEN = Response.status(Response.Status.FORBIDDEN)
+ .entity(new ResponseFormGET(new Status("Access error",StatusCodeMsg.ERR, "Access blocked for all users !!"))).build();
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/configuration/URINamespaces.java b/phis2-ws/src/main/java/phis2ws/service/configuration/URINamespaces.java
new file mode 100644
index 000000000..a721643dd
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/configuration/URINamespaces.java
@@ -0,0 +1,186 @@
+//**********************************************************************************************
+// URINamespaces.java from uris.php
+//
+// Author(s): Isabelle NEMBROT, Arnaud CHARLEROY, Morgane Vidal
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:i.nembrot@laposte.net, arnaud.charleroy@inra.fr, morgane.vidal@inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: June, 2017 (adaptation to PHIS field)
+// Subject: personal parameters for global usage
+// G_URI :
+// - M3P URI for further use so that we don"t need to repeat paths in each page
+// Usage :
+// ~~~~~~ URINamespaces uris = new URINamespaces("m3p");
+// ~~~~~~ String vocabulary = URINamespaces.getContextsProperty("pVocaPlateform")
+//***********************************************************************************************
+
+package phis2ws.service.configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+import phis2ws.service.PropertiesFileManager;
+
+
+/**
+ * Permet de creer des URI de concepts, objets et relation entre objets et proprietes en fonction pour une platform
+ * @author A. CHARLEROY
+ */
+public class URINamespaces {
+
+ private static final Map CONTEXTS = new HashMap<>();
+ private static final Map NAMESPACES = new HashMap<>();
+ private static final Map OBJECTS = new HashMap<>();
+ private static final Map RELATIONS = new HashMap<>();
+ private static final Map W3C_NAMESPACES = new HashMap<>();
+ private static String platform = null;
+
+ public URINamespaces() {
+ platform = PropertiesFileManager.getConfigFileProperty("sesame_rdf_config", "platform");;
+ setContexts();
+ setNamespaces();
+ setW3CNamespaces();
+ setRelations();
+ setObjects();
+ }
+
+ public Map getContexts() {
+ return URINamespaces.CONTEXTS;
+ }
+
+ public String getContextsProperty(String prop) {
+ String propValue = null;
+ if (URINamespaces.CONTEXTS.containsKey(prop)) {
+ propValue = URINamespaces.CONTEXTS.get(prop);
+ }
+ return propValue;
+ }
+
+ public String getObjectsProperty(String prop) {
+ String propValue = null;
+ if (URINamespaces.OBJECTS.containsKey(prop)) {
+ propValue = URINamespaces.OBJECTS.get(prop);
+ }
+ return propValue;
+ }
+
+ public String getNamespaceProperty(String prop) {
+ if (URINamespaces.NAMESPACES.containsKey(prop)) {
+ return URINamespaces.NAMESPACES.get(prop);
+ } else {
+ return null;
+ }
+ }
+
+ public boolean objectsPropertyContainsValue(String value) {
+ return OBJECTS.containsValue(value);
+ }
+
+ public String getRelationsProperty(String prop) {
+ String propValue = null;
+ if (URINamespaces.RELATIONS.containsKey(prop)) {
+ propValue = URINamespaces.RELATIONS.get(prop);
+ }
+ return propValue;
+ }
+
+ public String getW3CNamespacesProp(String prop) {
+ String propValue = null;
+ if (URINamespaces.W3C_NAMESPACES.containsKey(prop)) {
+ propValue = URINamespaces.W3C_NAMESPACES.get(prop);
+ }
+ return propValue;
+ }
+
+ private void setContexts() {
+ if (platform == null) {
+ platform = "";
+ }
+ //px => prefix
+ //c => context
+ //n => namespace
+ //p => phenome
+
+
+
+ //Plateforme et préfixes
+ CONTEXTS.put("pxPhenome", "http://www.phenome-fppn.fr");
+ CONTEXTS.put("pxDublinCore", "http://purl.org/dc/terms");
+ CONTEXTS.put("pxPlatform", CONTEXTS.get("pxPhenome") + "/" + platform);
+ CONTEXTS.put("pxGeoSPARQL", "http://www.opengis.net/ont/geosparql#");
+
+
+ //Context(s)
+ CONTEXTS.put("pVoc2017", CONTEXTS.get("pxPhenome") + "/vocabulary/2017");
+ CONTEXTS.put("documents", CONTEXTS.get("pxPlatform") + "/documents");
+ CONTEXTS.put("agronomicalObjects", CONTEXTS.get("pxPlatform") + "/agronomicalObjects");
+ CONTEXTS.put("variables", CONTEXTS.get("pxPlatform") + "/variables");
+
+
+
+ //Contextes de phenomeApi version serre
+// CONTEXTS.put("pxPhenome", "http://www.phenome-fppn.fr");
+// CONTEXTS.put("pExperiment", "http://www.phenome-fppn.fr/m3p/experiment");
+// CONTEXTS.put("pVocaPlateform", "http://www.phenome-fppn.fr/vocabulary/2015");
+// CONTEXTS.put("annotation", "http://www.mistea.supagro.inra.fr/ontologies/2014/v1/annotation");
+// CONTEXTS.put("annotSemantic", "http://www.mistea.supagro.inra.fr/ontologies/2014/v1/semanticAnnotation");
+// CONTEXTS.put("pEvent", "http://www.phenome-fppn.fr/vocabulary/"+ platform + "/2015/event");
+// CONTEXTS.put("eventRepo", "http://www.phenome-fppn.fr/" + platform + "/event");
+// CONTEXTS.put("annotationRepo", "http://www.phenome-fppn.fr/" + platform + "/annotation");
+// CONTEXTS.put("documents", "http://www.mistea.supagro.inra.fr/ontologies/2014/v1/documents");
+// CONTEXTS.put("documentsRepo", "http://www.phenome-fppn.fr/" + platform + "/document");
+ }
+
+ private void setNamespaces() {
+ NAMESPACES.put("variables", CONTEXTS.get("pxPlatform") + "/id/variables");
+ NAMESPACES.put("traits", CONTEXTS.get("pxPlatform") + "/id/traits");
+ NAMESPACES.put("methods", CONTEXTS.get("pxPlatform") + "/id/methods");
+ NAMESPACES.put("units", CONTEXTS.get("pxPlatform") + "/id/units");
+ }
+
+ private void setW3CNamespaces() {
+
+// W3C_NAMESPACES.put("time", "http://www.w3.org/2006/time");
+ }
+
+ private void setObjects() {
+ //c , concept
+ OBJECTS.put("cDocuments", CONTEXTS.get("pVoc2017") + "#Document");
+ OBJECTS.put("cExperiment", CONTEXTS.get("pVoc2017") + "#Experiment");
+ OBJECTS.put("cPlot", CONTEXTS.get("pVoc2017") + "#Plot");
+ OBJECTS.put("cFields", CONTEXTS.get("pVoc2017") + "#Fields");
+ OBJECTS.put("cCultivatedLand", CONTEXTS.get("pVoc2017") + "#CultivatedLand");
+ OBJECTS.put("cVariety", CONTEXTS.get("pVoc2017") + "#Variety");
+ OBJECTS.put("cGenotype", CONTEXTS.get("pVoc2017") + "#Genotype");
+ OBJECTS.put("cSpecies", CONTEXTS.get("pVoc2017") + "#Species");
+ OBJECTS.put("cVariable", CONTEXTS.get("pVoc2017") + "#Variable");
+ OBJECTS.put("cTrait", CONTEXTS.get("pVoc2017") + "#Trait");
+ OBJECTS.put("cMethod", CONTEXTS.get("pVoc2017") + "#Method");
+ OBJECTS.put("cUnit", CONTEXTS.get("pVoc2017") + "#Unit");
+ }
+
+ private void setRelations() {
+ //r , relation
+ //d , draft
+ //v , validated draft
+
+ RELATIONS.put("rHasDocument", CONTEXTS.get("pVoc2017") + "#hasDocument");
+ RELATIONS.put("rConcern", CONTEXTS.get("pVoc2017") + "#concern");
+ RELATIONS.put("rHasPlot", CONTEXTS.get("pVoc2017") + "#hasPlot");
+ RELATIONS.put("rFromGenotype", CONTEXTS.get("pVoc2017") + "#fromGenotype");
+ RELATIONS.put("rFromVariety", CONTEXTS.get("pVoc2017") + "#fromVariety");
+ RELATIONS.put("rExperimentModalities", CONTEXTS.get("pVoc2017") + "#hasExperimentModalities");
+ RELATIONS.put("rHasRepetition", CONTEXTS.get("pVoc2017") + "#hasRepetition");
+ RELATIONS.put("rHasAlias", CONTEXTS.get("pVoc2017") + "#hasAlias");
+ RELATIONS.put("rStatus", CONTEXTS.get("pVoc2017") + "#status");
+ RELATIONS.put("rHasTrait", CONTEXTS.get("pVoc2017") + "#hasTrait");
+ RELATIONS.put("rHasMethod", CONTEXTS.get("pVoc2017") + "#hasMethod");
+ RELATIONS.put("rHasUnit", CONTEXTS.get("pVoc2017") + "#hasUnit");
+
+ //Relations skos
+ RELATIONS.put("rExactMatch", "http://www.w3.org/2008/05/skos#exactMatch");
+ RELATIONS.put("rCloseMatch", "http://www.w3.org/2008/05/skos#closeMatch");
+ RELATIONS.put("rNarrower", "http://www.w3.org/2008/05/skos#narrower");
+ RELATIONS.put("rBroader", "http://www.w3.org/2008/05/skos#broader");
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/datasource/AbstractSQLDataSource.java b/phis2-ws/src/main/java/phis2ws/service/dao/datasource/AbstractSQLDataSource.java
new file mode 100644
index 000000000..7cd8d0b4e
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/datasource/AbstractSQLDataSource.java
@@ -0,0 +1,39 @@
+//**********************************************************************************************
+// AbstractSQLDataSource.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: Abstract class for SQL datasources
+//***********************************************************************************************
+package phis2ws.service.dao.datasource;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Représente une source de données avec les paramètres communs à toutes les
+ * sources de données SQL
+ *
+ * @author Arnaud CHARLEROY
+ */
+public abstract class AbstractSQLDataSource extends DataSource {
+
+ // Récupération des logs
+ final static Logger logger = LoggerFactory.getLogger(AbstractSQLDataSource.class);
+ // Fichier de configuration
+ protected static String propertyFileName;
+
+ public static String getPropertyFileName() {
+ return propertyFileName;
+ }
+
+ public static void setPropertyFileName(String propertyFileName) {
+ AbstractSQLDataSource.propertyFileName = propertyFileName;
+ }
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/datasource/DataSourceDAOPhisBrapi.java b/phis2-ws/src/main/java/phis2ws/service/dao/datasource/DataSourceDAOPhisBrapi.java
new file mode 100644
index 000000000..c011be248
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/datasource/DataSourceDAOPhisBrapi.java
@@ -0,0 +1,78 @@
+//**********************************************************************************************
+// DataSourceDAOPhisBrapi.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: Datasource for Phis database, create a pool of connexion for this database
+//***********************************************************************************************
+package phis2ws.service.dao.datasource;
+
+import java.sql.Connection;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import static phis2ws.service.PropertiesFileManager.getSQLPoolDataSourceProperties;
+
+/**
+ * Source de données qui gère un ensemble de connexion pour la base de données
+ * relationnelle Postgresql Phis pattern SingletonHolder
+ *
+ * @date 05/2016
+ * @author Arnaud CHARLEROY
+ */
+public abstract class DataSourceDAOPhisBrapi extends AbstractSQLDataSource {
+
+ private DataSourceDAOPhisBrapi() {
+ setPropertyFileName("phis_sql_config");
+ // récupération des propriétés
+ final PoolProperties p = getSQLPoolDataSourceProperties(propertyFileName);
+
+ try {
+ this.setPoolProperties(p); // S'l n'y a aucune connexion le web service propage une exception INTERNAL_SERVER_ERROR
+ } catch (Exception e) {
+ logger.error("Can not access to Phis Database.", e);
+ throw new WebApplicationException(
+ Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Can not access to Phis Database : " + e.getMessage()).build());
+ }
+ }
+
+ /**
+ * ThreadSafe
+ */
+ private static class DataSourceDAOPhisBrapiHolder {
+
+ final private static DataSourceDAOPhisBrapi instance = new DataSourceDAOPhisBrapi() {
+ };
+ }
+
+ /**
+ * Récupère une et unique instance du pool de connexion
+ *
+ * @return DataSourceDAOPhisBrapi
+ */
+ public static DataSourceDAOPhisBrapi getInstance() {
+ return DataSourceDAOPhisBrapiHolder.instance;
+ }
+
+ /**
+ * Récupère une connexion du pool de connexion
+ *
+ * @return Connection
+ */
+ public static Connection getInstanceConnection() {
+ try {
+ return getInstance().getConnection();
+ } catch (Exception e) {
+ logger.error("Can not access to Phis Database.", e);
+ throw new WebApplicationException(
+ Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+ .entity("Can not access to Phis Database : " + e.getMessage())
+ .build());
+ }
+
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAO.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAO.java
new file mode 100644
index 000000000..6052fe11a
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAO.java
@@ -0,0 +1,67 @@
+//**********************************************************************************************
+// DAO.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: A list of reusable functions for all DAO inherit class
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+/**
+ * Représente les fonctions de bases pour tout DAO
+ *
+ * @author Arnaud CHARLEROY
+ * @param
+ */
+public abstract class DAO {
+
+ /**
+ * Méthode de création
+ *
+ * @param obj
+ * @return boolean
+ * @throws java.lang.Exception
+ */
+ public abstract Boolean create(T obj) throws Exception;
+
+ /**
+ * Méthode pour effacer
+ *
+ * @param obj
+ * @return boolean
+ * @throws java.lang.Exception
+ */
+ public abstract boolean delete(T obj) throws Exception;
+
+ /**
+ * Méthode de mise à jour
+ *
+ * @param obj
+ * @return boolean
+ * @throws java.lang.Exception
+ */
+ public abstract boolean update(T obj) throws Exception;
+
+ /**
+ * Méthode de recherche des informations
+ *
+ * @param obj
+ * @return T
+ * @throws java.lang.Exception
+ */
+ public abstract T find(T obj) throws Exception;
+
+ /**
+ * Méthode de test d'existence
+ *
+ * @param obj
+ * @return T
+ * @throws java.lang.Exception
+ */
+ public abstract boolean existInDB(T obj) throws Exception;
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOFactory.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOFactory.java
new file mode 100644
index 000000000..66b3a4ae4
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOFactory.java
@@ -0,0 +1,38 @@
+//**********************************************************************************************
+// DAOFactory.java
+//
+// Author(s): Arnaud CHARLEROY, Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@inra.fr, morgane.vidal@inra.fr anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: MArch, 2017
+// Subject: Class which permit to list availableDAO
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+public class DAOFactory {
+ protected DAOFactory() {
+ }
+ /**
+ * Existing Dao for MongoDB
+ * @return MongoDBDAOFactory
+ */
+// public static MongoDBDAOFactory getMongoDBDAOFactory() {
+// return new MongoDBDAOFactory();
+// }
+ /**
+ * Existing Dao for SQL Database
+ * @return SQLDAOFactory
+ */
+// public static SQLDAOFactory getSQLDAOFactory() {
+// return new SQLDAOFactory();
+// }
+ /**
+ * Existing Dao for Sesame
+ * @return SESAMEDAOFactory
+ */
+ public static SESAMEDAOFactory getSESAMEDAOFactory() {
+ return new SESAMEDAOFactory();
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOMongo.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOMongo.java
new file mode 100644
index 000000000..1be99453e
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOMongo.java
@@ -0,0 +1,166 @@
+//**********************************************************************************************
+// DAOMongo.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject:This abstract class is the base of all Dao class for the Mongo DB
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientURI;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.gridfs.GridFS;
+import java.util.ArrayList;
+import org.bson.Document;
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.configuration.DefaultBrapiPaginationValues;
+import phis2ws.service.model.User;
+
+/**
+ * Répresente une définition de la classe DAO permettant de se connecter à la
+ * source de données MongoDB
+ *
+ * @author Arnaud CHARLEROY
+ * @param
+ */
+public abstract class DAOMongo {
+
+ /**
+ * @see service.properties file
+ */
+ private final static MongoClient MONGO_CLIENT = new MongoClient(
+ new MongoClientURI(PropertiesFileManager.getConfigFileProperty("mongodb_nosql_config", "url")));
+ protected GridFS gridFS = new GridFS(MONGO_CLIENT.getDB(PropertiesFileManager.getConfigFileProperty("mongodb_nosql_config", "db")));
+ protected MongoDatabase database;
+ protected MongoCollection collection;
+
+ public User user;
+ protected Integer page;
+ protected Integer pageSize;
+ /**
+ * User ip adress
+ */
+ protected String remoteUserAdress;
+
+ /**
+ * @see service.properties file
+ */
+ public DAOMongo() {
+ this.setDatabase(MONGO_CLIENT.getDatabase(PropertiesFileManager.getConfigFileProperty("mongodb_nosql_config", "db")));
+ }
+
+ public static MongoClient getMongoClient() {
+ return MONGO_CLIENT;
+ }
+
+ public MongoDatabase getDatabase() {
+ return database;
+ }
+
+ public void setDatabase(MongoDatabase database) {
+ this.database = database;
+ }
+
+
+
+ public MongoCollection getCollection() {
+ return collection;
+ }
+
+ public void setCollection(MongoCollection collection) {
+ this.collection = collection;
+ }
+
+ /**
+ * La page de l'api brapi commence à 0
+ *
+ * @return numéro de la page courante
+ */
+ public Integer getPage() {
+ if (page == null || pageSize < 0) {
+ return 0;
+ }
+ return page;
+ }
+
+ /**
+ * La page de l'api brapi pour pouvoir l'utiliser pour la pagination dans
+ * une base de données
+ *
+ * @return numéro de la page courante + 1
+ */
+ public Integer getPageForDBQuery() {
+ if (page == null || pageSize < 0) {
+ return 1;
+ }
+ return page + 1;
+ }
+
+ /**
+ * Définit le paramètre page
+ *
+ * @param page
+ */
+ public void setPage(Integer page) {
+ if (page < 0) {
+ this.page = Integer.valueOf(DefaultBrapiPaginationValues.PAGE);
+ }
+ this.page = page;
+ }
+
+ /**
+ * Retourne le paramètre taille de la page
+ */
+ public Integer getPageSize() {
+ if (pageSize == null || pageSize < 0) {
+ return Integer.valueOf(DefaultBrapiPaginationValues.PAGE_SIZE);
+ }
+ return pageSize;
+ }
+
+ /**
+ *
+ * @return Les logs qui seront utilisés pour la traçabilité
+ */
+ protected String getTraceabilityLogs() {
+ String log = "";
+ if (remoteUserAdress != null) {
+ log += "IP Address " + remoteUserAdress + " - ";
+ }
+ if (user != null) {
+ log += "User : " + user.getEmail() + " - ";
+ }
+
+ return log;
+ }
+
+ /**
+ * Définit le paramètre taille de page
+ *
+ * @param pageSize
+ */
+ public void setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * Fonction qui permet de créer la partie commune d'une requête à la fois
+ * pour lister les éléments et les récupérés
+ *
+ * @return BasicDBObject
+ */
+ abstract protected BasicDBObject prepareSearchQuery();
+
+ /**
+ * Retourne les élements retournés par la requête en prenant en compte la pagination de l'utilisateur
+ * @return
+ */
+ public abstract ArrayList allPaginate();
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOPhisBrapi.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOPhisBrapi.java
new file mode 100644
index 000000000..1e7176d68
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOPhisBrapi.java
@@ -0,0 +1,71 @@
+//**********************************************************************************************
+// DAOPhisBrapi.java
+//
+// Author(s): Arnaud CHARLEROY, Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: august 2016
+// Contact:arnaud.charleroy@inra.fr, morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: January, 2017
+// Subject:This abstract class is the base of all Dao class for the Phis DB
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+import java.util.List;
+import phis2ws.service.dao.datasource.DataSourceDAOPhisBrapi;
+import phis2ws.service.utils.POSTResultsReturn;
+
+/**
+ * Répresente une définition de la classe DAO permettant de se connecter à la
+ * source de données Phis tout en ayant les méthodes déjà définies
+ *
+ * @author Arnaud CHARLEROY
+ * @date 05/2016
+ * @param Classe représentant l'objet
+ * @param Classe représentant l'objet à enregistrer en BD
+ */
+public abstract class DAOPhisBrapi extends SQLDAO {
+
+ public DAOPhisBrapi() {
+ if (dataSource == null) {
+ dataSource = DataSourceDAOPhisBrapi.getInstance();
+ }
+ }
+
+ /**
+ *
+ * @param newObject
+ * @return
+ */
+ public abstract POSTResultsReturn checkAndInsert(D newObject);
+
+ /**
+ * Vérifie les données et les enregistre en base de données
+ * @param newObjects
+ * @return
+ */
+ public abstract POSTResultsReturn checkAndInsertList(List newObjects);
+
+ /**
+ * Vérifie les données et fais les modifications en BD
+ * @param newObjects
+ * @return
+ */
+ public abstract POSTResultsReturn checkAndUpdateList(List newObjects);
+
+ /**
+ *
+ * @return Les logs qui seront utilisés pour la traçabilité
+ */
+ protected String getTraceabilityLogs() {
+ String log = "";
+ if (remoteUserAdress != null) {
+ log += "IP Address " + remoteUserAdress + " - ";
+ }
+ if (user != null) {
+ log += "User : " + user.getEmail() + " - ";
+ }
+
+ return log;
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOSesame.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOSesame.java
new file mode 100644
index 000000000..6dbbd3070
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/DAOSesame.java
@@ -0,0 +1,278 @@
+//**********************************************************************************************
+// DAOSesame.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject:This abstract class is the base of all Dao class for the Sesame TripleStore
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.eclipse.rdf4j.query.MalformedQueryException;
+import org.eclipse.rdf4j.query.QueryEvaluationException;
+import org.eclipse.rdf4j.query.QueryLanguage;
+import org.eclipse.rdf4j.query.TupleQuery;
+import org.eclipse.rdf4j.query.TupleQueryResult;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryException;
+import org.eclipse.rdf4j.repository.http.HTTPRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.authentication.TokenManager;
+import phis2ws.service.configuration.DefaultBrapiPaginationValues;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.model.User;
+import phis2ws.service.utils.sparql.SPARQLQueryBuilder;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.brapi.form.ResponseFormPOST;
+
+/**
+ * Répresente une définition de la classe DAO permettant de se connecter au
+ * TripleStore Sesame
+ *
+ * @author Arnaud CHARLEROY
+ * @param
+ */
+public abstract class DAOSesame {
+
+ final static Logger LOGGER = LoggerFactory.getLogger(DAOSesame.class);
+ protected static final String PROPERTY_FILENAME = "sesame_rdf_config";
+ //SILEX:test
+ // Pour le soucis de pool de connexion plein
+ protected static final String SESAME_SERVER = PropertiesFileManager.getConfigFileProperty(PROPERTY_FILENAME, "sesameServer");
+ protected static final String REPOSITORY_ID = PropertiesFileManager.getConfigFileProperty(PROPERTY_FILENAME, "repositoryID");
+ //\SILEX:test
+
+ protected static Repository rep;
+ private RepositoryConnection connection;
+
+ protected static String resourceType;
+
+ public User user;
+ protected Integer page;
+ protected Integer pageSize;
+ /**
+ * User ip adress
+ */
+ public String remoteUserAdress;
+
+ public DAOSesame() {
+ try {
+ String sesameServer = PropertiesFileManager.getConfigFileProperty(PROPERTY_FILENAME, "sesameServer");
+ String repositoryID = PropertiesFileManager.getConfigFileProperty(PROPERTY_FILENAME, "repositoryID");
+ rep = new HTTPRepository(sesameServer, repositoryID); //Stockage triplestore Sesame
+ rep.initialize();
+ setConnection(rep.getConnection());
+ } catch (Exception e) {
+ ResponseFormPOST postForm = new ResponseFormPOST(new Status("Can't connect to triplestore", StatusCodeMsg.ERR, e.getMessage()));
+ throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(postForm).build());
+ }
+ }
+
+ public DAOSesame(String repositoryID) {
+ try {
+ String sesameServer = PropertiesFileManager.getConfigFileProperty(PROPERTY_FILENAME, "sesameServer");
+ rep = new HTTPRepository(sesameServer, repositoryID); //Stockage triplestore Sesame
+ rep.initialize();
+ setConnection(rep.getConnection());
+ } catch (Exception e) {
+ ResponseFormPOST postForm = new ResponseFormPOST(new Status("Can't connect to triplestore", StatusCodeMsg.ERR, e.getMessage()));
+ throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(postForm).build());
+ }
+ }
+
+ public RepositoryConnection getConnection() {
+ return connection;
+ }
+
+ public final void setConnection(RepositoryConnection connection) {
+ this.connection = connection;
+ }
+
+ public static Repository getRepository() {
+ return rep;
+ }
+
+ /**
+ * La page de l'api brapi commence à 0
+ *
+ * @return numéro de la page courante
+ */
+ public Integer getPage() {
+ if (page == null || pageSize < 0) {
+ return 0;
+ }
+ return page;
+ }
+
+ /**
+ * La page de l'api brapi pour pouvoir l'utiliser pour la pagination dans
+ * une base de données
+ *
+ * @return numéro de la page courante + 1
+ */
+ public Integer getPageForDBQuery() {
+ if (page == null || pageSize < 0) {
+ return 1;
+ }
+ return page + 1;
+ }
+
+ /**
+ * Définit le paramètre page
+ *
+ * @param page
+ */
+ public void setPage(Integer page) {
+ if (page < 0) {
+ this.page = Integer.valueOf(DefaultBrapiPaginationValues.PAGE);
+ }
+ this.page = page;
+ }
+
+ /**
+ * Retourne le paramètre taille de la page
+ * @return
+ */
+ public Integer getPageSize() {
+ if (pageSize == null || pageSize < 0) {
+ return Integer.valueOf(DefaultBrapiPaginationValues.PAGE_SIZE);
+ }
+ return pageSize;
+ }
+
+ /**
+ * Définit le paramètre taille de page
+ *
+ * @param pageSize
+ */
+ public void setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * Méthode de test d'existence d'un sujet par triplet
+ *
+ * @param subject
+ * @param predicate
+ * @param object
+ * @return boolean
+ */
+ public boolean exist(String subject, String predicate, String object) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
+ boolean exist = false;
+ SPARQLQueryBuilder query = new SPARQLQueryBuilder();
+ query.appendSelect(null);
+ query.appendTriplet(subject, predicate, object, null);
+ query.appendParameters("LIMIT 1");
+ TupleQuery tupleQuery = this.getConnection().prepareTupleQuery(QueryLanguage.SPARQL, query.toString());
+ try (TupleQueryResult result = tupleQuery.evaluate()) {
+ if (result.hasNext()) {
+ exist = true;
+ }
+ }
+// LOGGER.trace(query.toString());
+ return exist;
+ }
+
+ /**
+ *
+ * @param objectURI l'uri de l'objet recherché
+ * @return true si l'objet est dans le triplestore,
+ * false sinon
+ */
+ public boolean existObject(String objectURI) {
+ SPARQLQueryBuilder query = new SPARQLQueryBuilder();
+ query.appendSelect("?p");
+ query.appendTriplet(objectURI, "?p", "?o", null);
+ query.appendParameters("LIMIT 1");
+ TupleQuery tupleQuery = this.getConnection().prepareTupleQuery(QueryLanguage.SPARQL, query.toString());
+ try (TupleQueryResult result = tupleQuery.evaluate()) {
+ if (result.hasNext()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Méthode de récupération d'élement d'existence par triplet
+ *
+ * @param subject
+ * @param predicate
+ * @return
+ * @throws RepositoryException
+ * @throws MalformedQueryException
+ * @throws QueryEvaluationException
+ */
+ public String getValueFromPredicate(String subject, String predicate) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
+ String value = null;
+ if (subject != null || predicate != null) {
+ SPARQLQueryBuilder query = new SPARQLQueryBuilder();
+ query.appendSelect("?x");
+ query.appendTriplet(subject, predicate, "?x", null);
+ query.appendParameters("LIMIT 1");
+ LOGGER.trace(query.toString());
+ TupleQuery tupleQuery = this.getConnection().prepareTupleQuery(QueryLanguage.SPARQL, query.toString());
+ try (TupleQueryResult result = tupleQuery.evaluate()) {
+ if (result.hasNext()) {
+ value = result.next().getBinding("x").getValue().stringValue();
+ }
+ }
+ LOGGER.trace(value);
+ }
+ return value;
+ }
+
+ /**
+ * Fonction qui permet de créer la partie commune d'une requête à la fois
+ * pour lister les éléments et les récupérés
+ *
+ * @return SPARQLQueryBuilder
+ */
+ abstract protected SPARQLQueryBuilder prepareSearchQuery();
+
+ /**
+ * Compte le nombre d'élement retournés par la requête
+ *
+ * @return Integer
+ */
+ public abstract Integer count() throws RepositoryException, MalformedQueryException, QueryEvaluationException;
+
+ /**
+ *
+ * @return Les logs qui seront utilisés pour la traçabilité
+ */
+ protected String getTraceabilityLogs() {
+ String log = "";
+ if (remoteUserAdress != null) {
+ log += "IP Address " + remoteUserAdress + " - ";
+ }
+ if (user != null) {
+ log += "User : " + user.getEmail() + " - ";
+ }
+
+ return log;
+ }
+
+ /**
+ * Définit un objet utilisateur à partir d'un identifiant
+ *
+ * @param id identifiant
+ */
+ public void setUser(String id) {
+// LOGGER.debug(JsonConverter.ConvertToJson(TokenManager.Instance().getSession(id).getUser()));
+ if (TokenManager.Instance().getSession(id).getUser() == null) {
+ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
+ } else {
+ this.user = TokenManager.Instance().getSession(id).getUser();
+ }
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/SESAMEDAOFactory.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/SESAMEDAOFactory.java
new file mode 100644
index 000000000..7b3974e47
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/SESAMEDAOFactory.java
@@ -0,0 +1,20 @@
+//**********************************************************************************************
+// SESAMEDAOFactory.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: October, 2016
+// Subject: List available Dao which are connected to Sesame
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+import phis2ws.service.dao.sesame.DocumentDaoSesame;
+
+public class SESAMEDAOFactory extends DAOFactory {
+ public DocumentDaoSesame getDocumentsDaoSesame() {
+ return new DocumentDaoSesame();
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/manager/SQLDAO.java b/phis2-ws/src/main/java/phis2ws/service/dao/manager/SQLDAO.java
new file mode 100644
index 000000000..34443fcd8
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/manager/SQLDAO.java
@@ -0,0 +1,648 @@
+//**********************************************************************************************
+// SQLDAO.java
+//
+// Author(s): Arnaud CHARLEROY
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@supagro.inra.fr, anne.tireau@supagro.inra.fr, pascal.neveu@supagro.inra.fr
+// Last modification date: October, 2016
+// Subject: List all methods usable for all SQL Database DAO
+//***********************************************************************************************
+package phis2ws.service.dao.manager;
+
+import java.lang.reflect.Field;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.postgis.Geometry;
+import org.postgresql.util.PGobject;
+import phis2ws.service.authentication.TokenManager;
+import phis2ws.service.configuration.DefaultBrapiPaginationValues;
+import phis2ws.service.model.User;
+import phis2ws.service.utils.JsonConverter;
+import phis2ws.service.utils.sql.SQLQueryBuilder;
+
+/**
+ * Répresente les attributs et les methode d'un DAO se connectant à une base de
+ * données relationnelle
+ *
+ * @author Arnaud CHARLEROY
+ * @param
+ * @date 05/2016
+ */
+public abstract class SQLDAO extends DAO {
+
+ private final static Logger logger = LoggerFactory.getLogger(SQLDAO.class);
+ protected final static String DUPLICATE_KEY_ERROR_POSTGRE = "23505";
+
+ /**
+ * user c'est l'objet qui représente l'utilisateur
+ */
+ public User user;
+ protected Integer page;
+ protected Integer pageSize;
+
+ public String remoteUserAdress;
+ /**
+ * Nom de la table du dao (table principale)
+ */
+ protected String table;
+ protected String tableAlias;
+
+ /**
+ * Connexion du DAO pool de con ;)
+ */
+ protected DataSource dataSource;
+
+ /**
+ * pour le batch
+ */
+ protected final int batchSize = 1000;
+
+// protected static Connection connectCommitFalse = null;
+ public DataSource getDataSource() {
+ return dataSource;
+ }
+
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public String getTableAlias() {
+ return tableAlias;
+ }
+
+ public void setTableAlias(String alias) {
+ this.tableAlias = alias;
+ }
+
+ /**
+ * La page de l'api brapi commence à 0
+ *
+ * @return numéro de la page courante
+ */
+ public Integer getPage() {
+ if (page == null || pageSize < 0) {
+ return 0;
+ }
+ return page;
+ }
+
+ /**
+ * La page de l'api brapi pour pouvoir l'utiliser pour la pagination dans
+ * une base de données
+ *
+ * @return numéro de la page courante + 1
+ */
+ public Integer getPageForDBQuery() {
+ if (page == null || pageSize < 0) {
+ return 1;
+ }
+ return page + 1;
+ }
+
+ /**
+ * Définit le paramètre page
+ *
+ * @param page
+ */
+ public void setPage(Integer page) {
+ if (page < 0) {
+ this.page = Integer.valueOf(DefaultBrapiPaginationValues.PAGE);
+ }
+ this.page = page;
+ }
+
+ /**
+ * Retourne le paramètre taille de la page
+ *
+ * @return Integer taille de la page
+ */
+ public Integer getPageSize() {
+ if (pageSize == null || pageSize < 0) {
+ return Integer.valueOf(DefaultBrapiPaginationValues.PAGE_SIZE);
+ }
+ return pageSize;
+ }
+
+ /**
+ * Définit le paramètre taille de page
+ *
+ * @param pageSize
+ */
+ public void setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ /**
+ * Définit un objet utilisateur à partir d'un identifiant
+ *
+ * @param id identifiant
+ */
+ public void setUser(String id) {
+// logger.debug(JsonConverter.ConvertToJson(TokenManager.Instance().getSession(id).getUser()));
+ if (TokenManager.Instance().getSession(id).getUser() == null) {
+ throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
+ } else {
+ this.user = TokenManager.Instance().getSession(id).getUser();
+ }
+ }
+
+ public void setTable(String table) {
+ this.table = table;
+ }
+
+ /**
+ * Pas pratique les ressources (statement et resulset) restent ouvertes
+ * Exécute une requête de recherche à partir d'un DAO qui est en lien vers
+ * une BD relationnelle.
+ *
+ * @author Arnaud CHARLEROY
+ * @param query
+ * @return
+ * @deprecated
+ * @throws SQLException
+ */
+ public ResultSet selectQueryFromDAO(String query) throws SQLException {
+ Connection con = null;
+ Statement stat = null;
+ con = dataSource.getConnection();
+ stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+// System.err.println(query);
+ return stat.executeQuery(query);
+ }
+
+ /**
+ *
+ * Exécute une requête d'ajout de suppresion ou de mise à jour à partir d'un
+ * DAO qui est en lien vers une BD relationnelle.
+ *
+ * @author Arnaud CHARLEROY
+ * @param query
+ * @return
+ * @throws SQLException
+ */
+ public Integer insertOrUpdateOrDeleteQueryFromDAO(String query) throws SQLException {
+ Connection con = dataSource.getConnection();
+ Statement stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ Integer executeUpdate = stat.executeUpdate(query);
+ stat.close();
+ con.close();
+ return executeUpdate;
+ }
+
+ /**
+ * Prepare une requete sql en utilisant une chaine de variables sous forme
+ * variable1,variable2
+ *
+ * @author Samuel Cherimon
+ * @param variables
+ * @param request
+ * @update AC 05/16 Rendre la méthode générique
+ * @param column column pour laquelle les variables seront ajoutées
+ * @return La chaine correspondant a la requete complète
+ *
+ */
+ public static String formatMultipleValueQuery(String variables, String column, String request) {
+ StringTokenizer st = new StringTokenizer(variables, ",");
+ String result = "(";
+ result = result + column + " = '" + st.nextToken() + "'";
+// result = result + "mm.\"codeVariable\" = '" + st.nextToken() + "'";
+ while (st.hasMoreTokens()) {
+ result = result + " OR " + column + " = '" + st.nextToken() + "'";
+// result = result + " OR mm.\"codeVariable\" = '" + st.nextToken() + "'";
+ }
+ result = result + ")";
+ return request + " AND " + result;
+ }
+
+ /**
+ * Construit et exécute la requête qui permet de savoir si un objet de type
+ * T est présent dans la base dans une base de données relationnelle à
+ * partir des informations d'un objet T
+ *
+ * @param obj l'objet à chercher
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public boolean existInDB(T obj) throws Exception {
+ String query = new StringBuilder("SELECT * ")
+ .append("FROM ")
+ .append("\"").append(table).append("\"")
+ .append(" WHERE ")
+ .append(makeFindSQLConditionQuery(obj, false)).toString();
+ ResultSet rs = null;
+ PreparedStatement statement = null;
+ Connection con = null;
+
+ logger.debug(query);
+ try {
+ con = dataSource.getConnection();
+ statement = con.prepareStatement(query);
+ rs = statement.executeQuery();
+ if (rs != null) {
+ return rs.next();
+ }
+ return false;
+ } catch (SQLException e) {
+ logger.error("SQL error Exist Request Method ", e);
+ logger.error(query);
+ return false;
+ } finally {
+ try {
+
+ if (rs != null) {
+ rs.close();
+ }
+ if (statement != null) {
+ statement.close();
+ }
+ if (con != null) {
+ con.close();
+ }
+ } catch (SQLException ex) {
+ logger.error(ex.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Construit et exécute la requête qui permet de trouver un objet de type T
+ * dans une base de données relationnelle à partir des informations d'un
+ * objet T, Cette fonction retourne un objet de type T
+ *
+ * @param obj l'objet à chercher
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public T find(T obj) throws Exception {
+ StringBuilder strSQLBuilder = new StringBuilder();
+ // Requete SELECT préparée
+ strSQLBuilder.append("SELECT * ")
+ .append("FROM ")
+ .append("\"").append(table).append("\"")
+ .append(" WHERE ")
+ .append(makeFindSQLConditionQuery(obj, false));
+ logger.debug(strSQLBuilder.toString());
+ Statement Statement = null;
+ ResultSet rs = null;
+ Connection con = null;
+ Map objectFields = relationFieldsJavaSQLObject();
+ final Field[] attributes = obj.getClass().getDeclaredFields();
+ logger.debug(JsonConverter.ConvertToJson(obj));
+ try {
+ con = dataSource.getConnection();
+ Statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ rs = Statement.executeQuery(strSQLBuilder.toString());
+ if (rs != null && rs.first()) {
+ for (Field field : attributes) {
+ field.setAccessible(true);
+ if (objectFields.containsKey(field.getName())
+ && rs.getObject(objectFields.get(field.getName())) != null ) {
+
+ if (rs.getObject(objectFields.get(field.getName())) instanceof Date) {
+ if (field.getType() == String.class) {
+ LocalDate fromDateFields = LocalDate.fromDateFields((Date) rs.getObject(objectFields.get(field.getName())));
+ field.set(obj, fromDateFields.toString("yyyy-MM-dd"));
+ } else if (field.getType() == DateTime.class) {
+ Timestamp ts = new Timestamp(((Date) rs.getObject(objectFields.get(field.getName()))).getTime());
+ field.set(obj, new DateTime(ts));
+ }
+
+ } else if (rs.getObject(objectFields.get(field.getName())) instanceof Geometry) {
+ if (field.getType() == String.class) {
+ field.set(obj, field.toString());
+ }
+ } else {
+ field.set(obj, rs.getObject(objectFields.get(field.getName()).replaceAll("\"", "")).toString());
+ }
+ }
+ }
+ }
+ return obj;
+ } catch (SQLException e) {
+ logger.error("SQL error Exist Request ", e);
+ logger.error(strSQLBuilder.toString());
+// e.printStackTrace();
+ return null;
+ } finally {
+// logger.debug(strSQLBuilder.toString());
+ if (Statement != null) {
+ try {
+ Statement.close();
+ } catch (SQLException ex) {
+ logger.error(ex.getMessage());
+ }
+ }
+ if (rs != null) {
+ rs.close();
+ }
+ if (con != null) {
+ con.close();
+ }
+ }
+ }
+
+ /**
+ * Construit et exécute la requête qui permet d'inserér un objet de type T
+ * dans une base de données relationnelle à partir des informations d'un
+ * objet T
+ *
+ * @param obj l'objet à inserér
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public Boolean create(T obj) throws Exception {
+ String query = new StringBuilder("INSERT INTO ")
+ .append("\"").append(table).append("\" ").toString();
+ Connection con = null;
+ PreparedStatement preparedStatement = null;
+ try {
+ con = dataSource.getConnection();
+ preparedStatement = makeCreatePreparedSQLConditionQuery(con, query, obj);
+ preparedStatement.executeUpdate();
+ String log = "";
+ if (remoteUserAdress != null) {
+ log += " IP Adress : " + remoteUserAdress + " - ";
+ }
+ if (user != null) {
+ log += "User : " + user.getEmail() + "-";
+ }
+ logger.trace(log + " query : " + preparedStatement.toString());
+// logger.trace(preparedStatement.toString());
+// logger.debug(preparedStatement.toString());
+ return true;
+ } catch (SQLException e) {
+// System.err.println(e.getMessage());
+ if (e.getSQLState().contains(DUPLICATE_KEY_ERROR_POSTGRE)) {
+ return null;
+ } else {
+ logger.error("SQL error Create Request " + e.getErrorCode() + e.getSQLState(), e);
+ return false;
+ }
+ } finally {
+ if (preparedStatement != null) {
+ preparedStatement.close();
+ }
+ if (con != null) {
+ con.close();
+ }
+
+ }
+
+ }
+
+ /**
+ * HashMap qui décrit les attributs qui correspondent à la clé primaire de
+ * l'objet et leur label dans la BD
+ *
+ * @return Map
+ */
+ public abstract Map pkeySQLFieldLink();
+
+ /**
+ * HashMap qui décrit les attributs qui correspondent à l'objet et leur
+ * label dans la BD
+ *
+ * @return Map
+ */
+ public abstract Map relationFieldsJavaSQLObject();
+
+ @Override
+ public boolean delete(T obj) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public boolean update(T obj) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ /**
+ * Crée automatiquement une requête pour récupérer un élément dans une base
+ * de données à partir de sa clé primaire
+ *
+ * @param obj
+ * @param like
+ * @return String requête SQL
+ */
+ public String makeFindSQLConditionQuery(T obj, boolean like) {
+ final Map pkeyLink = this.pkeySQLFieldLink();
+ StringBuilder strBuilder = new StringBuilder();
+ List attributes = new ArrayList<>();
+ for (Class> c = obj.getClass(); c != null; c = c.getSuperclass()) {
+ attributes.addAll(Arrays.asList(c.getDeclaredFields()));
+ }
+ try {
+ for (Field field : attributes) {
+ field.setAccessible(true);
+ Object fieldObject = field.get(obj);
+ if (pkeyLink.containsKey(field.getName()) && fieldObject != null) {
+ if (strBuilder.length() > 0) {
+ strBuilder.append(" AND ");
+ }
+ String sqlField = "\"" + pkeyLink.get(field.getName()) + "\"";
+ if (fieldObject instanceof DateTime) {
+ if (like) {
+ final DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
+ final String finalDate = fmt.print((DateTime) fieldObject);
+ strBuilder.append(sqlField).append("::text LIKE '").append(finalDate).append("%'");
+ } else {
+ final DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ssZ");
+ final String finalDate = fmt.print((DateTime) fieldObject).substring(0, 22);
+ strBuilder.append(sqlField).append("='").append(finalDate).append("'");
+ }
+ } else if (like) {
+ strBuilder.append(sqlField).append(" LIKE '").append(fieldObject).append("%'");
+ } else {
+ strBuilder.append(sqlField).append("='").append(fieldObject).append("'");
+ }
+ }
+ }
+
+ } catch (SecurityException | IllegalArgumentException | IllegalAccessException ex) {
+ logger.error(ex.getMessage(), ex);
+ return null;
+ }
+ return strBuilder.toString();
+ }
+
+ /**
+ * Crée automatiquement une requête pour insérer un élément dans une base de
+ * données à partir de sa clé primaire
+ *
+ * @param obj l'objet à inserér
+ * @return
+ */
+ public String makeCreateSQLConditionQuery(T obj) {
+ final Map createSQLField = this.relationFieldsJavaSQLObject();
+ StringBuilder attributesBuilder = new StringBuilder();
+ StringBuilder valuesBuilder = new StringBuilder();
+ final Field[] attributes = obj.getClass().getDeclaredFields();
+ try {
+ for (Field field : attributes) {
+ field.setAccessible(true);
+ Object fieldObject = field.get(obj);
+ if (createSQLField.containsKey(field.getName())) {
+ if (attributesBuilder.length() > 0) {
+ attributesBuilder.append(", ");
+ }
+ String sqlField = createSQLField.get(field.getName());
+ attributesBuilder.append(sqlField);
+
+ if (valuesBuilder.length() > 0) {
+ valuesBuilder.append(", ");
+ }
+ if (fieldObject == null) {
+ valuesBuilder.append("NULL");
+ } else if (fieldObject instanceof DateTime) {
+ final DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ssZ");
+ final String finalDate = fmt.print((DateTime) fieldObject).substring(0, 22);
+ valuesBuilder.append("'").append(finalDate).append("'");
+ } else {
+ valuesBuilder.append("'").append(fieldObject).append("'");
+ }
+ }
+ }
+ } catch (SecurityException | IllegalArgumentException | IllegalAccessException ex) {
+ logger.error(ex.getMessage(), ex);
+ return null;
+ }
+ final String createSQLValuesQuery = "(" + attributesBuilder.toString() + ")"
+ + " VALUES (" + valuesBuilder.toString() + ")";
+ return createSQLValuesQuery;
+ }
+
+ /**
+ * Crée automatiquement une requête préparée pour insérer un élément dans
+ * une base de données à partir de sa clé primaire
+ *
+ * @param con
+ * @param query L'endroit de l'insertion
+ * @param obj l'objet à inserér
+ * @return
+ */
+ public PreparedStatement makeCreatePreparedSQLConditionQuery(Connection con, String query, T obj) {
+ PreparedStatement preparedStatement = null;
+ final Map createSQLField = this.relationFieldsJavaSQLObject();
+ StringBuilder attributesBuilder = new StringBuilder();
+ StringBuilder valuesBuilder = new StringBuilder();
+ final Field[] attributes = obj.getClass().getDeclaredFields();
+
+ try {
+ for (Field field : attributes) {
+ field.setAccessible(true);
+ if (createSQLField.containsKey(field.getName())) {
+ if (attributesBuilder.length() > 0) {
+ attributesBuilder.append(", ");
+ }
+ String sqlField = createSQLField.get(field.getName());
+ attributesBuilder.append(sqlField);
+
+ if (valuesBuilder.length() > 0) {
+ valuesBuilder.append(", ");
+ }
+ valuesBuilder.append("?");
+ }
+ }
+ final String createSQLValuesQuery = query + "(" + attributesBuilder.toString() + ")"
+ + " VALUES (" + valuesBuilder.toString() + ")";
+// System.err.println(createSQLValuesQuery);
+
+ con = dataSource.getConnection();
+ preparedStatement = con.prepareStatement(createSQLValuesQuery);
+ int fieldCount = 1;
+ for (Field field : attributes) {
+ field.setAccessible(true);
+ Object fieldObject = field.get(obj);
+ if (createSQLField.containsKey(field.getName())) {
+ if (fieldObject == null) {
+ preparedStatement.setObject(fieldCount, null);
+ } else if (fieldObject instanceof DateTime) {
+ preparedStatement.setTimestamp(fieldCount, new Timestamp(((DateTime) fieldObject).getMillis()));
+ } else {
+ preparedStatement.setObject(fieldCount, fieldObject);
+ }
+ fieldCount++;
+ }
+
+ }
+ } catch (SecurityException | IllegalArgumentException | IllegalAccessException ex) {
+ logger.error(ex.getMessage(), ex);
+ } catch (SQLException ex) {
+ java.util.logging.Logger.getLogger(SQLDAO.class.getName()).log(Level.SEVERE, null, ex);
+ }
+// logger.debug(preparedStatement.toString());
+ return preparedStatement;
+ }
+
+ public abstract T findByFields(Map Attr, String table);
+
+ public abstract T single(int id);
+
+ public abstract ArrayList all();
+
+ /**
+ * Transforme un objet ResulSet en objet défini T
+ *
+ * @param result Données retournées par la BD
+ * @return un objet de type défini T
+ * @throws SQLException
+ */
+ public abstract T get(ResultSet result) throws SQLException;
+
+ /**
+ * Retourne les élements retournés par la requête en prenant en compte la
+ * pagination de l'utilisateur
+ *
+ * @return
+ */
+ public abstract ArrayList allPaginate();
+
+ /**
+ * Compte le nombre d'élement retournés par la requête
+ *
+ * @return Integer
+ */
+ public abstract Integer count();
+
+ /**
+ * Compare deux objet du type T
+ *
+ * @param fromDB Premier objet à comparer
+ * @param object Deuxième objet à comparer
+ * @return un objet avec les informations des deux objets
+ */
+ protected abstract T compareAndMergeObjects(T fromDB, T object);
+
+ /**
+ * Fonction qui permet de créer la partie commune d'une requête à la fois
+ * pour lister les éléments et les récupérés
+ *
+ * @return SQLQueryBuilder
+ */
+ protected abstract SQLQueryBuilder prepareSearchQuery();
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/mongo/DocumentDaoMongo.java b/phis2-ws/src/main/java/phis2ws/service/dao/mongo/DocumentDaoMongo.java
new file mode 100644
index 000000000..fc6b85de6
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/mongo/DocumentDaoMongo.java
@@ -0,0 +1,100 @@
+//**********************************************************************************************
+// DocumentDaoMongo.java
+//
+// Author(s): Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: June 2017
+// Contact: morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: June, 2017
+// Subject: A Dao specific to documents insert into mongodb
+//***********************************************************************************************
+package phis2ws.service.dao.mongo;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.gridfs.GridFSDBFile;
+import com.mongodb.gridfs.GridFSInputFile;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.commons.io.IOUtils;
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.dao.manager.DAOMongo;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.utils.POSTResultsReturn;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.model.phis.Document;
+
+public class DocumentDaoMongo extends DAOMongo {
+
+ @Override
+ protected BasicDBObject prepareSearchQuery() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public ArrayList allPaginate() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ /**
+ *
+ * @param filePath le chemin du document à enregistrer en mongo
+ * @param fileUri l'uri du fichier, à mettre dans les métadonnées du document dans mongo
+ * @return POSTResultsReturn
+ */
+ public POSTResultsReturn insertFile(String filePath, String fileUri) {
+ POSTResultsReturn result = null;
+ List insertStatusList = new ArrayList<>();
+ try {
+ File file = new File(filePath);
+
+ GridFSInputFile in = gridFS.createFile(file);
+ in.put("uri", fileUri);
+ in.save();
+ result = new POSTResultsReturn(true, true, true);
+ insertStatusList.add(new Status("File saved", StatusCodeMsg.INFO, "File saved in mongodb"));
+ result.statusList = insertStatusList;
+ file.delete();
+ } catch (IOException ex) {
+ result = new POSTResultsReturn(false, false, false);
+ insertStatusList.add(new Status("File exception", StatusCodeMsg.ERR, "Error while loading the file"));
+ result.statusList = insertStatusList;
+ Logger.getLogger(DocumentDaoMongo.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param documentURI l'URI du document à récupérer dans mongo
+ * @return null si le document n'est pas dans la base,
+ * le document sinon
+ */
+ public File getDocument(String documentURI) {
+ GridFSDBFile out = (GridFSDBFile) gridFS.findOne(new BasicDBObject("uri", documentURI));
+ InputStream is = out.getInputStream();
+
+ File file = new File(PropertiesFileManager.getConfigFileProperty("service", "uploadFileServerDirectory") + out.get("filename"));
+
+ try {
+ OutputStream outputStream = new FileOutputStream(file);
+ IOUtils.copy(is, outputStream);
+ } catch (FileNotFoundException ex) {
+ Logger.getLogger(DocumentDaoMongo.class.getName()).log(Level.SEVERE, null, ex);
+ return null;
+ } catch (IOException ex) {
+ Logger.getLogger(DocumentDaoMongo.class.getName()).log(Level.SEVERE, null, ex);
+ return null;
+ }
+
+ return file;
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/mongo/PhenotypeDaoMongo.java b/phis2-ws/src/main/java/phis2ws/service/dao/mongo/PhenotypeDaoMongo.java
new file mode 100644
index 000000000..8dbab2f9e
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/mongo/PhenotypeDaoMongo.java
@@ -0,0 +1,277 @@
+//**********************************************************************************************
+// PhenotypeDaoMongo.java
+//
+// Author(s): Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: September 2017
+// Contact: morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: September, 14 2017
+// Subject: A specific Dao to retrieve data on phenotypes.
+//***********************************************************************************************
+package phis2ws.service.dao.mongo;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.BasicDBObjectBuilder;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Response;
+import org.bson.Document;
+import org.eclipse.rdf4j.repository.sparql.query.SPARQLBooleanQuery;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.PropertiesFileManager;
+import phis2ws.service.dao.manager.DAOMongo;
+import phis2ws.service.dao.phis.AgronomicalObjectDao;
+import phis2ws.service.dao.sesame.AgronomicalObjectDaoSesame;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.resources.dto.PhenotypeDTO;
+import phis2ws.service.utils.POSTResultsReturn;
+import phis2ws.service.utils.ResourcesUtils;
+import phis2ws.service.utils.sparql.SPARQLQueryBuilder;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.model.phis.AgronomicalObject;
+import phis2ws.service.view.model.phis.Data;
+import phis2ws.service.view.model.phis.Phenotype;
+
+public class PhenotypeDaoMongo extends DAOMongo {
+
+ final static Logger LOGGER = LoggerFactory.getLogger(PhenotypeDaoMongo.class);
+
+ private final MongoCollection provenanceCollection = database.getCollection(PropertiesFileManager.getConfigFileProperty("mongodb_nosql_config", "provenance"));
+ private final MongoCollection dataCollection = database.getCollection(PropertiesFileManager.getConfigFileProperty("mongodb_nosql_config", "data"));
+
+ public String experiment;
+ public String variable;
+ public ArrayList agronomicalObjects = new ArrayList<>();
+ public String startDate;
+ public String endDate;
+
+ public PhenotypeDaoMongo() {
+ super();
+ }
+
+ @Override
+ protected BasicDBObject prepareSearchQuery() {
+ BasicDBObject query = new BasicDBObject();
+
+ if (variable != null) {
+ query.append("variable", variable);
+ }
+
+ if (startDate != null && endDate != null) {
+ try {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Date start = df.parse(startDate);
+ Date end = df.parse(endDate);
+
+ query.append("date", BasicDBObjectBuilder.start("$gte", start).add("$lte", end).get());
+
+ } catch (ParseException ex) {
+ java.util.logging.Logger.getLogger(PhenotypeDaoMongo.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+
+ if (agronomicalObjects != null && !agronomicalObjects.isEmpty()) {
+ if (agronomicalObjects.size() > 1) {
+ BasicDBList or = new BasicDBList();
+ for (String agronomicalObject : agronomicalObjects) {
+ BasicDBObject clause = new BasicDBObject("agronomicalObject", agronomicalObject);
+ or.add(clause);
+ }
+ query.append("$or", or);
+ } else {
+ query.append("agronomicalObject", agronomicalObjects.get(0));
+ }
+ }
+
+ return query;
+ }
+
+ /**
+ * @action récupère la liste des objets agronomiques de l'expérimentation pour
+ * les ajouter à la liste des objets agronomiques recherchés.
+ * @param experiment
+ */
+ private void updateAgronomicalObjectsWithExperimentsAgronomicalObjects() {
+ AgronomicalObjectDaoSesame agronomicalObjectDaoSesame = new AgronomicalObjectDaoSesame();
+ agronomicalObjectDaoSesame.experiment = experiment;
+
+ ArrayList agronomicalObjects = agronomicalObjectDaoSesame.allPaginate();
+
+ for (AgronomicalObject agronomicalObject : agronomicalObjects) {
+ this.agronomicalObjects.add(agronomicalObject.getUri());
+ }
+ }
+
+ /**
+ *
+ * @return liste de phénotypes, résultats de la recherche, vide si pas de résultats
+ */
+ @Override
+ public ArrayList allPaginate() {
+ //Si on a une expérimentation, il faut récupérer la liste des objets agronomiques
+ //pour la requête mongo
+ if (experiment != null) {
+ updateAgronomicalObjectsWithExperimentsAgronomicalObjects();
+ }
+
+ BasicDBObject query = prepareSearchQuery();
+
+ LOGGER.trace(getTraceabilityLogs() + " query : " + query.toString());
+ FindIterable phenotypesMongo = dataCollection.find(query);
+
+ ArrayList phenotypes = new ArrayList<>();
+ Phenotype phenotype = new Phenotype();
+ phenotype.setExperiment(experiment);
+ phenotype.setVariableURI(variable);
+
+ //SILEX:todo
+ //récupérer les valeurs en fonction de la pagination...
+ //il faut faire cette pagination sur les objets agronomiques..
+ //en discuter avec Anne ?
+ //pour l'instant, j'ai enlevé la pagination
+ //\SILEX:todo
+
+ try (MongoCursor phenotypesCursor = phenotypesMongo.iterator()) {
+ while (phenotypesCursor.hasNext()) {
+ Document phenotypeDocument = phenotypesCursor.next();
+
+ Data data = new Data();
+ data.setAgronomicalObject(phenotypeDocument.getString("agronomicalObject"));
+ data.setDate(new SimpleDateFormat("yyyy-MM-dd").format(phenotypeDocument.getDate("date"))); // TODO: changer le format de la date pour le retour
+ data.setValue(phenotypeDocument.getString("value"));
+ data.setVariable(phenotypeDocument.getString("variable"));
+
+ phenotype.addData(data);
+ }
+ }
+ phenotypes.add(phenotype);
+
+ return phenotypes;
+ }
+
+ private boolean isElementValid(PhenotypeDTO phenotypeDTO) {
+ Map phenotypeOk = phenotypeDTO.isOk();
+ return (boolean) phenotypeOk.get("state");
+ }
+
+ //SILEX:todo
+ //Faire une fonction "check" commune entre l'insert et le update
+ //\SILEX:todo
+ private POSTResultsReturn checkAndInsertPhenotypesList(ArrayList phenotypesDTO) throws Exception {
+ List insertStatusList = new ArrayList<>();
+ POSTResultsReturn result = null;
+
+ ArrayList phenotypes = new ArrayList<>();
+ boolean dataState = true;
+
+
+ for (PhenotypeDTO phenotypeDTO : phenotypesDTO) {
+ if (isElementValid(phenotypeDTO)) {
+ for (Data data : phenotypeDTO.getData()) {
+ AgronomicalObjectDao agronomicalObjectDao = new AgronomicalObjectDao();
+ if (!agronomicalObjectDao.existInDB(new AgronomicalObject(data.getAgronomicalObject()))) {
+ dataState = false;
+ insertStatusList.add(new Status("Data error", StatusCodeMsg.ERR, "Unknown Agronomical Object URI : " + data.getAgronomicalObject()));
+ }
+ }
+
+ Phenotype phenotype = phenotypeDTO.createObjectFromDTO();
+ phenotypes.add(phenotype);
+
+ } else {
+ dataState = false;
+ insertStatusList.add(new Status("Data error", StatusCodeMsg.ERR, "Fields are missing in JSON Data"));
+ }
+ }
+
+ if (dataState) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ //SILEX:todo
+ //FAIRE UN TRUC EQUIVALENT AUX TRANSACTIONS
+ //On doit faire l'insertion dans mongoDb
+ for (Phenotype phenotype : phenotypes) {
+ //1. Insertion de la provenance
+ Document provenance = new Document();
+ Date creationDate = df.parse(phenotype.getProvenance().getCreationDate());
+
+ provenance.append("creationDate", creationDate);
+ provenance.append("wasGeneratedBy", phenotype.getProvenance().getWasGeneratedBy().getWasGeneratedBy());
+ provenance.append("wasGeneratedByDescription", phenotype.getProvenance().getWasGeneratedBy().getWasGeneratedByDescription());
+ provenance.append("documents", phenotype.getProvenance().getDocumentsUris());
+ provenance.append("uri", phenotype.getProvenance().getUri());
+
+ LOGGER.trace("MongoDB insert : " + provenance.toJson());
+
+ provenanceCollection.insertOne(provenance);
+
+ ArrayList dataToInsert = new ArrayList<>();
+ //2. Insertion des data
+ for (Data data : phenotype.getData()) {
+ Document d = new Document();
+ Date date = df.parse(data.getDate());
+
+ d.append("date", date);
+ d.append("variable", phenotype.getVariableURI());
+ d.append("value", data.getValue());
+ d.append("agronomicalObject", data.getAgronomicalObject());
+ //SILEX:todo
+ //Regarder DBRef (https://docs.mongodb.com/manual/reference/database-references/#dbref-explanation)
+ d.append("provenance", provenance.get("_id"));
+ //\SILEX:todo
+
+ LOGGER.trace("MongoDB insert : " + d.toJson());
+
+ dataToInsert.add(d);
+ }
+
+ dataCollection.insertMany(dataToInsert);
+ }
+
+ insertStatusList.add(new Status("Resource created", StatusCodeMsg.INFO, "phenotypes inserted"));;
+ result = new POSTResultsReturn(dataState);
+ result.setHttpStatus(Response.Status.CREATED);
+ result.statusList = insertStatusList;
+ //\SILEX:todo
+ } else {
+ result = new POSTResultsReturn(dataState);
+ result.setHttpStatus(Response.Status.BAD_REQUEST);
+ result.statusList = insertStatusList;
+ }
+
+ return result;
+ }
+
+ /**
+ * @action enregistre les données dans MongoDB
+ * @param phenotypesDTO liste de phénotypes à enregistrer en BD
+ * @return le résultat de l'insertion
+ */
+ public POSTResultsReturn checkAndInsert(ArrayList phenotypesDTO) {
+ POSTResultsReturn postResult;
+
+ try {
+ postResult = this.checkAndInsertPhenotypesList(phenotypesDTO);
+ } catch (Exception ex) {
+ LOGGER.error(ex.getMessage(), ex);
+ postResult = new POSTResultsReturn(false, Response.Status.INTERNAL_SERVER_ERROR, ex.toString());
+ }
+
+ return postResult;
+ }
+
+//TODO
+
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/phis/AgronomicalObjectDao.java b/phis2-ws/src/main/java/phis2ws/service/dao/phis/AgronomicalObjectDao.java
new file mode 100644
index 000000000..b1ac0907f
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/phis/AgronomicalObjectDao.java
@@ -0,0 +1,329 @@
+//**********************************************************************************************
+// AgronomicalObjectDao.java
+//
+// Author(s): Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2017
+// Creation date: July 2017
+// Contact: morgane.vidal@inra.fr, anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: August 28, 2017
+// Subject: A DAO specific to retrieve agronomical object data
+//***********************************************************************************************
+package phis2ws.service.dao.phis;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import javax.ws.rs.core.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.dao.manager.DAOPhisBrapi;
+import phis2ws.service.documentation.StatusCodeMsg;
+import phis2ws.service.resources.dto.AgronomicalObjectDTO;
+import phis2ws.service.utils.POSTResultsReturn;
+import phis2ws.service.utils.sql.SQLQueryBuilder;
+import phis2ws.service.view.brapi.Status;
+import phis2ws.service.view.model.phis.AgronomicalObject;
+
+public class AgronomicalObjectDao extends DAOPhisBrapi {
+
+ final static Logger LOGGER = LoggerFactory.getLogger(AgronomicalObjectDao.class);
+
+ public String uri;
+ public String typeAgronomicalObject;
+ public String geometry;
+ public String namedGraph;
+
+ public AgronomicalObjectDao() {
+ super();
+ setTable("agronomical_object");
+ setTableAlias("ao");
+ }
+
+ @Override
+ public POSTResultsReturn checkAndInsert(AgronomicalObjectDTO newObject) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ private boolean isElementValid(AgronomicalObjectDTO agronomicalObjectDTO) {
+ Map agronomicalObjectOk = agronomicalObjectDTO.isOk();
+ return (boolean) agronomicalObjectOk.get("state");
+ }
+
+ private POSTResultsReturn checkAndInsertAgronomicalObjectsList(List newAgronomicalObjectsDTO, List newAgronomicalObjects) throws Exception {
+ //init result returned maps
+ List insertStatusList = new ArrayList<>();
+ boolean dataState = true;
+ boolean resultState = true;
+ boolean insertionState = true;
+ POSTResultsReturn results = null;
+
+ for (AgronomicalObjectDTO agronomicalObjectDTO : newAgronomicalObjectsDTO) {
+ if (!isElementValid(agronomicalObjectDTO)) {
+ dataState = false;
+ insertStatusList.add(new Status("Data error", StatusCodeMsg.ERR, "Fields are missing in JSON Data"));
+ }
+ }
+
+ if (dataState) {
+ PreparedStatement insertPreparedStatement = null;
+
+ final String insertGab = "INSERT INTO \"agronomical_object\" (\"uri\", \"type\", \"geometry\", \"named_graph\") "
+ + "VALUES (?, ?, ST_GeomFromText(?, 4326), ?)";
+ Connection connection = null;
+ int inserted = 0;
+ int exists = 0;
+
+ try {
+ //batch
+ boolean insertionLeft = true;
+ int count = 0;
+
+ //connexion + préparation de la transaction
+ connection = dataSource.getConnection();
+ connection.setAutoCommit(false);
+
+ insertPreparedStatement = connection.prepareStatement(insertGab);
+
+ for (AgronomicalObject agronomicalObject : newAgronomicalObjects) {
+ if (!existInDB(agronomicalObject)) {
+ insertionLeft = true;
+ insertPreparedStatement.setString(1, agronomicalObject.getUri());
+ insertPreparedStatement.setString(2, agronomicalObject.getTypeAgronomicalObject());
+ insertPreparedStatement.setString(3, agronomicalObject.getGeometry());
+ insertPreparedStatement.setString(4, agronomicalObject.getUriExperiment());
+
+ LOGGER.trace(getTraceabilityLogs() + " quert : " + insertPreparedStatement.toString());
+
+ insertPreparedStatement.execute();
+
+ inserted++;
+ } else {
+ exists++;
+ }
+
+ //Insertion par batch
+ if (++count % batchSize == 0) {
+ insertPreparedStatement.executeBatch();
+ insertionLeft = false;
+ }
+ }
+
+ if (insertionLeft) {
+ insertPreparedStatement.executeBatch();
+ }
+
+ connection.commit();
+////////////////////
+//ATTENTION, vérifications à re regarder et re vérifier
+//////////////////
+ //Si data insérées et existantes
+ if (exists > 0 && inserted > 0) {
+ results = new POSTResultsReturn(resultState, insertionState, dataState);
+ insertStatusList.add(new Status("Already existing data", StatusCodeMsg.INFO, "All agronomical objects already exist"));
+ results.setHttpStatus(Response.Status.OK);
+ results.statusList = insertStatusList;
+ } else {
+ if (exists > 0) { //Si données existantes et aucunes insérées
+ insertStatusList.add(new Status ("Already existing data", StatusCodeMsg.INFO, String.valueOf(exists) + " agronomical objects already exists"));
+ } else { //Si données qui n'existent pas et donc sont insérées
+ insertStatusList.add(new Status("Data inserted", StatusCodeMsg.INFO, String.valueOf(inserted) + " agronomical objects inserted"));
+ }
+ }
+ results = new POSTResultsReturn(resultState, insertionState, dataState);
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+
+ //Rollback
+ if (connection != null) {
+ connection.rollback();
+ }
+
+ results = new POSTResultsReturn(false, insertionState, dataState);
+ insertStatusList.add(new Status("Error", StatusCodeMsg.ERRPG, e.getMessage()));
+ if (e.getNextException() != null) {
+ insertStatusList.add(new Status("Error", StatusCodeMsg.ERRPG, e.getNextException().getMessage()));
+ insertStatusList.add(new Status("Error", StatusCodeMsg.ERR, "Duplicated project in json or in database"));
+ }
+ results.statusList = insertStatusList;
+ } finally {
+ if (insertPreparedStatement != null) {
+ insertPreparedStatement.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ } else {
+ results = new POSTResultsReturn(resultState, insertionState, dataState);
+ results.statusList = insertStatusList;
+ }
+
+ return results;
+ }
+
+ public POSTResultsReturn checkAndInsertListAO(List newObjects, List newObjectsDTO) {
+ POSTResultsReturn postResult;
+ try {
+ postResult = this.checkAndInsertAgronomicalObjectsList(newObjectsDTO, newObjects);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ postResult = new POSTResultsReturn(false, Response.Status.INTERNAL_SERVER_ERROR, e.toString());
+ }
+
+ return postResult;
+ }
+
+ @Override
+ public POSTResultsReturn checkAndUpdateList(List newObjects) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Map pkeySQLFieldLink() {
+ Map pkeySQLFieldLink = new HashMap<>();
+ pkeySQLFieldLink.put("uri", "uri");
+ return pkeySQLFieldLink;
+ }
+
+ @Override
+ public Map relationFieldsJavaSQLObject() {
+ Map createSQLFields = new HashMap<>();
+ createSQLFields.put("uri", "uri");
+ createSQLFields.put("typeAgronomicalObject", "type");
+ createSQLFields.put("geometry", "geometry");
+ createSQLFields.put("namedGraph", "named_graph");
+
+ return createSQLFields;
+ }
+
+ @Override
+ public AgronomicalObject findByFields(Map Attr, String table) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public AgronomicalObject single(int id) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public ArrayList all() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public AgronomicalObject get(ResultSet result) throws SQLException {
+ AgronomicalObject agronomicalObject = new AgronomicalObject();
+ agronomicalObject.setUri(result.getString("uri"));
+ agronomicalObject.setGeometry(result.getString("geometry"));
+ agronomicalObject.setTypeAgronomicalObject(result.getString("type"));
+ agronomicalObject.setUriExperiment(result.getString("named_graph"));
+
+ return agronomicalObject;
+ }
+
+ @Override
+ public ArrayList allPaginate() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Integer count() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ protected AgronomicalObject compareAndMergeObjects(AgronomicalObject fromDB, AgronomicalObject object) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ protected SQLQueryBuilder prepareSearchQuery() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ /**
+ *
+ * @param agronomicalObjectsURIs la liste des uris pour lesquelles on veut la géométrie
+ * @return la géométrie associée à chaque uri, dans la BD, en geojson
+ * ex : {"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}
+ */
+ public HashMap getGeometries(ArrayList agronomicalObjectsURIs) throws SQLException {
+ Connection connection = null;
+ Statement statement = null;
+ try {
+ connection = dataSource.getConnection();
+ statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+
+ SQLQueryBuilder query = new SQLQueryBuilder();
+ query.appendSelect("ST_AsGeoJSON(ST_Transform(geometry, 4326)), ao.uri");
+ query.appendFrom(table, tableAlias);
+
+ for (String agronomicalObjectURI : agronomicalObjectsURIs) {
+ query.appendORWhereConditionIfNeeded("uri", agronomicalObjectURI, "=", null, tableAlias);
+ }
+
+ LOGGER.trace(getTraceabilityLogs() + " quert : " + query.toString());
+
+ ResultSet queryResult = statement.executeQuery(query.toString());
+ HashMap geometries = new HashMap<>();
+
+ while (queryResult.next()) {
+ geometries.put(queryResult.getString("uri"), queryResult.getString("st_asgeojson"));
+ }
+
+ return geometries;
+ } catch (SQLException ex) {
+ java.util.logging.Logger.getLogger(AgronomicalObjectDao.class.getName()).log(Level.SEVERE, null, ex);
+ return null;
+ } finally {
+ if (statement != null) {
+ statement.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ /**
+ *
+ * @param year
+ * @return String correspondant au nombre d'agronomical objects actuellement
+ * enregistrés sur l'année year
+ */
+ public String getNumberOfAgronomicalObjectForYear(String year) {
+ try {
+ String toReturn;
+ try (Connection connection = dataSource.getConnection();
+ Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT)) {
+ SQLQueryBuilder query = new SQLQueryBuilder();
+ query.appendSelect("count(*)");
+ query.appendFrom(table, tableAlias);
+ query.appendANDWhereConditionIfNeeded("uri", "/" + year + "/", "~*", null, tableAlias);
+ LOGGER.trace(getTraceabilityLogs() + " quert : " + query.toString());
+ ResultSet queryResult = statement.executeQuery(query.toString());
+ queryResult.next();
+ toReturn = queryResult.getString("count");
+ }
+
+ return toReturn;
+ } catch (SQLException ex) {
+ java.util.logging.Logger.getLogger(AgronomicalObjectDao.class.getName()).log(Level.SEVERE, null, ex);
+ return null;
+ }
+ }
+
+ @Override
+ public POSTResultsReturn checkAndInsertList(List newObjects) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+}
diff --git a/phis2-ws/src/main/java/phis2ws/service/dao/phis/DocumentDao.java b/phis2-ws/src/main/java/phis2ws/service/dao/phis/DocumentDao.java
new file mode 100644
index 000000000..d0ba2c042
--- /dev/null
+++ b/phis2-ws/src/main/java/phis2ws/service/dao/phis/DocumentDao.java
@@ -0,0 +1,113 @@
+//**********************************************************************************************
+// DocumentDao.java
+//
+// Author(s): Arnaud CHARLEROY, Morgane VIDAL
+// PHIS-SILEX version 1.0
+// Copyright © - INRA - 2016
+// Creation date: august 2016
+// Contact:arnaud.charleroy@inra.fr, morgane.vidal@inra.fr anne.tireau@inra.fr, pascal.neveu@inra.fr
+// Last modification date: March, 2017
+// Subject: A Dao specific to document insertion into PHIS DB
+//***********************************************************************************************
+package phis2ws.service.dao.phis;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import phis2ws.service.dao.manager.DAOPhisBrapi;
+import phis2ws.service.utils.POSTResultsReturn;
+import phis2ws.service.utils.sql.SQLQueryBuilder;
+import phis2ws.service.view.model.phis.Document;
+
+public class DocumentDao extends DAOPhisBrapi {
+ final static Logger logger = LoggerFactory.getLogger(DocumentDao.class);
+
+ public DocumentDao() {
+ super();
+ setTable("document");
+ }
+
+ @Override
+ public Integer count() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Map pkeySQLFieldLink() {
+ Map pkeySQLFieldLink = new HashMap<>();
+ pkeySQLFieldLink.put("id", "id");
+ pkeySQLFieldLink.put("name", "name");
+ pkeySQLFieldLink.put("uri", "uri");
+ return pkeySQLFieldLink;
+ }
+
+ @Override
+ public Map relationFieldsJavaSQLObject() {
+ Map createSQLFields = new HashMap<>();
+ createSQLFields.put("name", "name");
+ createSQLFields.put("type", "type");
+ createSQLFields.put("date", "date");
+ createSQLFields.put("path", "path");
+ createSQLFields.put("targetTable", "target_table");
+ createSQLFields.put("targetPk", "target_pk");
+ createSQLFields.put("version", "version");
+ createSQLFields.put("uri", "uri");
+
+ return createSQLFields;
+ }
+
+ @Override
+ public Document findByFields(Map Attr, String table) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Document single(int id) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public ArrayList all() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Document get(ResultSet result) throws SQLException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public ArrayList allPaginate() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ protected SQLQueryBuilder prepareSearchQuery() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public POSTResultsReturn checkAndInsert(Object newObject) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public POSTResultsReturn checkAndInsertList(List