From 10b3fab76ba0a394c78d53483d6d1b9ac6829f0d Mon Sep 17 00:00:00 2001 From: winkt0 <238452092+winkt0@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:36:20 +0200 Subject: [PATCH 1/2] 300: (WIP) Preparation: Caching works by annotating database accesses. Introduced annotations in QuestionnaireService, which accesses the questionnaire DAO, and ensured that these methods are the only routes over which the DAO is accessed. Therefore, I replaced all relevant usages of the DAO with calls to the services, which is more in line with Spring Architecture anyway. --- .../mopat/controller/BundleController.java | 15 +--- .../controller/ExportMappingController.java | 43 +++++------ .../mopat/controller/QuestionController.java | 23 +++--- .../controller/QuestionnaireController.java | 68 +++++++----------- .../imi/mopat/controller/ScoreController.java | 71 +++++++++---------- .../mopat/controller/StatisticController.java | 8 +-- .../mopat/controller/SurveyController.java | 27 ++++--- .../helper/controller/BundleService.java | 15 ++-- .../helper/controller/ConditionService.java | 5 +- .../helper/controller/QuestionService.java | 7 +- .../controller/QuestionnaireService.java | 37 +++++++--- .../QuestionnaireVersionGroupService.java | 5 +- 12 files changed, 147 insertions(+), 177 deletions(-) diff --git a/src/main/java/de/imi/mopat/controller/BundleController.java b/src/main/java/de/imi/mopat/controller/BundleController.java index ea31605c..d7f25e3f 100644 --- a/src/main/java/de/imi/mopat/controller/BundleController.java +++ b/src/main/java/de/imi/mopat/controller/BundleController.java @@ -3,18 +3,10 @@ import de.imi.mopat.dao.AnswerDao; import de.imi.mopat.dao.BundleDao; import de.imi.mopat.dao.ConditionDao; -import de.imi.mopat.dao.ExportTemplateDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.ScoreDao; import de.imi.mopat.dao.user.AclClassDao; import de.imi.mopat.dao.user.AclObjectIdentityDao; -import de.imi.mopat.helper.controller.AuthService; -import de.imi.mopat.helper.controller.BundleService; -import de.imi.mopat.helper.controller.LocaleHelper; -import de.imi.mopat.helper.controller.UserService; -import de.imi.mopat.helper.controller.ClinicService; -import de.imi.mopat.helper.model.BundleDTOMapper; -import de.imi.mopat.helper.model.QuestionnaireDTOMapper; +import de.imi.mopat.helper.controller.*; import de.imi.mopat.model.Answer; import de.imi.mopat.model.Bundle; import de.imi.mopat.model.BundleClinic; @@ -26,7 +18,6 @@ import de.imi.mopat.model.conditions.SelectAnswerCondition; import de.imi.mopat.model.conditions.SliderAnswerThresholdCondition; import de.imi.mopat.model.dto.BundleDTO; -import de.imi.mopat.model.dto.BundleQuestionnaireDTO; import de.imi.mopat.model.dto.QuestionnaireDTO; import de.imi.mopat.validator.BundleDTOValidator; @@ -62,7 +53,7 @@ public class BundleController { @Autowired private ScoreDao scoreDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private BundleDTOValidator bundleDTOValidator; @Autowired @@ -188,7 +179,7 @@ public String removeBundle(@RequestParam(value = "id", required = true) final Lo for (BundleQuestionnaire bundleQuestionnaire : bundle.getBundleQuestionnaires()) { Questionnaire questionnaire = bundleQuestionnaire.getQuestionnaire(); questionnaire.removeBundleQuestionnaire(bundleQuestionnaire); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); } // Delete the corresponding conditions diff --git a/src/main/java/de/imi/mopat/controller/ExportMappingController.java b/src/main/java/de/imi/mopat/controller/ExportMappingController.java index 2f3d3a6c..df719e2d 100644 --- a/src/main/java/de/imi/mopat/controller/ExportMappingController.java +++ b/src/main/java/de/imi/mopat/controller/ExportMappingController.java @@ -1,7 +1,5 @@ package de.imi.mopat.controller; -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.parser.DataFormatException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; @@ -13,13 +11,12 @@ import de.imi.mopat.dao.ExportRuleFormatDao; import de.imi.mopat.dao.ExportTemplateDao; import de.imi.mopat.dao.QuestionDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.ScoreDao; import de.imi.mopat.helper.controller.Constants; import de.imi.mopat.helper.controller.FhirVersionHelper; import de.imi.mopat.io.importer.ImportQuestionnaireError; import de.imi.mopat.io.importer.ImportQuestionnaireValidation; -import de.imi.mopat.io.importer.fhir.FhirDstu3Helper; +import de.imi.mopat.helper.controller.QuestionnaireService; import de.imi.mopat.helper.controller.StringUtilities; import de.imi.mopat.io.ExportTemplateImporter; import de.imi.mopat.io.importer.fhir.FhirImporter; @@ -55,15 +52,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; + import jakarta.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; @@ -108,7 +98,7 @@ public class ExportMappingController { @Autowired private ExportTemplateDao exportTemplateDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private ScoreDao scoreDao; @Autowired @@ -143,9 +133,8 @@ public void initListBinder(final WebDataBinder binder) { * object. */ public List getAllMappings(final Long id) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); - List exportTemplates = new ArrayList<>(questionnaire.getExportTemplates()); - return exportTemplates; + Optional questionnaire = questionnaireService.getQuestionnaireById(id); + return new ArrayList<>(questionnaire.get().getExportTemplates()); } /** @@ -170,14 +159,14 @@ public ArrayList getExportTemplateTypeList() { @PreAuthorize("hasRole('ROLE_EDITOR')") public String showMapping(@RequestParam(value = "id", required = true) final Long id, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); - if (questionnaire == null) { + Optional questionnaire = questionnaireService.getQuestionnaireById(id); + if (questionnaire.isEmpty()) { //clear the models attributes that are set in the @ModelAttribute // methods model.addAttribute("exportTemplateTypeList", null); return "redirect:/questionnaire/list"; } - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.get()); model.addAttribute("allMappings", this.getAllMappings(id)); return "mapping/list"; } @@ -195,9 +184,9 @@ public String showMapping(@RequestParam(value = "id", required = true) final Lon @PreAuthorize("hasRole('ROLE_EDITOR')") public String showUploadForm(@RequestParam(value = "id", required = true) final Long id, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); + Optional questionnaire = questionnaireService.getQuestionnaireById(id); model.addAttribute("export", new ExportTemplate()); - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.orElse(null)); return "mapping/uploadtemplate"; } @@ -288,7 +277,7 @@ public String handleUpload( return showUploadForm(questionnaireId, model); } - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); + Questionnaire questionnaire = questionnaireService.getQuestionnaireById(questionnaireId).orElse(null); List exportTemplates = ExportTemplate.createExportTemplates(name, exportTemplateType, file, configurationGroupDao, exportTemplateDao); @@ -311,7 +300,7 @@ public String handleUpload( } File uploadFile = new File(contextPath, uploadFilename); uploadFile.createNewFile(); - + //Do the upload for FHIR resource. if (ExportTemplateType.isExportTemplateTypeAFhirType(exportTemplateType)) { try { @@ -353,7 +342,7 @@ public String handleUpload( } // maybe not necessary - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); model.addAttribute("questionnaire", questionnaire); model.addAttribute("allMappings", this.getAllMappings(questionnaireId)); @@ -398,7 +387,7 @@ public String removeExportTemplate(@RequestParam(value = "id", required = true) } questionnaire.removeExportTemplate(exportTemplate); exportTemplateDao.remove(exportTemplate); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); } return showMapping(questionnaire.getId(), model); @@ -423,7 +412,7 @@ public String assignTemplate(@RequestParam(value = "id", required = true) final // reasons // using the questionnaireDao is a workaround to also get all recently // added questions of the questionnaire - questionnaire = questionnaireDao.getElementById(questionnaire.getId()); + questionnaire = questionnaireService.getQuestionnaireById(questionnaire.getId()).get(); // Sort the scores List scores = new ArrayList<>(); diff --git a/src/main/java/de/imi/mopat/controller/QuestionController.java b/src/main/java/de/imi/mopat/controller/QuestionController.java index eeef571d..76736a37 100644 --- a/src/main/java/de/imi/mopat/controller/QuestionController.java +++ b/src/main/java/de/imi/mopat/controller/QuestionController.java @@ -3,6 +3,7 @@ import de.imi.mopat.dao.*; import de.imi.mopat.helper.controller.Constants; import de.imi.mopat.helper.controller.LocaleHelper; +import de.imi.mopat.helper.controller.QuestionnaireService; import de.imi.mopat.helper.model.QuestionDTOMapper; import de.imi.mopat.helper.controller.StringUtilities; import de.imi.mopat.model.*; @@ -56,7 +57,7 @@ public class QuestionController { @Autowired private SliderAnswerValidator sliderAnswerValidator; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private SliderIconDao sliderIconDao; @@ -135,9 +136,9 @@ public ArrayList getQuestionTypeList() { @PreAuthorize("hasRole('ROLE_EDITOR')") public String showQuestions(@RequestParam(value = "id", required = true) final Long id, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); + Optional questionnaire = questionnaireService.getQuestionnaireById(id); - if (questionnaire == null) { + if (questionnaire.isEmpty()) { //clear the models attributes that are set in the @ModelAttribute // methods model.addAttribute("question", null); @@ -149,7 +150,7 @@ public String showQuestions(@RequestParam(value = "id", required = true) final L // map, which // contains the question texts grouped by the country and languages. Map>> localizedQuestionTextsForQuestion = new HashMap<>(); - for (Question question : questionnaire.getQuestions()) { + for (Question question : questionnaire.get().getQuestions()) { // Get the question texts grouped by country from the current // question SortedMap> groupedLocalizedQuestionTextByCountry = question.getLocalizedQuestionTextGroupedByCountry(); @@ -163,7 +164,7 @@ public String showQuestions(@RequestParam(value = "id", required = true) final L question.setHasScores(scoreDao.hasScore(question)); } model.addAttribute("localizedQuestionTextsForQuestion", localizedQuestionTextsForQuestion); - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.get()); return "question/list"; } @@ -330,8 +331,8 @@ public String editQuestion(@RequestParam final String action, return "question/edit"; } - Questionnaire questionnaire = questionnaireDao.getElementById( - questionDTO.getQuestionnaireId()); + Questionnaire questionnaire = questionnaireService.getQuestionnaireById( + questionDTO.getQuestionnaireId()).orElse(null); Integer minNumberAnswers = questionDTO.getMinNumberAnswers(); Integer maxNumberAnswers = questionDTO.getMaxNumberAnswers(); Map localizedQuestionText = removePTags(questionDTO); @@ -359,7 +360,7 @@ public String editQuestion(@RequestParam final String action, } // Merge in any case, because the questionnaire is already persisted questionDao.merge(question); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); // Since the next step is a redirect to a controller which loads a // new model, @@ -604,7 +605,7 @@ public String removeQuestion(@RequestParam(value = "id", required = true) final deleteFile.delete(); } - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); // Since the next step is a redirect to a controller which loads a // new model, @@ -628,7 +629,7 @@ public String removeQuestion(@RequestParam(value = "id", required = true) final public @ResponseBody String repositionQuestion( @RequestParam(value = "questionIds", required = true) final List questionIds, @RequestParam(value = "questionnaireId", required = true) final Long questionnaireId) { - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); + Questionnaire questionnaire = questionnaireService.getQuestionnaireById(questionnaireId).get(); // Check if any condition trigger is after its target for (int i = 0; i < questionIds.size(); i++) { @@ -661,7 +662,7 @@ public String removeQuestion(@RequestParam(value = "id", required = true) final for (Question question : questionnaire.getQuestions()) { question.setPosition((questionIds.indexOf(question.getId()) + 1)); } - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); return ""; } diff --git a/src/main/java/de/imi/mopat/controller/QuestionnaireController.java b/src/main/java/de/imi/mopat/controller/QuestionnaireController.java index 504fc16e..7ce34a12 100644 --- a/src/main/java/de/imi/mopat/controller/QuestionnaireController.java +++ b/src/main/java/de/imi/mopat/controller/QuestionnaireController.java @@ -1,15 +1,6 @@ package de.imi.mopat.controller; -import de.imi.mopat.dao.AnswerDao; -import de.imi.mopat.dao.BundleDao; -import de.imi.mopat.dao.ConditionDao; -import de.imi.mopat.dao.ConfigurationDao; -import de.imi.mopat.dao.ConfigurationGroupDao; -import de.imi.mopat.dao.ExportTemplateDao; -import de.imi.mopat.dao.OperatorDao; -import de.imi.mopat.dao.QuestionDao; -import de.imi.mopat.dao.QuestionnaireDao; -import de.imi.mopat.dao.ScoreDao; +import de.imi.mopat.dao.*; import de.imi.mopat.helper.controller.AuthService; import de.imi.mopat.helper.controller.FhirVersionHelper; import de.imi.mopat.helper.controller.LocaleHelper; @@ -46,16 +37,7 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.SortedMap; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.parsers.DocumentBuilder; @@ -149,7 +131,7 @@ public class QuestionnaireController { @RequestMapping(value = "/questionnaire/list", method = RequestMethod.GET) @PreAuthorize("hasRole('ROLE_EDITOR')") public String listQuestionnaires(final Model model) { - List allQuestionnaires = questionnaireDao.getAllElements(); + List allQuestionnaires = questionnaireService.getAllQuestionnaires(); // This map contians a questionnaire id as key and a set with all // languages // which are available for all questions in this questionnaire. @@ -250,7 +232,7 @@ public String edit(@RequestParam final String action, Questionnaire questionnaire = questionnaireService.saveOrUpdateQuestionnaire( questionnaireDTO, logo, principalId); Boolean hasQuestionnaireConditions = questionnaireService.hasQuestionnaireConditions( - questionnaireDao.getElementById(questionnaireDTO.getId())); + questionnaireService.getQuestionnaireById(questionnaireDTO.getId()).orElse(null)); redirectAttributes.addFlashAttribute("hasQuestionnaireConditions", hasQuestionnaireConditions); if (action.equals("saveEditButton")) { @@ -272,10 +254,10 @@ private void fillModelForValidationErrors(QuestionnaireDTO questionnaireDTO, Mod boolean isEditableState = true; if (questionnaireDTO.getId() != null) { - Questionnaire existingQuestionnaire = questionnaireDao.getElementById( + Optional existingQuestionnaire = questionnaireService.getQuestionnaireById( questionnaireDTO.getId()); - if (existingQuestionnaire != null) { - questionnaireDTO.setLogo(existingQuestionnaire.getLogo()); + if (existingQuestionnaire.isPresent()) { + questionnaireDTO.setLogo(existingQuestionnaire.get().getLogo()); isEditableState = questionnaireService.editingQuestionnaireAllowed( questionnaireDTO); } @@ -298,11 +280,11 @@ private void fillModelForValidationErrors(QuestionnaireDTO questionnaireDTO, Mod @PreAuthorize("hasRole('ROLE_EDITOR')") public String removeQuestionnaire(@RequestParam(value = "id", required = true) final Long id, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); - if (questionnaire != null) { - if (questionnaire.isDeletable()) { + Optional questionnaire = questionnaireService.getQuestionnaireById(id); + if (questionnaire.isPresent()) { + if (questionnaire.get().isDeletable()) { // Delete the associated conditions - for (Condition condition : conditionDao.getConditionsByTarget(questionnaire)) { + for (Condition condition : conditionDao.getConditionsByTarget(questionnaire.get())) { if (condition instanceof SelectAnswerCondition || condition instanceof SliderAnswerThresholdCondition) { // Refresh the trigger so that multiple conditions of @@ -315,7 +297,7 @@ public String removeQuestionnaire(@RequestParam(value = "id", required = true) f conditionDao.remove(condition); } - for (ExportTemplate exportTemplate : questionnaire.getExportTemplates()) { + for (ExportTemplate exportTemplate : questionnaire.get().getExportTemplates()) { //Remove ExportTemplates manually to prevent integrity clashes with scores exportTemplateDao.remove(exportTemplate); } @@ -323,7 +305,7 @@ public String removeQuestionnaire(@RequestParam(value = "id", required = true) f // Collect all scores in an array list to make sure they will // be removed in correct order List scoresToDelete = new ArrayList<>(); - for (Score scoreToDelete : questionnaire.getScores()) { + for (Score scoreToDelete : questionnaire.get().getScores()) { List dependingScores = scoreToDelete.getDependingScores(); // Sort depending scores by amount of their depending // scores to prevent database errors @@ -351,7 +333,7 @@ public String removeQuestionnaire(@RequestParam(value = "id", required = true) f } // Delete connection to the bundles - for (BundleQuestionnaire bundleQuestionnaire : questionnaire.getBundleQuestionnaires()) { + for (BundleQuestionnaire bundleQuestionnaire : questionnaire.get().getBundleQuestionnaires()) { Bundle bundle = bundleQuestionnaire.getBundle(); bundle.removeBundleQuestionnaire(bundleQuestionnaire); //Update the position of all following bundleQuestionnaires @@ -364,17 +346,17 @@ public String removeQuestionnaire(@RequestParam(value = "id", required = true) f } bundleDao.merge(bundle); } - questionnaire.removeAllBundleQuestionnaires(); + questionnaire.get().removeAllBundleQuestionnaires(); questionnaireVersionGroupService.removeQuestionnaire( - questionnaire.getQuestionnaireVersionGroupId(), questionnaire); - questionnaireDao.remove(questionnaire); + questionnaire.get().getQuestionnaireVersionGroupId(), questionnaire.get()); + questionnaireService.removeQuestionnaire(questionnaire.get()); model.addAttribute("messageSuccess", messageSource.getMessage("questionnaire.error" + ".deleteQuestionnairePossible", - new Object[]{questionnaire.getName()}, LocaleContextHolder.getLocale())); + new Object[]{questionnaire.get().getName()}, LocaleContextHolder.getLocale())); } else { model.addAttribute("messageFail", messageSource.getMessage( "questionnaire.error" + ".deleteQuestionnaireNotPossible", - new Object[]{questionnaire.getName()}, LocaleContextHolder.getLocale())); + new Object[]{questionnaire.get().getName()}, LocaleContextHolder.getLocale())); } } return listQuestionnaires(model); @@ -397,9 +379,9 @@ public ResponseEntity downloadQuestionnaire( @RequestParam(value = "id", required = true) final Long id, @RequestParam(value = "type", required = true) final List types, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); + Optional questionnaire = questionnaireService.getQuestionnaireById(id); - if (questionnaire == null) { + if (questionnaire.isEmpty()) { HttpHeaders headers = new HttpHeaders(); headers.add("Location", "list"); return new ResponseEntity<>(null, headers, HttpStatus.FOUND); @@ -412,16 +394,16 @@ public ResponseEntity downloadQuestionnaire( MetadataExporter exporter = metadataExporterFactory.getMetadataExporter( MetadataFormat.valueOf(type)); - for (Question question : questionnaire.getQuestions()) { + for (Question question : questionnaire.get().getQuestions()) { question.setHasConditionsAsTarget(conditionDao.isConditionTarget(question)); } - byte[] data = exporter.export(questionnaire, messageSource, configurationDao, + byte[] data = exporter.export(questionnaire.get(), messageSource, configurationDao, configurationGroupDao, exportTemplateDao, questionnaireDao, questionDao, scoreDao); // Create a windows-compliant path/filename Path path = Paths.get( - questionnaire.getName().replaceAll("[\\\\/:;*?\"<>|]", "").replaceAll(" ", "_") + questionnaire.get().getName().replaceAll("[\\\\/:;*?\"<>|]", "").replaceAll(" ", "_") + "_" + type + MetadataFormat.valueOf(type).getFileExtension()); paths.add(path); @@ -455,7 +437,7 @@ public ResponseEntity downloadQuestionnaire( ByteArrayResource zipResource = new ByteArrayResource(baos.toByteArray()); String zipName = - questionnaire.getName().replaceAll("[\\\\/:;*?\"<>|]", "").replaceAll(" ", "_") + questionnaire.get().getName().replaceAll("[\\\\/:;*?\"<>|]", "").replaceAll(" ", "_") + "_exports.zip"; return ResponseEntity.ok() diff --git a/src/main/java/de/imi/mopat/controller/ScoreController.java b/src/main/java/de/imi/mopat/controller/ScoreController.java index 6e8fd483..c8f194b0 100644 --- a/src/main/java/de/imi/mopat/controller/ScoreController.java +++ b/src/main/java/de/imi/mopat/controller/ScoreController.java @@ -3,8 +3,8 @@ import de.imi.mopat.dao.ExportTemplateDao; import de.imi.mopat.dao.OperatorDao; import de.imi.mopat.dao.QuestionDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.ScoreDao; +import de.imi.mopat.helper.controller.QuestionnaireService; import de.imi.mopat.model.Question; import de.imi.mopat.model.Questionnaire; import de.imi.mopat.model.dto.ExpressionDTO; @@ -21,9 +21,7 @@ import de.imi.mopat.model.score.ValueOperator; import de.imi.mopat.validator.ScoreDTOValidator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -45,7 +43,7 @@ public class ScoreController { @Autowired private ExportTemplateDao exportTemplateDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private QuestionDao questionDao; @Autowired @@ -66,16 +64,16 @@ public class ScoreController { @RequestMapping(value = "/score/list", method = RequestMethod.GET) @PreAuthorize("hasRole('ROLE_ADMIN')") public String showScoresForQuestionnaire( - @RequestParam(value = "id", required = true) final Long id, final Model model) { - Questionnaire questionnaire = questionnaireDao.getElementById(id); + @RequestParam(value = "id", required = true) final Long id, final Model model) { + Optional questionnaire = questionnaireService.getQuestionnaireById(id); - if (questionnaire == null) { + if (questionnaire.isEmpty()) { return "redirect:/questionnaire/list"; } // Sort the scores List scores = new ArrayList<>(); - scores.addAll(questionnaire.getScores()); + scores.addAll(questionnaire.get().getScores()); Collections.sort(scores, (Score o1, Score o2) -> o1.getName().compareTo(o2.getName())); List scoreDTOs = new ArrayList<>(); @@ -84,7 +82,7 @@ public String showScoresForQuestionnaire( } model.addAttribute("scores", scoreDTOs); - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.get()); return "score/list"; } @@ -100,24 +98,24 @@ public String showScoresForQuestionnaire( @RequestMapping(value = "/score/fill", method = RequestMethod.GET) @PreAuthorize("hasRole('ROLE_EDITOR')") public String fillScore( - @RequestParam(value = "questionnaireId", required = true) final Long questionnaireId, - @RequestParam(value = "id", required = false) final Long scoreId, final Model model) { + @RequestParam(value = "questionnaireId", required = true) final Long questionnaireId, + @RequestParam(value = "id", required = false) final Long scoreId, final Model model) { // Get a new ScoreDTO ScoreDTO scoreDTO = new ScoreDTO(); // Get the Questionnaire and the Score - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); + Optional questionnaire = questionnaireService.getQuestionnaireById(questionnaireId); List availableScores; // If the scoreId is set, get the ScoreDTO representation from the score if (scoreId != null) { Score score = scoreDao.getElementById(scoreId); scoreDTO = score.toScoreDTO(); - availableScores = questionnaire.getAvailableScoresForScore(score); + availableScores = questionnaire.get().getAvailableScoresForScore(score); } else { - availableScores = new ArrayList<>(questionnaire.getScores()); + availableScores = new ArrayList<>(questionnaire.get().getScores()); } // Sort the available scores by name Collections.sort(availableScores, - (Score o1, Score o2) -> o1.getName().compareTo(o2.getName())); + (Score o1, Score o2) -> o1.getName().compareTo(o2.getName())); scoreDTO.setQuestionnaireId(questionnaireId); // Get all Operators @@ -126,11 +124,11 @@ public String fillScore( if (availableScores.isEmpty()) { operators.remove(operatorDao.getOperatorByDisplaySign("valueOfScore")); } - List availableQuestionsForScore = questionnaire.getAvailableQuestionsForScore(); + List availableQuestionsForScore = questionnaire.get().getAvailableQuestionsForScore(); if (availableQuestionsForScore == null || availableQuestionsForScore.isEmpty()) { operators.remove(operatorDao.getOperatorByDisplaySign("valueOf")); } - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.get()); model.addAttribute("operators", operators); model.addAttribute("availableQuestionsForScore", availableQuestionsForScore); model.addAttribute("availableScoresForScore", availableScores); @@ -152,10 +150,10 @@ public String fillScore( @RequestMapping(value = "/score/edit", method = RequestMethod.POST) @PreAuthorize("hasRole('ROLE_EDITOR')") public String editScore( - @RequestParam(value = "questionnaireId", required = true) final Long questionnaireId, - @RequestParam(required = false, value = "postAction") final String action, - @ModelAttribute("scoreDTO") final ScoreDTO scoreDTO, BindingResult result, - final Model model) { + @RequestParam(value = "questionnaireId", required = true) final Long questionnaireId, + @RequestParam(required = false, value = "postAction") final String action, + @ModelAttribute("scoreDTO") final ScoreDTO scoreDTO, BindingResult result, + final Model model) { if (action.equalsIgnoreCase("cancel")) { return "redirect:/score/list?id=" + questionnaireId; @@ -167,24 +165,24 @@ public String editScore( scoreDTOValidator.validate(scoreDTO, result); if (result.hasErrors()) { - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); + Optional questionnaire = questionnaireService.getQuestionnaireById(questionnaireId); List availableScores; if (scoreDTO.getId() != null) { - availableScores = questionnaire.getAvailableScoresForScore( - scoreDao.getElementById(scoreDTO.getId())); + availableScores = questionnaire.get().getAvailableScoresForScore( + scoreDao.getElementById(scoreDTO.getId())); } else { - availableScores = new ArrayList<>(questionnaire.getScores()); + availableScores = new ArrayList<>(questionnaire.get().getScores()); } // Sort the available scores by name Collections.sort(availableScores, - (Score o1, Score o2) -> o1.getName().compareTo(o2.getName())); + (Score o1, Score o2) -> o1.getName().compareTo(o2.getName())); // Get all Operators List operators = new ArrayList<>(operatorDao.getOperators()); // And delete value of score, if available scores are empty if (availableScores.isEmpty()) { operators.remove(operatorDao.getOperatorByDisplaySign("valueOfScore")); } - List availableQuestionsForScore = questionnaire.getAvailableQuestionsForScore(); + List availableQuestionsForScore = questionnaire.get().getAvailableQuestionsForScore(); if (availableQuestionsForScore == null || availableQuestionsForScore.isEmpty()) { operators.remove(operatorDao.getOperatorByDisplaySign("valueOf")); } @@ -193,11 +191,11 @@ public String editScore( model.addAttribute("availableScoresForScore", availableScores); // overwrite the spring errors and take the new one model.addAttribute("org.springframework.validation.BindingResult.scoreDTO", result); - model.addAttribute("questionnaire", questionnaire); + model.addAttribute("questionnaire", questionnaire.get()); return "score/edit"; } - Questionnaire questionnaire = questionnaireDao.getElementById( - scoreDTO.getQuestionnaireId()); + Optional questionnaire = questionnaireService.getQuestionnaireById( + scoreDTO.getQuestionnaireId()); Score score = null; @@ -206,17 +204,17 @@ public String editScore( score.setExpression(null); } else { score = new Score(); - score.setQuestionnaire(questionnaire); + score.setQuestionnaire(questionnaire.orElse(null)); } score.setName(scoreDTO.getName()); Expression expression = scoreDTO.getExpression() - .toExpression(operatorDao, questionDao, scoreDao); + .toExpression(operatorDao, questionDao, scoreDao); score.setExpression(expression); scoreDao.merge(score); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire.orElse(null)); return "redirect:/score/list?id=" + questionnaireId; } @@ -231,14 +229,13 @@ public String editScore( @RequestMapping(value = "/score/remove") @PreAuthorize("hasRole('ROLE_EDITOR')") public String removeScore(@RequestParam(value = "id", required = true) final Long scoreId, - final Model model) { + final Model model) { Score score = scoreDao.getElementById(scoreId); List dependingScores = score.getDependingScores(); // Sort depending scores by amount of their depending scores to // prevent database errors Collections.sort(dependingScores, - (Score o1, Score o2) -> o1.getDependingScores().size() - o2.getDependingScores() - .size()); + Comparator.comparingInt((Score o) -> o.getDependingScores().size())); // Safely delete all depending scores for (Score scoreToDelete : dependingScores) { scoreDao.remove(scoreToDelete); diff --git a/src/main/java/de/imi/mopat/controller/StatisticController.java b/src/main/java/de/imi/mopat/controller/StatisticController.java index 2392690b..a11040a2 100644 --- a/src/main/java/de/imi/mopat/controller/StatisticController.java +++ b/src/main/java/de/imi/mopat/controller/StatisticController.java @@ -2,8 +2,8 @@ import de.imi.mopat.dao.BundleDao; import de.imi.mopat.dao.EncounterDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.StatisticDao; +import de.imi.mopat.helper.controller.QuestionnaireService; import de.imi.mopat.model.dto.OneTimeStatisticDTO; import de.imi.mopat.model.dto.StatisticDTO; import de.imi.mopat.validator.OneTimeStatisticDTOValidator; @@ -41,7 +41,7 @@ public class StatisticController { @Autowired private OneTimeStatisticDTOValidator oneTimeStatisticDTOValidator; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private BundleDao bundleDao; @Autowired @@ -62,7 +62,7 @@ public String getOneTimeStatistic(final Model model) { OneTimeStatisticDTO oneTimeStatisticDTO = new OneTimeStatisticDTO(new Date(), new Date()); model.addAttribute("oneTimeStatisticDTO", oneTimeStatisticDTO); model.addAttribute("bundles", bundleDao.getAllElements()); - model.addAttribute("questionnaires", questionnaireDao.getAllElements()); + model.addAttribute("questionnaires", questionnaireService.getAllQuestionnaires()); model.addAttribute("patients", encounterDao.getAllCaseNumbers()); return "statistic/onetimestatistic"; } @@ -84,7 +84,7 @@ public String getOneTimeStatistics( final BindingResult result, final Model model) { oneTimeStatisticDTOValidator.validate(oneTimeStatisticDTO, result); model.addAttribute("bundles", bundleDao.getAllElements()); - model.addAttribute("questionnaires", questionnaireDao.getAllElements()); + model.addAttribute("questionnaires", questionnaireService.getAllQuestionnaires()); model.addAttribute("patients", encounterDao.getAllCaseNumbers()); if (result.hasErrors()) { return "statistic/onetimestatistic"; diff --git a/src/main/java/de/imi/mopat/controller/SurveyController.java b/src/main/java/de/imi/mopat/controller/SurveyController.java index 7ac94d20..b11e5c8a 100644 --- a/src/main/java/de/imi/mopat/controller/SurveyController.java +++ b/src/main/java/de/imi/mopat/controller/SurveyController.java @@ -12,7 +12,6 @@ import de.imi.mopat.dao.ConditionDao; import de.imi.mopat.dao.ConfigurationDao; import de.imi.mopat.dao.EncounterDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.ResponseDao; import de.imi.mopat.dao.ScoreDao; import de.imi.mopat.dao.user.PinAuthorizationDao; @@ -86,7 +85,7 @@ public class SurveyController { @Autowired private AnswerDao answerDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private ConditionDao conditionDao; @Autowired @@ -627,7 +626,7 @@ public String showQuestionnaire(final Model model, final HttpSession session) { QuestionnaireDTO questionnaireDTO = bundleQuestionnaireDTO.getQuestionnaireDTO(); // Get the boolean if this questionnaire has any conditions boolean hasConditionsAsTarget = conditionDao.isConditionTarget( - questionnaireDao.getElementById(questionnaireDTO.getId())); + questionnaireService.getQuestionnaireById(questionnaireDTO.getId()).orElse(null)); // Set the boolean in the QuestionnaireDTO questionnaireDTO.setHasConditionsAsTarget(hasConditionsAsTarget); } @@ -690,7 +689,7 @@ public String testBundle(@RequestParam(value = "id", required = false) final Lon QuestionnaireDTO questionnaireDTO = bundleQuestionnaireDTO.getQuestionnaireDTO(); // Get the boolean if this questionnaire has any conditions boolean hasConditionsAsTarget = conditionDao.isConditionTarget( - questionnaireDao.getElementById(questionnaireDTO.getId())); + questionnaireService.getQuestionnaireDTOById(questionnaireDTO.getId()).orElse(null)); // Set the boolean in the QuestionnaireDTO questionnaireDTO.setHasConditionsAsTarget(hasConditionsAsTarget); } @@ -926,7 +925,7 @@ public String showQuestionnaireScheduled( QuestionnaireDTO questionnaireDTO = bundleQuestionnaireDTO.getQuestionnaireDTO(); // Get the boolean if this questionnaire has any conditions boolean hasConditionsAsTarget = conditionDao.isConditionTarget( - questionnaireDao.getElementById(questionnaireDTO.getId())); + questionnaireService.getQuestionnaireById(questionnaireDTO.getId()).orElse(null)); // Set the boolean in the QuestionnaireDTO questionnaireDTO.setHasConditionsAsTarget(hasConditionsAsTarget); } @@ -992,7 +991,7 @@ public String showQuestionnaireScheduled( currentAnswer.removeResponse(responseToDelete); existingResponses.remove(responseToDelete); } - questionnaireDao.merge(currentAnswer.getQuestion().getQuestionnaire()); + questionnaireService.merge(currentAnswer.getQuestion().getQuestionnaire()); continue; } @@ -1102,7 +1101,7 @@ public String showQuestionnaireScheduled( Response response = createResponseObject(responseDTO, encounter, currentAnswer); existingResponses.add(response); } - questionnaireDao.merge(currentAnswer.getQuestion().getQuestionnaire()); + questionnaireService.merge(currentAnswer.getQuestion().getQuestionnaire()); } // Get all existing responses that were not in the DTO @@ -1115,7 +1114,7 @@ public String showQuestionnaireScheduled( encounter.getId()); answer.removeResponse(responseToDelete); existingResponses.remove(responseToDelete); - questionnaireDao.merge(answer.getQuestion().getQuestionnaire()); + questionnaireService.merge(answer.getQuestion().getQuestionnaire()); } // Update the response list of the encounter and merge it @@ -1278,9 +1277,9 @@ public void finishQuestionnaire( updateEncounter(encounterDTO); // Refresh encounter from database after storing of responses encounter = encounterDao.getElementByUUID(encounterDTO.getUuid()); - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); - if (encounter.getActiveQuestionnaires().contains(questionnaire.getId())) { - encounterExporter.export(encounter, questionnaire, false); + Optional questionnaire = questionnaireService.getQuestionnaireById(questionnaireId); + if (encounter.getActiveQuestionnaires().contains(questionnaire.get().getId())) { + encounterExporter.export(encounter, questionnaire.orElse(null), false); } } } @@ -1316,8 +1315,8 @@ private void finishQuestionnaireTest(final Long questionnaireId, if (bundle != null && !bundle.getIsPublished()) { - Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireId); - if (encounterDTO.getActiveQuestionnaireIds().contains(questionnaire.getId())) { + Optional questionnaire = questionnaireService.getQuestionnaireById(questionnaireId); + if (encounterDTO.getActiveQuestionnaireIds().contains(questionnaire.get().getId())) { Encounter encounter = new Encounter(); encounter.setCaseNumber(encounterDTO.getCaseNumber()); encounter.setBundleLanguage(encounterDTO.getBundleLanguage()); @@ -1333,7 +1332,7 @@ private void finishQuestionnaireTest(final Long questionnaireId, } encounter.setResponses(responses); if(performExportTest) { - encounterExporter.export(encounter, questionnaire, true); + encounterExporter.export(encounter, questionnaire.orElse(null), true); } } } diff --git a/src/main/java/de/imi/mopat/helper/controller/BundleService.java b/src/main/java/de/imi/mopat/helper/controller/BundleService.java index f4ecd99c..9bf1879b 100644 --- a/src/main/java/de/imi/mopat/helper/controller/BundleService.java +++ b/src/main/java/de/imi/mopat/helper/controller/BundleService.java @@ -5,7 +5,6 @@ import de.imi.mopat.dao.BundleDao; import de.imi.mopat.dao.BundleQuestionnaireDao; import de.imi.mopat.dao.ExportTemplateDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.ScoreDao; import de.imi.mopat.helper.model.BundleDTOMapper; import de.imi.mopat.helper.model.QuestionnaireDTOMapper; @@ -38,8 +37,6 @@ public class BundleService { @Autowired private BundleDao bundleDao; @Autowired - private QuestionnaireDao questionnaireDao; - @Autowired private ScoreDao scoreDao; @Autowired private BundleQuestionnaireDao bundleQuestionnaireDao; @@ -77,7 +74,7 @@ public BundleDTO getBundleDTO(final Long id) { bundleDTO.getBundleQuestionnaireDTOs().forEach(bundleQuestionnaireDTO -> { QuestionnaireDTO questionnaireDTO = bundleQuestionnaireDTO.getQuestionnaireDTO(); if (questionnaireDTO != null && questionnaireDTO.getId() != null) { - questionnaireDTO.setHasScores(scoreDao.hasScore(questionnaireDao.getElementById(questionnaireDTO.getId()))); + questionnaireDTO.setHasScores(scoreDao.hasScore(questionnaireService.getQuestionnaireById(questionnaireDTO.getId()).orElse(null))); } }); @@ -286,10 +283,10 @@ private void persistBundleQuestionnaires(BundleDTO bundleDTO, Bundle bundle) { continue; } - Questionnaire questionnaire = questionnaireDao.getElementById(bundleQuestionnaireDTO.getQuestionnaireDTO().getId()); + Optional questionnaire = questionnaireService.getQuestionnaireById(bundleQuestionnaireDTO.getQuestionnaireDTO().getId()); BundleQuestionnaire bundleQuestionnaire = new BundleQuestionnaire( bundle, - questionnaire, + questionnaire.orElse(null), bundleQuestionnaireDTO.getPosition().intValue(), Optional.ofNullable(bundleQuestionnaireDTO.getIsEnabled()).orElse(false), Optional.ofNullable(bundleQuestionnaireDTO.getShowScores()).orElse(false) @@ -304,8 +301,8 @@ private void persistBundleQuestionnaires(BundleDTO bundleDTO, Bundle bundle) { }); bundle.addBundleQuestionnaire(bundleQuestionnaire); - questionnaire.addBundleQuestionnaire(bundleQuestionnaire); - questionnaireDao.merge(questionnaire); + questionnaire.get().addBundleQuestionnaire(bundleQuestionnaire); + questionnaireService.merge(questionnaire.get()); } } @@ -340,7 +337,7 @@ private void cleanupRemovedBundleQuestionnaires(Bundle bundle) { } Questionnaire questionnaire = toDelete.getQuestionnaire(); questionnaire.removeBundleQuestionnaire(toDelete); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); } bundle.removeAllBundleQuestionnaires(); bundleDao.merge(bundle); diff --git a/src/main/java/de/imi/mopat/helper/controller/ConditionService.java b/src/main/java/de/imi/mopat/helper/controller/ConditionService.java index 4589d447..187a35f1 100644 --- a/src/main/java/de/imi/mopat/helper/controller/ConditionService.java +++ b/src/main/java/de/imi/mopat/helper/controller/ConditionService.java @@ -3,7 +3,6 @@ import de.imi.mopat.dao.AnswerDao; import de.imi.mopat.dao.BundleDao; import de.imi.mopat.dao.QuestionDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.model.Answer; import de.imi.mopat.model.Bundle; import de.imi.mopat.model.NumberInputAnswer; @@ -23,7 +22,7 @@ public class ConditionService { @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private BundleDao bundleDao; @@ -45,7 +44,7 @@ public void mergeCondition(ConditionDTO conditionDTO) { // condition into the database if (conditionDTO.getBundleId() != null && conditionDTO.getTargetClass() .equalsIgnoreCase("de.imi.mopat.model.Questionnaire")) { - targetQuestionnaire = questionnaireDao.getElementById(conditionDTO.getTargetId()); + targetQuestionnaire = questionnaireService.getQuestionnaireById(conditionDTO.getTargetId()).orElse(null); bundle = bundleDao.getElementById(conditionDTO.getBundleId()); conditionDTO.setTargetAnswerQuestionId(null); } else { diff --git a/src/main/java/de/imi/mopat/helper/controller/QuestionService.java b/src/main/java/de/imi/mopat/helper/controller/QuestionService.java index 6f4b3995..e1d94d39 100644 --- a/src/main/java/de/imi/mopat/helper/controller/QuestionService.java +++ b/src/main/java/de/imi/mopat/helper/controller/QuestionService.java @@ -2,7 +2,6 @@ import de.imi.mopat.dao.AnswerDao; import de.imi.mopat.dao.BundleDao; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.model.Answer; import de.imi.mopat.model.Question; import de.imi.mopat.model.conditions.Condition; @@ -25,7 +24,7 @@ public class QuestionService { private AnswerDao answerDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private BundleDao bundleDao; @@ -105,9 +104,9 @@ Questionnaire duplicateQuestionsToNewQuestionnaire( copiedQuestions.add(newQuestion); } newQuestionnaire.setQuestions(copiedQuestions); - questionnaireDao.merge(newQuestionnaire); + questionnaireService.merge(newQuestionnaire); //Refetch questionnaire to get ids from db - return questionnaireDao.getElementById(newQuestionnaire.getId()); + return questionnaireService.getQuestionnaireById(newQuestionnaire.getId()).orElse(null); } MapHolder getMappingForDuplicatedQuestions( diff --git a/src/main/java/de/imi/mopat/helper/controller/QuestionnaireService.java b/src/main/java/de/imi/mopat/helper/controller/QuestionnaireService.java index c08e472a..327a52fc 100644 --- a/src/main/java/de/imi/mopat/helper/controller/QuestionnaireService.java +++ b/src/main/java/de/imi/mopat/helper/controller/QuestionnaireService.java @@ -47,6 +47,8 @@ import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.MessageSource; import org.springframework.stereotype.Service; @@ -126,11 +128,12 @@ public void processLocalizedText(QuestionnaireDTO questionnaireDTO) { * @return A list of all {@link QuestionnaireDTO} objects. */ public List getAllQuestionnaireDTOs() { - return questionnaireDao.getAllElements().stream() + return getAllQuestionnaires().stream() .map(questionnaireDTOMapper) .collect(Collectors.toList()); } + @Cacheable(value = "questionnaires", key = "'all'") public List getAllQuestionnaires() { return questionnaireDao.getAllElements(); } @@ -158,6 +161,7 @@ public void validateQuestionnaire(QuestionnaireDTO questionnaireDTO, MultipartFi * @param userId The ID of the user performing the action. * @return The saved or updated {@link Questionnaire}. */ + @CacheEvict(value = "questionnaires", key = "'all'") public Questionnaire saveOrUpdateQuestionnaire(QuestionnaireDTO questionnaireDTO, MultipartFile logo, Long userId) { // Update questionnaire directly if editing is allowed @@ -174,6 +178,16 @@ public Questionnaire saveOrUpdateQuestionnaire(QuestionnaireDTO questionnaireDTO return createNewQuestionnaire(questionnaireDTO, logo, userId); } + @CacheEvict(value = "questionnaires", key = "'all'") + public void removeQuestionnaire(Questionnaire questionnaire) { + questionnaireDao.remove(questionnaire); + } + + @CacheEvict(value = "questionnaires", key = "'all'") + public void merge(Questionnaire questionnaire) { + questionnaireDao.merge(questionnaire); + } + /** * Retrieves a {@link QuestionnaireDTO} by its ID. * @@ -182,11 +196,14 @@ public Questionnaire saveOrUpdateQuestionnaire(QuestionnaireDTO questionnaireDTO * otherwise. */ public Optional getQuestionnaireDTOById(Long questionnaireId) { - if (questionnaireId == null || questionnaireId <= 0) { + return getQuestionnaireById(questionnaireId).map(questionnaireDTOMapper); + } + + public Optional getQuestionnaireById(Long id) { + if (id == null || id <= 0) { return Optional.empty(); } - return Optional.ofNullable(questionnaireDao.getElementById(questionnaireId)) - .map(questionnaireDTOMapper); + return Optional.ofNullable(questionnaireDao.getElementById(id)); } /** @@ -312,7 +329,7 @@ private Questionnaire createNewQuestionnaire(QuestionnaireDTO questionnaireDTO, userId, Boolean.TRUE ); - questionnaireDao.merge(newQuestionnaire); + merge(newQuestionnaire); QuestionnaireVersionGroup questionnaireVersionGroup = questionnaireVersionGroupService.createQuestionnaireGroup( newQuestionnaire.getName()); @@ -320,7 +337,7 @@ private Questionnaire createNewQuestionnaire(QuestionnaireDTO questionnaireDTO, copyLocalizedTextsToQuestionnaire(newQuestionnaire, questionnaireDTO); handleLogoUpload(newQuestionnaire, questionnaireDTO, logo); - questionnaireDao.merge(newQuestionnaire); + merge(newQuestionnaire); return newQuestionnaire; } @@ -343,7 +360,7 @@ private Questionnaire updateExistingQuestionnaire(QuestionnaireDTO questionnaire copyLocalizedTextsToQuestionnaire(existingQuestionnaire, questionnaireDTO); handleLogoUpload(existingQuestionnaire, questionnaireDTO, logo); - questionnaireDao.merge(existingQuestionnaire); + merge(existingQuestionnaire); return existingQuestionnaire; } @@ -365,7 +382,7 @@ private Questionnaire createQuestionnaireCopy(QuestionnaireDTO questionnaireDTO, userId, Boolean.TRUE ); - questionnaireDao.merge(newQuestionnaire); + merge(newQuestionnaire); newQuestionnaire = questionService.duplicateQuestionsToNewQuestionnaire(existingQuestionnaire.getQuestions(), newQuestionnaire); @@ -389,7 +406,7 @@ private Questionnaire createQuestionnaireCopy(QuestionnaireDTO questionnaireDTO, QuestionnaireVersionGroup existingGroup = existingQuestionnaire.getQuestionnaireVersionGroup(); questionnaireVersionGroupService.addQuestionnaireToGroup(existingGroup, newQuestionnaire); - questionnaireDao.merge(newQuestionnaire); + merge(newQuestionnaire); //Apparently Conditions are already persisted with the previous merge command //for(Condition condition : clonedConditions) @@ -563,7 +580,7 @@ public Boolean hasQuestionnaireConditions(Questionnaire questionnaire) { * @param questionnaireDTO The {@link QuestionnaireDTO} containing the logo information. * @param logo The {@link MultipartFile} containing the new logo file. */ - public void handleLogoUpload(Questionnaire questionnaire, QuestionnaireDTO questionnaireDTO, MultipartFile logo) { + private void handleLogoUpload(Questionnaire questionnaire, QuestionnaireDTO questionnaireDTO, MultipartFile logo) { try { String imagePath = configurationDao.getImageUploadPath() + "/" + Constants.IMAGE_QUESTIONNAIRE + "/" + questionnaire.getId().toString(); diff --git a/src/main/java/de/imi/mopat/helper/controller/QuestionnaireVersionGroupService.java b/src/main/java/de/imi/mopat/helper/controller/QuestionnaireVersionGroupService.java index 97f09d2c..db76b44c 100644 --- a/src/main/java/de/imi/mopat/helper/controller/QuestionnaireVersionGroupService.java +++ b/src/main/java/de/imi/mopat/helper/controller/QuestionnaireVersionGroupService.java @@ -1,6 +1,5 @@ package de.imi.mopat.helper.controller; -import de.imi.mopat.dao.QuestionnaireDao; import de.imi.mopat.dao.QuestionnaireVersionGroupDao; import de.imi.mopat.helper.model.QuestionnaireGroupDTOMapper; import de.imi.mopat.model.Questionnaire; @@ -26,7 +25,7 @@ public class QuestionnaireVersionGroupService { private QuestionnaireVersionGroupDao questionnaireVersionGroupDao; @Autowired - private QuestionnaireDao questionnaireDao; + private QuestionnaireService questionnaireService; @Autowired private QuestionnaireGroupDTOMapper questionnaireGroupDTOMapper; @@ -197,7 +196,7 @@ public void removeQuestionnaire(Long questionnaireVersionGroupId, Questionnaire // Unlink the questionnaire from the group questionnaire.setQuestionnaireVersionGroup(null); - questionnaireDao.merge(questionnaire); + questionnaireService.merge(questionnaire); if (questionnairesInGroup.isEmpty()){ //If there would be no questionnaire left, delete the group From d8fe0c04e7e601d7c0bbd8a3113f530663634784 Mon Sep 17 00:00:00 2001 From: winkt0 <238452092+winkt0@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:49:37 +0200 Subject: [PATCH 2/2] 300: (WIP) Added redis dependency and created RedisCacheConfig --- pom.xml | 5 +++ .../de/imi/mopat/config/RedisCacheConfig.java | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/main/java/de/imi/mopat/config/RedisCacheConfig.java diff --git a/pom.xml b/pom.xml index 897db063..cd636d8f 100644 --- a/pom.xml +++ b/pom.xml @@ -796,6 +796,11 @@ + + org.springframework.boot + spring-boot-starter-data-redis + 4.0.5 + org.springframework spring-webmvc diff --git a/src/main/java/de/imi/mopat/config/RedisCacheConfig.java b/src/main/java/de/imi/mopat/config/RedisCacheConfig.java new file mode 100644 index 00000000..bffe4ebc --- /dev/null +++ b/src/main/java/de/imi/mopat/config/RedisCacheConfig.java @@ -0,0 +1,34 @@ +package de.imi.mopat.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.GenericJacksonJsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; + +@Configuration +public class RedisCacheConfig { + + @Bean + public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(5)) + .serializeKeysWith( + RedisSerializationContext.SerializationPair + .fromSerializer(new StringRedisSerializer()) + ) + .serializeValuesWith( + RedisSerializationContext.SerializationPair + .fromSerializer(GenericJacksonJsonRedisSerializer.builder().build()) + ) + .disableCachingNullValues(); + return RedisCacheManager.builder(connectionFactory) + .cacheDefaults(config) + .build(); + } +} \ No newline at end of file