Skip to content

Commit

Permalink
feat: simplify questionnaire with references for public-enemy (#226)
Browse files Browse the repository at this point in the history
* feat: Questionnaire service: create getQuestionnaireByID with ref

* feat: move deref implementation to QuestionnaireService

* feat: composition, adapt VariablesService

* feat: add requestParam "references" to GET "api/questionnaire/{id}" with false by default

* test: fix test

* fix: mock issue and log

* docs: add javadoc to explain what "references" means

---------

Co-authored-by: Nicolas Senave <nicolas.senave@gmail.com>
  • Loading branch information
laurentC35 and nsenave committed Mar 5, 2024
1 parent b9aecf7 commit 75a71f2
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 75 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<groupId>fr.insee</groupId>
<artifactId>Pogues-BO</artifactId>
<packaging>jar</packaging>
<version>4.4.1</version>
<version>4.4.2</version>
<name>Pogues-BO</name>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,27 @@ public interface QuestionnairesService {
* @throws Exception
*/
JSONObject getQuestionnaireByID(String id) throws Exception;


/**
* A questionnaire can "contain" other questionnaires. These questionnaires appear as references.
* This method makes it possible to obtain the complete questionnaire, by replacing the references with the complete questionnaires.
* @param id Id of requested object
*
* @return JSON representation of the questionnaire with references
* @throws Exception
*/
JSONObject getQuestionnaireByIDWithReferences(String id) throws Exception;

/**
* A questionnaire can "contain" other questionnaires. These questionnaires appear as references.
* This method makes it possible to obtain the complete questionnaire, by replacing the references with the complete questionnaires.
*
* @param jsonQuestionnaire JSON representation of a questionnaire
* @return JSON representation of the questionnaire with its references
* @throws Exception
*/
JSONObject getQuestionnaireWithReferences(JSONObject jsonQuestionnaire) throws Exception;

/**
*
* @param id Id of requested object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package fr.insee.pogues.persistence.service;

import java.util.List;
import java.util.Map;

import fr.insee.pogues.exception.NullReferenceException;
import fr.insee.pogues.model.Questionnaire;
import fr.insee.pogues.transforms.visualize.PoguesJSONToPoguesJSONDeref;
import fr.insee.pogues.transforms.visualize.PoguesJSONToPoguesJSONDerefImpl;
import fr.insee.pogues.transforms.visualize.composition.QuestionnaireComposition;
import fr.insee.pogues.utils.PoguesDeserializer;
import fr.insee.pogues.utils.PoguesSerializer;
import fr.insee.pogues.utils.json.JSONFunctions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import fr.insee.pogues.persistence.query.EntityNotFoundException;
import fr.insee.pogues.persistence.query.NonUniqueResultException;
import fr.insee.pogues.persistence.query.QuestionnairesServiceQuery;
import fr.insee.pogues.webservice.rest.PoguesException;

/**
* Questionnaire Service to assume the persistence of Pogues UI in JSON
*
Expand All @@ -21,9 +32,11 @@
@Service
public class QuestionnairesServiceImpl implements QuestionnairesService {

static final Logger logger = LogManager.getLogger(QuestionnairesServiceImpl.class);
@Autowired
private QuestionnairesServiceQuery questionnaireServiceQuery;


public List<JSONObject> getQuestionnaireList() throws Exception {
List<JSONObject> questionnaires = questionnaireServiceQuery.getQuestionnaires();
if (questionnaires.isEmpty()) {
Expand Down Expand Up @@ -61,7 +74,22 @@ public JSONObject getQuestionnaireByID(String id) throws Exception {
}
return questionnaire;
}


@Override
public JSONObject getQuestionnaireByIDWithReferences(String id) throws Exception {
JSONObject jsonQuestionnaire = this.getQuestionnaireByID(id);
return getQuestionnaireWithReferences(jsonQuestionnaire);
}

@Override
public JSONObject getQuestionnaireWithReferences(JSONObject jsonQuestionnaire) throws Exception {
Questionnaire questionnaireWithReferences = this.deReference(jsonQuestionnaire);
JSONObject jsonQuestionnaireWithReferences = (JSONObject) new JSONParser().parse(
PoguesSerializer.questionnaireJavaToString(questionnaireWithReferences)
);
return jsonQuestionnaireWithReferences;
}

public JSONObject getJsonLunaticByID(String id) throws Exception {
JSONObject questionnaireLunatic = this.questionnaireServiceQuery.getJsonLunaticByID(id);
if (null == questionnaireLunatic) {
Expand Down Expand Up @@ -109,4 +137,32 @@ public void updateJsonLunatic(String id, JSONObject dataLunatic) throws Exceptio
throw new PoguesException(404, "Not found", e.getMessage());
}
}

public Questionnaire deReference(JSONObject jsonQuestionnaire) throws Exception {

Questionnaire questionnaire = PoguesDeserializer.questionnaireToJavaObject(jsonQuestionnaire);
List<String> references = JSONFunctions.getChildReferencesFromQuestionnaire(jsonQuestionnaire);
deReference(references, questionnaire);
return questionnaire;
}

private void deReference(List<String> references, Questionnaire questionnaire) throws Exception {
for (String reference : references) {
JSONObject referencedJsonQuestionnaire = this.getQuestionnaireByID(reference);
if (referencedJsonQuestionnaire == null) {
throw new NullReferenceException(String.format(
"Null reference behind reference '%s' in questionnaire '%s'.",
reference, questionnaire.getId()));
} else {
Questionnaire referencedQuestionnaire = PoguesDeserializer.questionnaireToJavaObject(referencedJsonQuestionnaire);
// Coherence check
if (! reference.equals(referencedQuestionnaire.getId())) {
logger.warn("Reference '{}' found in questionnaire '{}' mismatch referenced questionnaire's id '{}'",
reference, questionnaire.getId(), referencedQuestionnaire.getId());
}
//
QuestionnaireComposition.insertReference(questionnaire, referencedQuestionnaire);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,18 @@ public class VariablesServiceImpl implements VariablesService {

@Autowired
JdbcTemplate jdbcTemplate;

@Autowired
private QuestionnairesServiceQuery questionnaireServiceQuery;

@Autowired QuestionnairesService questionnairesService;

public VariablesServiceImpl() {}

public VariablesServiceImpl(QuestionnairesServiceQuery questionnairesServiceQuery) {
this.questionnaireServiceQuery = questionnairesServiceQuery;
public VariablesServiceImpl(QuestionnairesService questionnairesService) {
this.questionnairesService = questionnairesService;
}

public JSONArray getVariablesByQuestionnaireForPublicEnemy(String id){
try {
JSONObject questionnaire = questionnaireServiceQuery.getQuestionnaireByID(id);
JSONObject questionnaire = questionnairesService.getQuestionnaireByIDWithReferences(id);
// We test the existence of the questionnaire in repository
if (questionnaire != null) {
JSONObject variables = (JSONObject) questionnaire.get("Variables");
Expand All @@ -61,7 +60,7 @@ public String getVariablesByQuestionnaire(String id){
StreamSource json = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
JSONObject questionnaire = questionnaireServiceQuery.getQuestionnaireByID(id);
JSONObject questionnaire = questionnairesService.getQuestionnaireByID(id);
// We test the existence of the questionnaire in repository
if (questionnaire != null) {
logger.info("Deserializing questionnaire ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,36 +80,9 @@ public Questionnaire transformAsQuestionnaire(String input) throws Exception {
// Parse Pogues json questionnaire
JSONParser parser = new JSONParser();
JSONObject jsonQuestionnaire = (JSONObject) parser.parse(input);
// Get referenced questionnaire identifiers
// TODO: The "childQuestionnaireRef" in the json should be supported by Pogues-Model
List<String> references = JSONFunctions.getChildReferencesFromQuestionnaire(jsonQuestionnaire);
// Deserialize json into questionnaire object
Questionnaire questionnaire = PoguesDeserializer.questionnaireToJavaObject(jsonQuestionnaire);
//
deReference(references, questionnaire);
logger.info("Sequences inserted");
//
return questionnaire;
JSONObject questionnaireWithRef = questionnairesService.getQuestionnaireWithReferences(jsonQuestionnaire);
return PoguesDeserializer.questionnaireToJavaObject(questionnaireWithRef);
}

private void deReference(List<String> references, Questionnaire questionnaire) throws Exception {
for (String reference : references) {
JSONObject referencedJsonQuestionnaire = questionnairesService.getQuestionnaireByID(reference);
if (referencedJsonQuestionnaire == null) {
throw new NullReferenceException(String.format(
"Null reference behind reference '%s' in questionnaire '%s'.",
reference, questionnaire.getId()));
} else {
Questionnaire referencedQuestionnaire = PoguesDeserializer.questionnaireToJavaObject(referencedJsonQuestionnaire);
// Coherence check
if (! reference.equals(referencedQuestionnaire.getId())) {
logger.warn("Reference '{}' found in questionnaire '{}' mismatch referenced questionnaire's id '{}'",
reference, questionnaire.getId(), referencedQuestionnaire.getId());
}
//
QuestionnaireComposition.insertReference(questionnaire, referencedQuestionnaire);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import fr.insee.pogues.config.auth.user.User;
import fr.insee.pogues.persistence.service.QuestionnairesService;
import fr.insee.pogues.persistence.service.VariablesService;
import fr.insee.pogues.transforms.visualize.PoguesJSONToPoguesJSONDeref;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;

import java.util.*;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
Expand All @@ -21,6 +22,7 @@
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -73,6 +75,14 @@ public class PoguesPersistence {
private static final String BAD_REQUEST = "Bad Request";
private static final String MESSAGE_INVALID_IDENTIFIER = "Identifier %s is invalid";

/**
* @param id: the id of questionnaire
* @param references (false by default): this param indicates if you want the complete questionnaire
* A questionnaire may be "contain" other questionnaires. These questionnaires appear as references.
* This end-point makes it possible to obtain the complete questionnaire, by replacing the references with the complete questionnaires.
* @return the json representation of questionnaire (and potentially its references according to references param)
* @throws Exception
*/
@GetMapping("questionnaire/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
Expand All @@ -85,9 +95,12 @@ public class PoguesPersistence {
@ApiResponse(responseCode = "404", description = "Not found")
})
public ResponseEntity<Object> getQuestionnaire(
@PathVariable(value = "id") String id
@PathVariable(value = "id") String id,
@RequestParam(name = "references", defaultValue = "false") Boolean references
) throws Exception {
JSONObject result = questionnaireService.getQuestionnaireByID(id);
JSONObject result = references ?
questionnaireService.getQuestionnaireByIDWithReferences(id) :
questionnaireService.getQuestionnaireByID(id);
return ResponseEntity.status(HttpStatus.OK).body(result);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ void getVariables() throws Exception {
String stringQuestionnaire = Files.readString(Path.of(url.toURI()));
JSONObject jsonQuestionnaire = (JSONObject) new JSONParser().parse(stringQuestionnaire);
// Mock questionnaire service
QuestionnairesServiceQuery questionnairesServiceQuery = Mockito.mock(QuestionnairesServiceQuery.class);
Mockito.when(questionnairesServiceQuery.getQuestionnaireByID("l4i3m6qa")).thenReturn(jsonQuestionnaire);
QuestionnairesService questionnairesService = Mockito.mock(QuestionnairesService.class);
Mockito.when(questionnairesService.getQuestionnaireByID("l4i3m6qa")).thenReturn(jsonQuestionnaire);

// When
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesServiceQuery);
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesService);
String result = variablesService.getVariablesByQuestionnaire("l4i3m6qa");

// Then
Expand All @@ -56,11 +56,11 @@ void getVariablesForPublicEnemy() throws Exception {
String stringQuestionnaire = Files.readString(Path.of(url.toURI()));
JSONObject jsonQuestionnaire = (JSONObject) new JSONParser().parse(stringQuestionnaire);
// Mock questionnaire service
QuestionnairesServiceQuery questionnairesServiceQuery = Mockito.mock(QuestionnairesServiceQuery.class);
Mockito.when(questionnairesServiceQuery.getQuestionnaireByID("l4i3m6qa")).thenReturn(jsonQuestionnaire);
QuestionnairesService questionnairesService = Mockito.mock(QuestionnairesService.class);
Mockito.when(questionnairesService.getQuestionnaireByIDWithReferences("l4i3m6qa")).thenReturn(jsonQuestionnaire);

// When
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesServiceQuery);
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesService);
JSONArray result = variablesService.getVariablesByQuestionnaireForPublicEnemy("l4i3m6qa");

// Then
Expand All @@ -78,11 +78,11 @@ public MockedException() {
@Test
void getVariables_exceptionDuringQuestionnaireQuery_shouldReturnNull() throws Exception {
// Given
QuestionnairesServiceQuery questionnairesServiceQuery = Mockito.mock(QuestionnairesServiceQuery.class);
Mockito.when(questionnairesServiceQuery.getQuestionnaireByID("foo-id")).thenThrow(new MockedException());
QuestionnairesService questionnairesService = Mockito.mock(QuestionnairesService.class);
Mockito.when(questionnairesService.getQuestionnaireByID("foo-id")).thenThrow(new MockedException());

// When
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesServiceQuery);
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesService);
String result = variablesService.getVariablesByQuestionnaire("foo-id");

// Then
Expand All @@ -92,11 +92,11 @@ void getVariables_exceptionDuringQuestionnaireQuery_shouldReturnNull() throws Ex
@Test
void getVariablesForPublicEnemy_exceptionDuringQuestionnaireQuery_shouldReturnNull() throws Exception {
// Given
QuestionnairesServiceQuery questionnairesServiceQuery = Mockito.mock(QuestionnairesServiceQuery.class);
Mockito.when(questionnairesServiceQuery.getQuestionnaireByID("foo-id")).thenThrow(new MockedException());
QuestionnairesService questionnairesService = Mockito.mock(QuestionnairesService.class);
Mockito.when(questionnairesService.getQuestionnaireByID("foo-id")).thenThrow(new MockedException());

// When
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesServiceQuery);
VariablesServiceImpl variablesService = new VariablesServiceImpl(questionnairesService);
JSONArray result = variablesService.getVariablesByQuestionnaireForPublicEnemy("foo-id");

// Then
Expand Down
Loading

0 comments on commit 75a71f2

Please sign in to comment.