diff --git a/TestProd.pdf b/TestProd.pdf deleted file mode 100644 index 7d99b11..0000000 Binary files a/TestProd.pdf and /dev/null differ diff --git a/backup.ps1 b/backup.ps1 new file mode 100644 index 0000000..ba3686b --- /dev/null +++ b/backup.ps1 @@ -0,0 +1,46 @@ +param ( + [string]$WorkDir = "./workdir", + [string]$BackupPath = "./backup", + [boolean]$OverWrite = $False +) + +Write-Host "Démarrage de la sauvegarde..." +if (!(Test-Path -Path $WorkDir)) +{ + Write-Host "Le dossier de travail ($WorkDir) n'existe pas." + exit +} + +if (!(Test-Path -Path $BackupPath)) +{ + Write-Host "Création du dossier des sauvegardes. ($BackupPath)" + New-Item -ItemType directory -Path $BackupPath | Out-Null +} + +Write-Host "Début de la compression..." +$BackupFile = "$BackupPath/backup_$( Get-Date -f yyyyMMdd-HHmm ).zip" +$CompressArgs = @{ + 'Path' = $WorkDir + 'DestinationPath' = $BackupFile + 'Update' = $OverWrite +} + +try +{ + Compress-Archive @CompressArgs + + Write-Host "Sauvegarde réussie! ($BackupFile)" +} +catch [System.IO.IOException] +{ + Write-Output "Une erreur est survenue lors de la sauvegarde:" + + if ($_.FullyQualifiedErrorId -like "ArchiveFileExists*") + { + Write-Host "L'archive de sauvegarde '$BackupFile' existe déjà. Ajoutez l'argument '-OverWrite `$true' pour écraser l'archive." + } + else + { + Write-Host $_ + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 210c1fb..8309979 100644 --- a/pom.xml +++ b/pom.xml @@ -8,11 +8,10 @@ 2.1.4.RELEASE - fyloz.trial + dev.fyloz.trial.colorrecipesexplorer ColorRecipesExplorer - 0.0.1-SNAPSHOT - ColorRecipesExplorer - Demo project for Spring Boot + 1.1.1 + Color Recipes Explorer UTF-8 @@ -42,21 +41,26 @@ spring-boot-starter-test test - - + + org.xhtmlrenderer + flying-saucer-pdf + 9.1.18 + + + org.apache.poi + poi-ooxml + 4.1.0 + com.h2database h2 runtime - commons-codec commons-codec 1.11 - - com.itextpdf itextpdf @@ -67,6 +71,30 @@ pdfbox 2.0.4 + + org.mockito + mockito-core + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + 1.18.10 + provided + + + org.springframework.boot + spring-boot-devtools + + + com.atlassian.commonmark + commonmark + 0.13.1 + @@ -75,6 +103,23 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-antrun-plugin + + + test + + run + + + + + + + + + diff --git a/recipes.mv.db b/recipes.mv.db deleted file mode 100644 index 417112b..0000000 Binary files a/recipes.mv.db and /dev/null differ diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java similarity index 50% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java index 3d6efd4..3139f68 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java @@ -1,11 +1,13 @@ -package fyloz.trial.ColorRecipesExplorer; +package dev.fyloz.trial.colorrecipesexplorer; -import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler; -import fyloz.trial.ColorRecipesExplorer.web.StringBank; +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.MessageSource; import java.io.File; import java.io.IOException; @@ -15,26 +17,38 @@ import java.util.List; @SpringBootApplication public class ColorRecipesExplorerApplication { - public static final Logger logger = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class); - // Chemin du fichier contenant les utilisateurs + public static final Logger LOGGER = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class); + public static String UPLOAD_LOCATION; public static final String USERS_FILE_NAME = "passwords"; + public static boolean USE_PORT; + + public static ColorRecipesExplorerApplication CREApp; + + private MessageSource messageSource; public static void main(String[] args) { - logger.info("Le fichier des utilisateurs se situe à: " + new File(StringBank.UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath()); - loadPasswords(); + UPLOAD_LOCATION = args[0] != null ? args[0] : "./"; SpringApplication.run(ColorRecipesExplorerApplication.class, args); } + @Autowired + public ColorRecipesExplorerApplication(MessageSource messageSource) { + this.messageSource = messageSource; + + CREApp = this; + LOGGER.info("Le fichier des utilisateurs se situe à: " + new File(UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath()); + + loadPasswords(); + } + /** * Charge les mots de passes contenus dans le fichier. *

* Un mot de passe correspond à une ligne dans le fichier passwords.txt. - * - * @throws IOException */ - private static void loadPasswords() { - FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TXT); + private void loadPasswords() { + FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TEXT); if (!fileHandler.isValid()) { fileHandler.createFile(); } @@ -43,15 +57,19 @@ public class ColorRecipesExplorerApplication { List fileContent = Files.readAllLines(fileHandler.getPath()); if (fileContent.size() < 1) { - logger.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application."); + LOGGER.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application."); } for (String line : fileContent) { - PasswordValidator.addPassword(line); + PasswordService.addPassword(line); } } catch (IOException e) { - logger.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e); - logger.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application."); + LOGGER.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e); + LOGGER.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application."); } } + + public MessageSource getMessageSource() { + return messageSource; + } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java new file mode 100644 index 0000000..a2d5f66 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java @@ -0,0 +1,41 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.configuration; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class InitialDataLoader implements ApplicationListener { + + private MaterialTypeService materialTypeService; + + @Autowired + public InitialDataLoader(MaterialTypeService materialTypeService) { + this.materialTypeService = materialTypeService; + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + if (!materialTypeService.getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME).isPresent()) { + createDefaultMaterialType(); + } + } + + private void createDefaultMaterialType() { + MaterialType defaultMaterialType = new MaterialType(MaterialType.DEFAULT_MATERIAL_TYPE_NAME, "", false); + + Optional optionalSavedMaterialType = materialTypeService.save(defaultMaterialType); + if (!optionalSavedMaterialType.isPresent()) { + ColorRecipesExplorerApplication.LOGGER.warn("Échec de la création du type de produit par défaut."); + } + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java similarity index 79% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java index d42819b..c014431 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.core.configuration; +package dev.fyloz.trial.colorrecipesexplorer.core.configuration; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; @@ -18,19 +18,11 @@ public class LocaleConfiguration implements WebMvcConfigurer { @Bean public MessageSource messageSource() { ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); -// messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses"); - messageSource.setBasename("classpath:lang/responses"); + messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses"); messageSource.setDefaultEncoding("UTF-8"); return messageSource; } -// @Bean -// public MessageSource responsesMessageSource() { -// ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); -// messageSource.setBasename("classpath:lang/responses"); -// return messageSource; -// } - @Bean public LocaleResolver localeResolver() { SessionLocaleResolver localeResolver = new SessionLocaleResolver(); diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java similarity index 94% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java index 1573517..25f7338 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.core.configuration; +package dev.fyloz.trial.colorrecipesexplorer.core.configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java new file mode 100644 index 0000000..fc61ecd --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java @@ -0,0 +1,19 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.configuration; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpringConfiguration { + + @Value("${response.useport}") + public boolean usePort; + + @Bean + public void setUsePort() { + ColorRecipesExplorerApplication.USE_PORT = usePort; + } + +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java similarity index 87% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java index 451075e..9ebb7c3 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java @@ -1,6 +1,6 @@ -package fyloz.trial.ColorRecipesExplorer.core.io; +package dev.fyloz.trial.colorrecipesexplorer.core.io.file; -import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; import org.slf4j.Logger; import java.io.File; @@ -9,12 +9,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.UPLOAD_LOCATION; - public class FileHandler { protected String name; - protected Logger logger = ColorRecipesExplorerApplication.logger; + protected Logger logger = ColorRecipesExplorerApplication.LOGGER; private FileContext context; private FileExtension extension; @@ -91,7 +89,7 @@ public class FileHandler { } public Path getPath() { - return Paths.get(String.format("%s/%s/%s%s", UPLOAD_LOCATION, context.getPath(), name, extension.getExtension())); + return Paths.get(String.format("%s/%s/%s%s", ColorRecipesExplorerApplication.UPLOAD_LOCATION, context.getPath(), name, extension.getExtension())); } public File getFile() { @@ -118,8 +116,9 @@ public class FileHandler { public enum FileExtension { JPEG("jpeg"), PDF("pdf"), - TXT("txt"), - DB("db"); + TEXT("txt"), + DATABASE("db"), + MARKDOWN("md"); private String extension; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java similarity index 77% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java index 7e13c22..d53848b 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java @@ -1,13 +1,16 @@ -package fyloz.trial.ColorRecipesExplorer.core.io; +package dev.fyloz.trial.colorrecipesexplorer.core.io.file; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; import java.util.List; import java.util.stream.Collectors; public class ImageHandler extends FileHandler { + public static final String IMAGES_LOCATION = ColorRecipesExplorerApplication.UPLOAD_LOCATION + "/images"; + private Recipe recipe; private int index = 0; private RecipeService recipeService; @@ -22,6 +25,8 @@ public class ImageHandler extends FileHandler { public ImageHandler(String name, RecipeService recipeService) { super(name.replace(".jpeg", ""), FileContext.IMAGE, FileExtension.JPEG); + this.recipeService = recipeService; + String[] nameParts = name.split("-"); index = Integer.parseInt(nameParts[1].replace(".jpeg", "")); } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java new file mode 100644 index 0000000..755bec6 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java @@ -0,0 +1,25 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.io.response; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import org.springframework.context.i18n.LocaleContextHolder; + +import java.util.HashMap; +import java.util.Map; + +public class JSONResponseBuilder extends ResponseBuilder> { + + @Override + protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) { + Map attributeContent = new HashMap<>(); + + // Récupère le message depuis le fichier des messages de la bonne language et rajoute ces paramètres. + String message = ColorRecipesExplorerApplication.CREApp.getMessageSource().getMessage(responseMessagePath, parameters, LocaleContextHolder.getLocale()); + attributeContent.put("message", message); + + addAttribute(responseCodeType, attributeContent); + } + + public Map build() { + return attributes; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java new file mode 100644 index 0000000..1d676b1 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java @@ -0,0 +1,50 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.io.response; + +import org.springframework.web.servlet.ModelAndView; + +public class ModelResponseBuilder extends ResponseBuilder { + + private static final String PATH_PARAMETER_PATTERN = "(\\{\\w+\\})"; + + private ModelAndView model; + + public ModelResponseBuilder() { + this.model = new ModelAndView(); + } + + public ModelResponseBuilder(String view) { + this(new ModelAndView(view)); + } + + public ModelResponseBuilder(ModelAndView model) { + this.model = model == null ? new ModelAndView() : model; + } + + public ModelResponseBuilder withView(String path) { + model.setViewName(path); + + return this; + } + + public ModelResponseBuilder withRedirect(String path, Object... parameters) { + for (Object parameter : parameters) path = path.replaceFirst(PATH_PARAMETER_PATTERN, parameter.toString()); + model.setViewName("redirect:/" + path); + + return this; + } + + @Override + protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) { + addAttribute(responseCodeType, responseMessagePath); + + for (int i = 0; i < parameters.length; i++) { + addAttribute(String.format("responseArg%s", i + 1), parameters[i]); + } + } + + public ModelAndView build() { + model.addAllObjects(attributes); + + return model; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java new file mode 100644 index 0000000..87734db --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java @@ -0,0 +1,112 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.io.response; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; + +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class ResponseBuilder { + + protected static final String RESPONSE_PREFIX = "response."; + protected static final String ERROR_ATTRIBUTE_NAME = "error"; + protected static final String SUCCESS_ATTRIBUTE_NAME = "success"; + + protected Map attributes; + + private boolean containsErrors = false; + + public ResponseBuilder() { + attributes = new HashMap<>(); + + // Ajoute l'URL de base à toutes les réponses + attributes.put("baseUrl", ControllerUtils.getCurrentBaseUrl()); + } + + protected abstract void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters); + + protected abstract R build(); + + public T addResponseCode(ResponseCode responseCode, Object... parameters) { + String[] parametersAsStr = new String[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + parametersAsStr[i] = parameters[i].toString(); + } + + return addResponseCode(responseCode, parametersAsStr); + } + + public T addResponseCode(ResponseCode responseCode, String... parameters) { + int requiredParametersNumber = responseCode.getParametersNumber(); + int givenParametersNumber = parameters.length; + + if (requiredParametersNumber != givenParametersNumber) { + throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans une réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber)); + } + + // Ajoute les paramètres, si nécessaire + if (requiredParametersNumber > 0) { + // Avertit s'il y a plus de paramètres que le nombre de paramètres supporté par le template thymeleaf (aussi MAX_PARAMETERS_NUMBER) + int maxParametersNumber = ResponseCode.MAX_PARAMETERS_NUMBER; + if (givenParametersNumber > maxParametersNumber) { + ColorRecipesExplorerApplication.LOGGER.warn(String.format("Trop de paramètres fournis pour le code de réponse %s: %s maximum, %s fournis", responseCode.name(), maxParametersNumber, givenParametersNumber)); + } + } + + String responseCodeType; + if (responseCode.getType() == ResponseCode.ResponseCodeType.ERROR) { + containsErrors = true; + responseCodeType = ERROR_ATTRIBUTE_NAME; + } else { + responseCodeType = SUCCESS_ATTRIBUTE_NAME; + } + + String responseMessagePath = RESPONSE_PREFIX + responseCode.getCode(); + addResponseCodeToAttribute(responseCodeType, responseMessagePath, parameters); + + return (T) this; + } + + public T addResponseData(ResponseDataType responseDataType, @NotNull Object data) { + Class requiredDataTypeClass = responseDataType.getDataType(); + Class requiredListDataTypeClass = responseDataType.getListDataType(); + Class givenDataTypeClass = data.getClass(); + + // Vérifie le type de l'objet + if (!requiredDataTypeClass.equals(givenDataTypeClass)) { + throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", requiredDataTypeClass.getName(), givenDataTypeClass.getName())); + } + + // Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type + if (requiredDataTypeClass.equals(List.class) && requiredListDataTypeClass != null) { + List listData = (List) data; + + if (listData.size() < 1) { + throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément"); + } + + Class givenListDataTypeClass = listData.get(0).getClass(); + if (givenDataTypeClass.equals(requiredListDataTypeClass)) { + throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", requiredListDataTypeClass.getName(), givenListDataTypeClass.getName())); + } + } + + // Ajoute l'attribut dans le Map + addAttribute(responseDataType.getDataTypeName(), data); + + return (T) this; + } + + public T addAttribute(String attributeName, Object content) { + attributes.put(attributeName, content); + + return (T) this; + } + + public boolean containsErrors() { + return containsErrors; + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java similarity index 68% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java index 027938a..fa8dda0 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.core; +package dev.fyloz.trial.colorrecipesexplorer.core.io.response; public enum ResponseCode { SUCCESS_USING_MATERIALS(1, ResponseCodeType.SUCCESS, 0), @@ -18,7 +18,21 @@ public enum ResponseCode { COMPANY_LINKED(15, ResponseCodeType.ERROR, 1), MIX_NOT_ASSOCIATED_WITH_RECIPE(16, ResponseCodeType.ERROR, 2), NOT_ENOUGH_MATERIAL(17, ResponseCodeType.ERROR, 1), - MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1); + MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1), + MATERIAL_TYPE_NOT_FOUND(19, ResponseCodeType.ERROR, 1), + MATERIAL_TYPE_ALREADY_EXIST_PREFIX(20, ResponseCodeType.ERROR, 1), + MATERIAL_TYPE_LINKED(21, ResponseCodeType.ERROR, 1), + NO_COMPANY(22, ResponseCodeType.ERROR, 0), + NO_MATERIAL(23, ResponseCodeType.ERROR, 0), + FILE_NOT_IMAGE(24, ResponseCodeType.ERROR, 0), + RECIPE_NOT_FOUND_NO_PARAMS(25, ResponseCodeType.ERROR, 0), + MATERIAL_NOT_FOUND_BY_NAME(26, ResponseCodeType.ERROR, 1), + + // HTTP Errors + _500(100, ResponseCodeType.ERROR, 0), + _404(101, ResponseCodeType.ERROR, 0), + _401(102, ResponseCodeType.ERROR, 0), + ; public static final int MAX_PARAMETERS_NUMBER = 2; @@ -48,4 +62,5 @@ public enum ResponseCode { ERROR, SUCCESS } + } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java similarity index 79% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java index 50d23d4..19a55c8 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java @@ -1,12 +1,12 @@ -package fyloz.trial.ColorRecipesExplorer.core; +package dev.fyloz.trial.colorrecipesexplorer.core.io.response; -import fyloz.trial.ColorRecipesExplorer.model.*; +import dev.fyloz.trial.colorrecipesexplorer.core.model.*; import java.util.ArrayList; import java.util.HashMap; import java.util.stream.Stream; -public enum ModelDataType { +public enum ResponseDataType { MATERIAL("material", Material.class), MATERIALS("materials", ArrayList.class, MATERIAL), MATERIAL_ID("materialID", Integer.class), @@ -14,6 +14,7 @@ public enum ModelDataType { MATERIAL_TYPE("materialType", MaterialType.class), MATERIAL_TYPES("materialTypes", ArrayList.class, MATERIAL_TYPE), + MATERIAL_TYPE_NAME("materialTypeName", String.class), RECIPE("recipe", Recipe.class), RECIPES("recipes", ArrayList.class, RECIPE), @@ -40,17 +41,19 @@ public enum ModelDataType { COMPANY_NAME("companyName", String.class), IMAGE("image", String.class), - IMAGES("images", ArrayList.class, IMAGE); + IMAGES("images", ArrayList.class, IMAGE), + + BLOCK_BUTTON("blockButton", Boolean.class); private String dataTypeName; private Class dataType; private Class listDataType; - ModelDataType(String dataTypeName, Class dataType) { + ResponseDataType(String dataTypeName, Class dataType) { this(dataTypeName, dataType, null); } - ModelDataType(String dataTypeName, Class dataType, ModelDataType listDataType) { + ResponseDataType(String dataTypeName, Class dataType, ResponseDataType listDataType) { this.dataTypeName = dataTypeName; this.dataType = dataType; @@ -76,7 +79,7 @@ public enum ModelDataType { return getDataTypeName(); } - public static ModelDataType getModelDataTypeFromDataType(Class dataType) { + public static ResponseDataType getModelDataTypeFromDataType(Class dataType) { return Stream.of(values()).filter(r -> r.getDataType().equals(dataType)).findFirst().orElse(null); } } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java similarity index 56% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java index f374df9..a9a1690 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; public abstract class BeanModel { public abstract Integer getID(); diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java similarity index 96% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java index 63ed96b..a9650e1 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import org.hibernate.validator.constraints.Length; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java similarity index 98% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java index 2c25ae2..a796832 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import org.hibernate.annotations.ColumnDefault; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java similarity index 94% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java index 007ed60..e9140ce 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import org.hibernate.annotations.ColumnDefault; @@ -11,6 +11,8 @@ import java.util.Objects; @Entity public class MaterialType extends BeanModel implements Serializable { + public static final String DEFAULT_MATERIAL_TYPE_NAME = "Aucun"; + @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Integer materialTypeID; @@ -19,6 +21,7 @@ public class MaterialType extends BeanModel implements Serializable { @NotNull private String materialTypeName; + @Column(unique = true) @NotNull private String prefix; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java similarity index 95% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java index 6e77016..3d79705 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -23,7 +23,7 @@ public class Mix extends BeanModel implements Serializable { @ManyToOne private MixType mixType; - @OneToMany(mappedBy = "mix") + @OneToMany(mappedBy = "mix", cascade = CascadeType.ALL) private List mixQuantities; // Casier diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java similarity index 97% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java index dce9916..71694f1 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java similarity index 94% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java index a0c5f79..6c223bd 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -6,7 +6,7 @@ import java.io.Serializable; import java.util.Objects; @Entity -@Table(name = "mixTypes") +@Table(name = "mixTypes") // TODO retirer @Table public class MixType extends BeanModel implements Serializable { @Id diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java similarity index 94% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java index 286f71a..3c83fcc 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import com.fasterxml.jackson.annotation.JsonIgnore; import org.hibernate.validator.constraints.Length; @@ -6,6 +6,7 @@ import org.hibernate.validator.constraints.Length; import javax.persistence.*; import javax.validation.constraints.NotNull; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -38,10 +39,10 @@ public class Recipe extends BeanModel implements Serializable { private String note; @JsonIgnore - @OneToMany(mappedBy = "recipe") + @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL) private List recipeMixes; - @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL) + @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List recipeSteps; public Recipe() { @@ -131,7 +132,7 @@ public class Recipe extends BeanModel implements Serializable { } public List getRecipeSteps() { - return recipeSteps; + return recipeSteps == null ? new ArrayList<>() : recipeSteps; } public void setRecipeSteps(List recipeSteps) { diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java similarity index 95% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java index 3616b14..70117ce 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.model; +package dev.fyloz.trial.colorrecipesexplorer.core.model; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -15,7 +15,7 @@ public class RecipeStep extends BeanModel implements Serializable { @GeneratedValue(strategy = GenerationType.SEQUENCE) private int stepID; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JsonIgnore private Recipe recipe; diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java new file mode 100644 index 0000000..10586fb --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java @@ -0,0 +1,21 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.model.dto; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import lombok.Data; + +import java.util.List; + +@Data +public class MixCreationFormDto { + + private Recipe recipe; + + private String mixTypeName; + + private List materials; + + private List quantities; + + public MixCreationFormDto() { + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java similarity index 52% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java index 6e3d6f9..2acc38a 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java @@ -1,27 +1,29 @@ -package fyloz.trial.ColorRecipesExplorer.services; +package dev.fyloz.trial.colorrecipesexplorer.core.services; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication; -import fyloz.trial.ColorRecipesExplorer.model.BeanModel; +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel; import org.slf4j.Logger; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.lang.NonNull; import java.util.List; +import java.util.Optional; -public abstract class GenericService implements IGenericService { +public abstract class GenericService> implements IGenericService { - protected Logger logger = ColorRecipesExplorerApplication.logger; + protected Logger logger = ColorRecipesExplorerApplication.LOGGER; - protected JpaRepository dao; + protected R dao; - public GenericService(JpaRepository dao) { + public GenericService(R dao) { this.dao = dao; } @Override - public T getByID(int id) { - return dao.findById(id).get(); + public Optional getByID(int id) { + return dao.findById(id); } @Override @@ -30,36 +32,42 @@ public abstract class GenericService implements IGenericSer } @Override - public T save(T entity) { + public Optional save(T entity) { if (isValidForCreation(entity)) { - return dao.save(entity); + return Optional.of(dao.save(entity)); } - return null; + return Optional.empty(); } @Override - public boolean saveAll(List entities) { + public boolean saveAll(Iterable entities) { + if (entities == null) return false; + for (T e : entities) { - if (save(e) == null) { + if (!save(e).isPresent()) { return false; } } + dao.saveAll(entities); + return true; } @Override - public T update(T entity) { - if (exists(entity)) { - return dao.save(entity); + public Optional update(@NonNull T entity) { + if (isValidForUpdate(entity)) { + return Optional.of(dao.save(entity)); } - return null; + return Optional.empty(); } @Override public boolean delete(T entity) { + if (entity == null) return false; + if (exists(entity)) { dao.delete(entity); return true; @@ -70,12 +78,13 @@ public abstract class GenericService implements IGenericSer @Override public boolean deleteAll(List entities) { - for (T e : entities) { - if (!delete(e)) { - return false; - } + if (entities == null) return false; + + for (T entity : entities) { + if (!exists(entity)) return false; } + dao.deleteAll(entities); return true; } @@ -89,6 +98,16 @@ public abstract class GenericService implements IGenericSer return entity != null && !exists(entity); } + /** + * Vérifie si une entité est valide pour la création dans la base de données. + * + * @param entity L'entité à vérifier. + * @return Si l'entité est valide pour l'édition. + */ + public boolean isValidForUpdate(@NonNull T entity) { + return exists(entity); + } + /** * Vérifie si une entité existe dans la base de données. * @@ -97,7 +116,12 @@ public abstract class GenericService implements IGenericSer */ @Override public boolean exists(T entity) { - return dao.findById(entity.getID()).isPresent(); + return entity != null && existsById(entity.getID()); + } + + @Override + public boolean existsById(int id) { + return dao.existsById(id); } /** diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java similarity index 83% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java index 7dbae0f..45a2275 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java @@ -1,16 +1,17 @@ -package fyloz.trial.ColorRecipesExplorer.services; +package dev.fyloz.trial.colorrecipesexplorer.core.services; -import fyloz.trial.ColorRecipesExplorer.model.BeanModel; +import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; public interface IGenericService { /** * Récupère toutes les entités du même type dans la base de données. * - * @return Une liste de toutes les entités du même type. + * @return Une collection contenant toutes les entités du même type. */ List getAll(); @@ -20,7 +21,7 @@ public interface IGenericService { * @param id L'identifiant de l'entité * @return L'entité correspondant à l'identifiant. */ - T getByID(int id); + Optional getByID(int id); /** * Sauvegarde une entité dans la base de données. @@ -30,7 +31,7 @@ public interface IGenericService { * @param entity L'entité à sauvegarder * @return Si la sauvegarde a fonctionné. */ - T save(T entity); + Optional save(T entity); /** * Sauvegarde des entités dans la base de données. @@ -41,7 +42,7 @@ public interface IGenericService { * @return Si la sauvegarde a fonctionné. */ @Transactional - boolean saveAll(List entities); + boolean saveAll(Iterable entities); /** * Met à jour une entité dans la base de données. @@ -51,7 +52,7 @@ public interface IGenericService { * @param entity L'entité à mettre à jour * @return Si la mise à jour a fonctionné. */ - T update(T entity); + Optional update(T entity); /** * Supprime une entité dans la base de données. @@ -75,4 +76,6 @@ public interface IGenericService { boolean deleteAll(List entities); boolean exists(T entity); + + boolean existsById(int id); } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java similarity index 65% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java index 4c094de..f230ded 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java @@ -1,10 +1,12 @@ -package fyloz.trial.ColorRecipesExplorer.services; +package dev.fyloz.trial.colorrecipesexplorer.core.services; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.Mix; -import fyloz.trial.ColorRecipesExplorer.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -32,12 +34,13 @@ public class InventoryService { } public boolean useMix(Mix mix, Map quantities) { - for (Material material : mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList())) { + List materials = mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList()); + for (Material material : materials) { if (!material.isMixType()) { float quantity = quantities.get(material); material.setInventoryQuantity(material.getInventoryQuantity() - quantity); - if (materialService.update(material) == null) return false; + if (!materialService.update(material).isPresent()) return false; } } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java similarity index 77% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java index 7cad7f5..306b562 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java @@ -1,9 +1,9 @@ -package fyloz.trial.ColorRecipesExplorer; +package dev.fyloz.trial.colorrecipesexplorer.core.services; import java.util.ArrayList; import java.util.List; -public class PasswordValidator { +public class PasswordService { private static List passwords = new ArrayList<>(); diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java new file mode 100644 index 0000000..bed4aa5 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java @@ -0,0 +1,40 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.CompanyDao; +import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CompanyService extends GenericService { + + private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...) + + @Autowired + public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) { + super(companyDao); + this.recipeDao = recipeDao; + } + + @Override + public boolean isValidForCreation(Company entity) { + return super.isValidForCreation(entity) && !existsByName(entity.getCompanyName()); + } + + public boolean existsByName(String name) { + return dao.existsByCompanyName(name); + } + + public boolean isLinkedToRecipes(Company company) { + return !recipeDao.findAllByCompany(company).isEmpty(); + } + + public boolean deleteIfNotLinked(Company company) { + if (company == null) return false; + if (isLinkedToRecipes(company)) return false; + + return delete(company); + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java similarity index 58% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java index b4c4fd2..5f81a5d 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java @@ -1,17 +1,23 @@ -package fyloz.trial.ColorRecipesExplorer.services; +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; -import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler; -import fyloz.trial.ColorRecipesExplorer.dao.MaterialDao; -import fyloz.trial.ColorRecipesExplorer.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Service -public class MaterialService extends GenericService { +public class MaterialService extends GenericService { private MixQuantityService mixQuantityService; @@ -21,14 +27,14 @@ public class MaterialService extends GenericService { this.mixQuantityService = mixQuantityService; } - /** - * Récupère la produit ayant le code spécifié dans la base de données. - * - * @param materialCode Le code du produit - * @return Le produit correspondant au code. - */ - public Material getByMaterialCode(String materialCode) { - return ((MaterialDao) dao).findByMaterialCode(materialCode); + public Optional getByMaterialCode(String materialCode) { + return dao.findByMaterialCode(materialCode); + } + + public List getAllByMaterialType(MaterialType materialType) { + if (materialType == null) return new ArrayList<>(); + + return dao.findAllByMaterialType(materialType); } /** @@ -38,21 +44,43 @@ public class MaterialService extends GenericService { * @return Si le produit est lié à d'autres mélanges. */ public boolean isLinkedToMixes(Material material) { - return !mixQuantityService.getByMaterial(material).isEmpty(); + return mixQuantityService.existsByMaterial(material); } public boolean deleteIfNotLinked(Material material) { if (!isLinkedToMixes(material)) { - return super.delete(material); + return delete(material); } return false; } @Override - public boolean exists(Material entity) { - Material material = getByMaterialCode(entity.getMaterialCode()); - return super.exists(entity) || material != null; + public boolean exists(Material material) { + return material != null && (super.exists(material) || dao.existsByMaterialCode(material.getMaterialCode())); + } + + @Override + public boolean isValidForUpdate(Material material) { + if (material == null) return false; + + Optional materialByCode = dao.findByMaterialCode(material.getMaterialCode()); + return super.isValidForUpdate(material) && (!materialByCode.isPresent() || material.getMaterialID().equals(materialByCode.get().getMaterialID())); + } + + public List getAllBySearchString(String searchString) { + return dao.findAllByMaterialCodeContainingIgnoreCase(searchString).stream().filter(m -> !m.isMixType()).collect(Collectors.toList()); + } + + /** + * Crée un FileHandler pour le produit passé en paramètre. + * + * @param material Le produit dont on veut créer un FileHandler + * @return Le FileHandler correspondant au produit. + */ + private FileHandler getFileHandlerForMaterial(Material material) { + String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode()); + return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF); } /** @@ -66,9 +94,9 @@ public class MaterialService extends GenericService { * @return Si le fichier SIMDUT à bien été créé ou non. */ public boolean addSimdut(MultipartFile simdut, Material material) { - if (simdut.getSize() <= 0) return true; + if (simdut.getSize() <= 0) return false; - FileHandler fileHandler = getFilesServiceForMaterial(material); + FileHandler fileHandler = getFileHandlerForMaterial(material); if (!fileHandler.createFile()) { return false; @@ -92,7 +120,7 @@ public class MaterialService extends GenericService { * @return Si la suppression du fichier SIMDUT s'est effectuée. */ public boolean removeSimdut(Material material) { - FileHandler fileHandler = getFilesServiceForMaterial(material); + FileHandler fileHandler = getFileHandlerForMaterial(material); if (fileHandler.getFile().exists()) { return fileHandler.deleteFile(); @@ -100,15 +128,4 @@ public class MaterialService extends GenericService { return true; } - - /** - * Crée un FileHandler pour le produit passé en paramètre. - * - * @param material Le produit dont on veut créer un FileHandler - * @return Le FileHandler correspondant au produit. - */ - private FileHandler getFilesServiceForMaterial(Material material) { - String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode()); - return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF); - } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java new file mode 100644 index 0000000..99aa914 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java @@ -0,0 +1,69 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialTypeDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class MaterialTypeService extends GenericService { + + private MaterialService materialService; + + @Autowired + public MaterialTypeService(MaterialTypeDao materialTypeDao, MaterialService materialService) { + super(materialTypeDao); + this.materialService = materialService; + } + + public boolean isLinkedToMaterials(MaterialType materialType) { + return !materialService.getAllByMaterialType(materialType).isEmpty(); + } + + public boolean deleteIfNotLinked(MaterialType materialType) { + if (!isLinkedToMaterials(materialType)) { + return delete(materialType); + } + + return false; + } + + @Override + public boolean isValidForCreation(MaterialType entity) { + return entity != null && !existsByName(entity.getMaterialTypeName()); + } + + @Override + public boolean isValidForUpdate(MaterialType materialType) { + return super.isValidForUpdate(materialType) + && isValidForUpdateName(materialType) + && isValidForUpdatePrefix(materialType); + } + + public boolean isValidForUpdateName(MaterialType materialType) { + Optional materialTypeByName = dao.findByMaterialTypeName(materialType.getMaterialTypeName()); + + return !materialTypeByName.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByName.get().getMaterialTypeID()); + } + + public boolean isValidForUpdatePrefix(MaterialType materialType) { + Optional materialTypeByPrefix = dao.findByPrefix(materialType.getPrefix()); + + return !materialTypeByPrefix.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByPrefix.get().getMaterialTypeID()); + } + + public Optional getByName(String name) { + return dao.findByMaterialTypeName(name); + } + + public Optional getDefaultMaterialType() { + return getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME); + } + + public boolean existsByName(String name) { + return getByName(name).isPresent(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java new file mode 100644 index 0000000..7774f78 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java @@ -0,0 +1,21 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MixQuantityDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MixQuantityService extends GenericService { + + @Autowired + public MixQuantityService(MixQuantityDao mixQuantityDao) { + super(mixQuantityDao); + } + + public boolean existsByMaterial(Material material) { + return dao.existsByMaterial(material); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java new file mode 100644 index 0000000..e83e7ba --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java @@ -0,0 +1,130 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.model.*; +import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MixDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +public class MixService extends GenericService { + + private MaterialService materialService; + private MixQuantityService mixQuantityService; + private MixTypeService mixTypeService; + private RecipeService recipeService; + + @Autowired + public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService, MixTypeService mixTypeService, RecipeService recipeService) { + super(mixDao); + this.materialService = materialService; + this.mixQuantityService = mixQuantityService; + this.mixTypeService = mixTypeService; + this.recipeService = recipeService; + } + + @Transactional + public ModelResponseBuilder create(MixCreationFormDto formDto, @NotNull Recipe recipe) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(); + + List materials = new ArrayList<>(); + for (String materialCode : formDto.getMaterials()) { + Optional found = materialService.getByMaterialCode(materialCode); + if (!found.isPresent()) { + return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode); + } + + materials.add(found.get()); + } + + Optional optionalMixType = mixTypeService.createByName(formDto.getMixTypeName()); + if (!optionalMixType.isPresent()) return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + + MixType mixType = optionalMixType.get(); + if (recipeService.hasMixType(recipe, mixType)) + return modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, mixType.getTypeName()); + + // Crée le mélange en premier pour avoir accès à son ID pour les autres éléments + Mix mix = new Mix(recipe, mixType, null); + + Optional savedMix = save(mix); + if (savedMix.isPresent()) { + mix = savedMix.get(); + + List mixQuantities = createMixQuantities(savedMix.get(), materials, formDto.getQuantities()); + mix.setMixQuantities(mixQuantities); + + // Retourne aucune erreur s'il la mise à jour à lieu + if (update(mix).isPresent()) return null; + + deleteMix(mix); + } + + return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + } + + @Transactional + public ModelResponseBuilder edit(Mix mix, MixCreationFormDto formDto) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(); + + List materials = new ArrayList<>(); + for (String materialCode : formDto.getMaterials()) { + Optional found = materialService.getByMaterialCode(materialCode); + if (!found.isPresent()) { + return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode); + } + + materials.add(found.get()); + } + + List mixQuantities = createMixQuantities(mix, materials, formDto.getQuantities()); + + // Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données + if (!mixQuantityService.deleteAll(mix.getMixQuantities())) { + return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + } + + mix.setMixQuantities(mixQuantities); + if (update(mix).isPresent()) return null; + else return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + } + + public boolean deleteMix(Mix mix) { + if (mixQuantityService.deleteAll(mix.getMixQuantities())) { + return super.delete(mix); + } + + return false; + } + + /** + * Crée une liste de MixQuantity, pour la création d'un mélange + * + * @param mix Le mélange associé aux MixQuantity + * @param materials Les matériaux + * @param quantities Les quantités + * @return La liste des MixQuantity créés. + */ + public List createMixQuantities(Mix mix, List materials, List quantities) { + List mixQuantities = new ArrayList<>(); + + for (int i = 0; i < materials.size(); i++) { + Material material = materials.get(i); + float quantity = quantities.get(i); + + MixQuantity mixQuantity = new MixQuantity(mix, material, quantity); + mixQuantities.add(mixQuantity); + } + + return mixQuantities; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java new file mode 100644 index 0000000..dbd70c9 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java @@ -0,0 +1,46 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MixTypeDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class MixTypeService extends GenericService { + + private MaterialTypeService materialTypeService; + + @Autowired + public MixTypeService(MixTypeDao mixTypeDao, MaterialTypeService materialTypeService) { + super(mixTypeDao); + this.materialTypeService = materialTypeService; + } + + public Optional getByName(String name) { + return dao.findByTypeName(name); + } + + public Optional getByMaterial(Material material) { + return dao.findByMaterial(material); + } + + public Optional createByName(String name) { + Optional defaultType = materialTypeService.getDefaultMaterialType(); + if (!defaultType.isPresent()) return Optional.empty(); + + Optional mixTypeByName = getByName(name); + if (mixTypeByName.isPresent()) { + return mixTypeByName; + } + + Material mixTypeMaterial = new Material(name, 0, true, defaultType.get()); + MixType mixType = new MixType(name, mixTypeMaterial); + + return save(mixType); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java new file mode 100644 index 0000000..37aaa80 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java @@ -0,0 +1,196 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.model.*; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; + +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class RecipeService extends GenericService { + + private CompanyService companyService; + private StepService stepService; + + @Autowired + public RecipeService(RecipeDao recipeDao, CompanyService companyService, StepService stepService) { + super(recipeDao); + this.companyService = companyService; + this.stepService = stepService; + } + + /** + * Récupère la liste des recettes associées à une compagnie. + * + * @param company La compagnie. + * @return La liste des recettes associées à cette compagnie. + */ + public List getByCompany(Company company) { + return dao.findAllByCompany(company); + } + + /** + * Récupère une liste triée des mélanges pour une recette. + * + * @param recipe La recette dont on veut récupérer les mélanges + * @return Une liste triée des mélanges. + */ + public List getSortedMixes(Recipe recipe) { + List mixes = recipe.getRecipeMixes(); + mixes.sort(Comparator.comparing(Mix::getMixID)); + return mixes; + } + + /** + * Récupère toutes les recettes dans la base de données et les classes par compagnie. + * + * @return Un Map contenant les recettes classées par compagnie. + */ + public Map> getRecipesByCompany() { + return mappedByCompany(getAll()); + } + + public Optional updateRecipe(Recipe newRecipe, Recipe storedRecipe, MultiValueMap form) { + storedRecipe.setRecipeCode(newRecipe.getRecipeCode()); + storedRecipe.setCompany(newRecipe.getCompany()); + storedRecipe.setRecipeDescription(newRecipe.getRecipeDescription()); + storedRecipe.setSample(newRecipe.getSample()); + storedRecipe.setApprobationDate(newRecipe.getApprobationDate()); + storedRecipe.setRemark(newRecipe.getRemark()); + storedRecipe.setNote(newRecipe.getNote()); + + Optional optionalRecipe = convertAndCreateSteps(storedRecipe, form); + if (!optionalRecipe.isPresent()) { + return Optional.empty(); + } + + return update(optionalRecipe.get()); + } + + @Transactional + public boolean deleteRecipe(Recipe recipe) { + if (!delete(recipe)) return false; + return removeAllFiles(recipe); + } + + /** + * Récupère le nom des images liées à une recette. + * + * @param recipe La recette dont on veut récupérer les images + * @return Une liste contenant le nom des images liées à la recette. + */ + public List getImageFiles(Recipe recipe) { + int recipeID = recipe.getRecipeID(); + String recipeCode = recipe.getRecipeCode(); + String fileName = String.format("%s_%s", recipeID, recipeCode); + + File imageLocation = new File(ImageHandler.IMAGES_LOCATION); + File[] result = imageLocation.listFiles((d, n) -> n.startsWith(fileName) && n.endsWith("jpeg")); + + if (result == null) return new ArrayList<>(); + + return Arrays.stream(result).map(File::getName).collect(Collectors.toList()); + } + + /** + * Récupère les types de mélanges associés à la recette. + * + * @param recipe La recette dont on veut récupérer les types de mélange + * @return Une liste contenant les types de mélanges. + */ + public List getAssociatedMixesTypes(Recipe recipe) { + return recipe + .getRecipeMixes() + .stream() + .map(Mix::getMixType) + .collect(Collectors.toList()); + } + + /** + * Vérifie si une recette contient un mélange ayant le type de mélange spécifié. + * + * @param recipe La recette + * @param mixType Le type de mélange + * @return Si la recette contient le type de mélange + */ + public boolean hasMixType(Recipe recipe, MixType mixType) { + return getAssociatedMixesTypes(recipe) + .contains(mixType); + } + + public Map> getRecipesForSearchString(String searchString) { + List recipes = dao.findAllByRecipeDescriptionContainsOrRecipeCodeContains(searchString.toUpperCase()); + + return mappedByCompany(recipes); + } + + private Map> mappedByCompany(List recipes) { + List companies = companyService.getAll(); + Map> mappedRecipes = new HashMap<>(); + + for (Company c : companies) { + List recipesForCompany = recipes.stream().filter(r -> r.getCompany().equals(c)).collect(Collectors.toList()); + + if (recipesForCompany.size() > 0) { + mappedRecipes.put(c, recipesForCompany); + } + } + + return mappedRecipes; + } + + /** + * Crée et assigne des étapes à une recette, en se basant sur l'entrée de utilisateur. + * + * @param recipe La recette à assigner les étapes + * @param input L'entrée de l'utilisateur, contenant les étapes (key = "step_*") + * @return La recette avec les étapes. + */ + @Transactional + public Optional convertAndCreateSteps(Recipe recipe, MultiValueMap input) { + if (recipe == null || input == null) return Optional.empty(); + + // Convertit les étapes en RecipeSteps + List steps = new ArrayList<>(); + if (input.containsKey("step")) { + Object field = input.get("step"); + + if (field instanceof LinkedList && ((LinkedList) field).getFirst() instanceof String) { + for (String step : (LinkedList) field) { + steps.add(new RecipeStep(recipe, step)); + } + } + } + + return setSteps(recipe, steps); + } + + private Optional setSteps(Recipe recipe, List steps) { + if (!stepService.deleteAll(recipe.getRecipeSteps())) return Optional.empty(); + + recipe.setRecipeSteps(null); + update(recipe); + + recipe.setRecipeSteps(steps); + return Optional.of(recipe); + } + + private boolean removeAllFiles(Recipe recipe) { + FileHandler fileHandler; + for (String image : getImageFiles(recipe)) { + fileHandler = new FileHandler(image.replace(".jpeg", ""), FileHandler.FileContext.IMAGE, FileHandler.FileExtension.JPEG); + + if (!fileHandler.deleteFile()) return false; + } + + return true; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java new file mode 100644 index 0000000..8063109 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java @@ -0,0 +1,16 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services.model; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep; +import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService; +import dev.fyloz.trial.colorrecipesexplorer.dao.StepDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class StepService extends GenericService { + + @Autowired + public StepService(StepDao stepDao) { + super(stepDao); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java new file mode 100644 index 0000000..8685fd7 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java @@ -0,0 +1,26 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.utils; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; + +public class ControllerUtils { + + public static String redirect(String viewName) { + return String.format("redirect:/%s", viewName); + } + + public static String getCurrentBaseUrl() { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes == null) { + return null; + } + + HttpServletRequest request = attributes.getRequest(); + + String port = ":" + (ColorRecipesExplorerApplication.USE_PORT ? request.getServerPort() : ""); + return String.format("%s://%s%s%s", request.getScheme(), request.getServerName(), port, request.getContextPath()); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java new file mode 100644 index 0000000..be7277a --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java @@ -0,0 +1,22 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.utils; + +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.FileCopyUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class FileUtils { + + public static String readClasspathFile(ResourceLoader loader, String path) { + try (InputStream stream = loader.getResource(path).getInputStream()) { + byte[] data = FileCopyUtils.copyToByteArray(stream); + return new String(data, StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java similarity index 50% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java index 003e036..2785ed3 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java @@ -1,13 +1,11 @@ -package fyloz.trial.ColorRecipesExplorer.dao; +package dev.fyloz.trial.colorrecipesexplorer.dao; -import fyloz.trial.ColorRecipesExplorer.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface CompanyDao extends JpaRepository { - void deleteByCompanyID(int companyID); - - Company findByCompanyName(String companyName); + boolean existsByCompanyName(String companyName); } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java new file mode 100644 index 0000000..8014e54 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java @@ -0,0 +1,20 @@ +package dev.fyloz.trial.colorrecipesexplorer.dao; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface MaterialDao extends JpaRepository { + Optional findByMaterialCode(String materialCode); + + List findAllByMaterialType(MaterialType materialType); + + List findAllByMaterialCodeContainingIgnoreCase(String stringSearch); + + boolean existsByMaterialCode(String materialCode); +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java new file mode 100644 index 0000000..96ba4dc --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java @@ -0,0 +1,14 @@ +package dev.fyloz.trial.colorrecipesexplorer.dao; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface MaterialTypeDao extends JpaRepository { + + Optional findByMaterialTypeName(String name); + + Optional findByPrefix(String prefix); + +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java similarity index 62% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java index 729df1b..46a2b3c 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java @@ -1,7 +1,7 @@ -package fyloz.trial.ColorRecipesExplorer.dao; +package dev.fyloz.trial.colorrecipesexplorer.dao; -import fyloz.trial.ColorRecipesExplorer.model.Mix; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java similarity index 55% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java index 463a157..1a41d6a 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java @@ -1,7 +1,7 @@ -package fyloz.trial.ColorRecipesExplorer.dao; +package dev.fyloz.trial.colorrecipesexplorer.dao; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -9,7 +9,7 @@ import java.util.List; @Repository public interface MixQuantityDao extends JpaRepository { - MixQuantity findByMixQuantityID(int mixQuantityID); - List findAllByMaterial(Material material); + + boolean existsByMaterial(Material material); } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java new file mode 100644 index 0000000..5ae466d --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java @@ -0,0 +1,15 @@ +package dev.fyloz.trial.colorrecipesexplorer.dao; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface MixTypeDao extends JpaRepository { + Optional findByTypeName(String typeName); + + Optional findByMaterial(Material material); +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java new file mode 100644 index 0000000..7ed35d4 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java @@ -0,0 +1,22 @@ +package dev.fyloz.trial.colorrecipesexplorer.dao; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface RecipeDao extends JpaRepository { + + List findAllByCompany(Company company); + + Recipe findByRecipeCode(String recipeCode); + + Recipe findByRecipeID(int recipeID); + + @Query("select r from Recipe r where upper(r.recipeCode) like %?1% or upper(r.recipeDescription) like %?1%") + List findAllByRecipeDescriptionContainsOrRecipeCodeContains(String searchWordUpperCase); +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java similarity index 58% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java index 9d04a0a..5b998a7 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java @@ -1,7 +1,7 @@ -package fyloz.trial.ColorRecipesExplorer.dao; +package dev.fyloz.trial.colorrecipesexplorer.dao; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.model.RecipeStep; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java similarity index 69% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java index cf1dbbd..6000b93 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java @@ -1,17 +1,25 @@ -package fyloz.trial.ColorRecipesExplorer.web; +package dev.fyloz.trial.colorrecipesexplorer.web; public class PagesPaths { // Autres public static final String INDEX = "index"; + public static final String SEARCH = "search"; + public static final String SEARCH_INVENTORY = "inventory/search"; public static final String SIMDUT_FILES = "simdut/{materialID}"; public static final String PASSWORD_VALIDATION = "password/valid"; public static final String TOUCHUP = "touchup"; + public static final String RECIPE_XLS = "recipe/xls/{recipeID}"; + public static final String ALL_RECIPES_XLS = "recipe/xls"; + public static final String ERROR = "error"; + public static final String CLOSE_TAB = "closeTab"; + public static final String UPDATES = "updates"; + public static final String UPDATES_GET = "updates/get"; // Images public static final String IMAGES_FILES = "images/{image}"; public static final String ADD_IMAGE = "images/add"; public static final String ADD_IMAGE_SPECIFIC = "images/add/{recipeID}"; - public static final String DELETE_IMAGE = "images/deleteIfNotLinked"; + public static final String DELETE_IMAGE = "images/delete"; // Inventaire public static final String INVENTORY = "inventory"; @@ -47,6 +55,11 @@ public class PagesPaths { // Types de matériaux public static final String CREATOR_MATERIAL_TYPE = "materialType/creator"; + public static final String REMOVER_MATERIAL_TYPE = "materialType/remover"; + public static final String REMOVER_MATERIAL_TYPE_SPECIFIC = "materialType/remover/{materialTypeID}"; + public static final String EDITOR_MATERIAL_TYPE = "materialType/editor"; + public static final String EDITOR_MATERIAL_TYPE_SPECIFIC = "materialType/editor/{materialTypeID}"; + public static final String EDITOR_MATERIAL_TYPE_EDITOR = "materialType/edit"; // Mélanges public static final String CREATOR_MIX = "mix/creator"; @@ -54,4 +67,6 @@ public class PagesPaths { public static final String EDITOR_MIX = "mix/editor"; public static final String EDITOR_MIX_SPECIFIC = "mix/editor/{mixID}"; public static final String REMOVER_MIX_SPECIFIC = "mix/remover/{mixID}"; + public static final String MATERIAL_SELECTOR_MIX = "mix/selector/{recipeID}/{mixID}"; + public static final String MATERIAL_SELECTOR_FRAGMENT = "mix/selector.html :: materialSelector"; } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java similarity index 92% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java index ba3c1a6..598497d 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer.web; +package dev.fyloz.trial.colorrecipesexplorer.web; public class StringBank { @@ -48,8 +48,4 @@ public class StringBank { public static final String COMPANY = "company"; public static final String COMPANY_ID = "companyID"; - public static final String UPLOAD_LOCATION = System.getProperty("upload.location"); - public static final String IMAGES_LOCATION = UPLOAD_LOCATION + "/images"; - public static final String SIMDUTS_LOCATION = UPLOAD_LOCATION + "/simdut/"; - } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java new file mode 100644 index 0000000..51716fb --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java @@ -0,0 +1,51 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.RequestDispatcher; +import javax.servlet.http.HttpServletRequest; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.ERROR; + +@Controller +public class CREErrorController implements ErrorController { + + @RequestMapping("/error") + public ModelAndView handleError(HttpServletRequest request) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder("error"); + responseBuilder.addAttribute("referer", request.getHeader("referer")); + + Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + + ResponseCode responseCode = ResponseCode._500; + if (status != null) { + int statusCode = Integer.parseInt(status.toString()); + + switch (statusCode) { + case 401: + responseCode = ResponseCode._401; + break; + case 404: + responseCode = ResponseCode._404; + break; + default: + responseCode = ResponseCode._500; + break; + } + } + + responseBuilder.addResponseCode(responseCode); + return responseBuilder.build(); + } + + @Override + public String getErrorPath() { + return ERROR; + } + +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java similarity index 58% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java index 109e579..9cef050 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java @@ -1,12 +1,14 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; +package dev.fyloz.trial.colorrecipesexplorer.web.controller; -import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.core.io.ImageHandler; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -17,15 +19,13 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; +import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; -import java.util.HashMap; import java.util.Map; +import java.util.Optional; -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.ERROR_SAVING_IMAGE; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.RESPONSE_ERROR; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; @Controller public class ImageFilesController { @@ -68,9 +68,9 @@ public class ImageFilesController { */ @GetMapping(ADD_IMAGE_SPECIFIC) public ModelAndView showPage(ModelAndView model, @PathVariable int recipeID) { - return new ModelBuilder(model) - .setView(ADD_IMAGE) - .addData(ModelDataType.RECIPE_ID, recipeID) + return new ModelResponseBuilder(model) + .withView(ADD_IMAGE) + .addResponseData(ResponseDataType.RECIPE_ID, recipeID) .build(); } @@ -95,37 +95,45 @@ public class ImageFilesController { * @return La page à afficher. */ @PostMapping(ADD_IMAGE) - public ModelAndView addImage(int recipeID, MultipartFile image) { - ModelBuilder modelBuilder = new ModelBuilder(redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID)))); - Recipe recipe = recipeService.getByID(recipeID); + public ModelAndView addImage(int recipeID, MultipartFile image) throws IOException { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID)))); - if (recipe == null) { - modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)); - - return showPage(modelBuilder.build(), recipeID); + // Vérifie que le fichier est bien une image + if (ImageIO.read(image.getInputStream()) == null) { + return showPage(modelResponseBuilder + .addResponseCode(ResponseCode.FILE_NOT_IMAGE) + .build(), recipeID); } + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + return showPage(modelResponseBuilder + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID) + .build(), recipeID); + } + + Recipe recipe = optionalRecipe.get(); ImageHandler imageHandler = new ImageHandler(recipe, recipeService); if (!imageHandler.createFile()) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE); - - return showPage(modelBuilder.build(), recipeID); + return showPage(modelResponseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING_IMAGE) + .build(), recipeID); } - modelBuilder - .addData(ModelDataType.RECIPE_CODE, recipe.getRecipeCode()) - .addData(ModelDataType.RECIPE_ID, recipe.getRecipeID()); + modelResponseBuilder + .addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode()) + .addResponseData(ResponseDataType.RECIPE_ID, recipe.getRecipeID()); try { // Si je n'utilise pas le path, il cherche un fichier dans les tmp ? image.transferTo(new File(imageHandler.getFile().getAbsolutePath())); - return modelBuilder.build(); + return modelResponseBuilder.build(); } catch (IOException e) { - ColorRecipesExplorerApplication.logger.error("Erreur inconnue lors de la création d'une image", e); - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE); + ColorRecipesExplorerApplication.LOGGER.error("Erreur inconnue lors de la création d'une image", e); + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE); - return showPage(modelBuilder.build(), recipeID); + return showPage(modelResponseBuilder.build(), recipeID); } } @@ -142,18 +150,18 @@ public class ImageFilesController { * REQUIERT UNE AUTORISATION * * @param form Le formulaire contenant les informations sur l'opération - * @return La réponse sous forme de Map (-> Json) + * @return La réponse sous forme de Map (pour y accéder en Json) */ @PostMapping(value = DELETE_IMAGE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody - public Map deleteImage(@RequestBody Map form) { - Map response = new HashMap<>(); + public Map deleteImage(@RequestBody Map form) { + JSONResponseBuilder responseBuilder = new JSONResponseBuilder(); ImageHandler imageHandler = new ImageHandler(form.get("image"), recipeService); if (!imageHandler.deleteFile()) { - response.put(RESPONSE_ERROR, ERROR_SAVING_IMAGE); + responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE); } - return response; + return responseBuilder.build(); } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java new file mode 100644 index 0000000..cc51792 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java @@ -0,0 +1,81 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class IndexController { + + private CompanyService companyService; + private RecipeService recipeService; + + @Autowired + public IndexController(CompanyService companyService, RecipeService recipeService) { + this.companyService = companyService; + this.recipeService = recipeService; + } + + /** + * Affiche la page d'acceuil. + * + * @return La page à afficher. + */ + @GetMapping({INDEX, "/"}) + public ModelAndView showPage() { + List companies = companyService.getAll(); + Map> recipes = new HashMap<>(); + + for (Company company : companies) { + recipes.put(company, recipeService.getByCompany(company)); + } + + return new ModelResponseBuilder(INDEX) + .addResponseData(ResponseDataType.RECIPE_MAP, recipes) + .build(); + } + + @GetMapping(value = SEARCH, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Map searchWord(@RequestParam String searchString) { + Map> searchResult = recipeService.getRecipesForSearchString(searchString); + Map> outputResult = new HashMap<>(); + + for (Company c : searchResult.keySet()) { + outputResult.put(c.getCompanyID(), searchResult.get(c).stream().map(Recipe::getRecipeID).collect(Collectors.toList())); + } + + return new JSONResponseBuilder() + .addAttribute("result", outputResult) + .build(); + } + + /** + * Valide un mot de passe reçu dans une requête HTTP POST, dans le champ "password". + * + * @param data Corps de la requête HTTP + * @return Si le mot de passe est valide. + */ + @PostMapping(value = PASSWORD_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public boolean validatePassword(@RequestBody Map data) { + return PasswordService.isValid((String) data.get("password")); + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java similarity index 51% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java index bd9ea27..ed2ed89 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java @@ -1,33 +1,28 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; +package dev.fyloz.trial.colorrecipesexplorer.web.controller; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.Mix; -import fyloz.trial.ColorRecipesExplorer.model.MixQuantity; -import fyloz.trial.ColorRecipesExplorer.services.InventoryService; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService; -import fyloz.trial.ColorRecipesExplorer.services.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.services.InventoryService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.INVENTORY; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.USE_INVENTORY; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; +import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.RESPONSE_REASON; @Controller public class InventoryController { @@ -45,19 +40,12 @@ public class InventoryController { this.materialTypeService = materialTypeService; } - /** - * Affiche la page de l'inventaire. - *

- * Modèle de la page: - * - materials: Contient la liste de tous les matériaux - * - * @return La page à afficher. - */ @GetMapping(INVENTORY) public ModelAndView getInventory(ModelAndView model) { - return new ModelBuilder(INVENTORY) - .addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) - .addData(ModelDataType.MATERIAL_TYPES, materialTypeService.getAll()) + return new ModelResponseBuilder(model) + .withView(INVENTORY) + .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) + .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll()) .build(); } @@ -83,14 +71,14 @@ public class InventoryController { * - success: Contient le message à affiche lors du succès de la méthode * * @param form Le JSON contenant les quantités à utiliser. - * @return Une réponse sous forme de Map (-> Json). + * @return Une réponse sous forme de Map (vers Json). */ @PostMapping(value = USE_INVENTORY, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @Transactional - // TODO traduits les méthodes JSON - public Map consumeMaterials(@RequestBody Map form) { - Map response = new HashMap<>(); + // TODO traduit les méthodes JSON + public Map consumeMaterials(@RequestBody Map form) { + JSONResponseBuilder responseBuilder = new JSONResponseBuilder(); List mixes = new ArrayList<>(); Map> quantities = new HashMap<>(); @@ -98,12 +86,14 @@ public class InventoryController { for (String mixIDStr : form.keySet()) { int mixID = Integer.parseInt(mixIDStr); - Mix mix = mixService.getByID(mixID); - if (mix == null) { - response.put(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID)); - return response; + Optional optionalMix = mixService.getByID(mixID); + if (!optionalMix.isPresent()) { + return responseBuilder + .addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID) + .build(); } + Mix mix = optionalMix.get(); mixes.add(mix); Map formMaterials = (Map) form.get(mixIDStr); @@ -123,20 +113,36 @@ public class InventoryController { for (Mix mix : mixes) { String errorCode = inventoryService.checkQuantities(mix, quantities.get(mix)); if (errorCode != null) { - response.put(RESPONSE_ERROR, String.format(NOT_ENOUGH_MATERIAL, materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).getMaterialCode())); - response.put(RESPONSE_REASON, errorCode); - return response; + String materialCode = materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).orElse(new Material()).getMaterialCode(); + + return responseBuilder + .addResponseCode(ResponseCode.NOT_ENOUGH_MATERIAL, materialCode) + .addAttribute(RESPONSE_REASON, errorCode) + .build(); } } for (Mix mix : mixes) { if (!inventoryService.useMix(mix, quantities.get(mix))) { - response.put(RESPONSE_ERROR, ERROR_SAVING); - return response; + return responseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build(); } } - response.put(RESPONSE_SUCCESS, SUCCESS_USING_MATERIALS); - return response; + return responseBuilder + .addResponseCode(ResponseCode.SUCCESS_USING_MATERIALS) + .build(); + } + + @GetMapping(value = SEARCH_INVENTORY, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Map searchWordInventory(@RequestParam String searchString) { + List searchResult = materialService.getAllBySearchString(searchString); + List outputResult = searchResult.stream().map(Material::getMaterialID).collect(Collectors.toList()); + + return new JSONResponseBuilder() + .addAttribute("result", outputResult) + .build(); } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java new file mode 100644 index 0000000..e675c88 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java @@ -0,0 +1,169 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.FileUtils; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.XlsxExporter; +import org.commonmark.node.Node; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ResourceLoader; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; +import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MATERIALS; + +@Controller +public class OthersController { + + private RecipeService recipeService; + private MaterialService materialService; + private MixTypeService mixTypeService; + private MixService mixService; + private ResourceLoader resourceLoader; + + @Autowired + public OthersController(RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService, MixService mixService, ResourceLoader resourceLoader) { + this.recipeService = recipeService; + this.materialService = materialService; + this.mixTypeService = mixTypeService; + this.mixService = mixService; + this.resourceLoader = resourceLoader; + } + + @GetMapping(CLOSE_TAB) + public ModelAndView closeTab() { + return new ModelResponseBuilder(CLOSE_TAB).build(); + } + + @GetMapping(MATERIAL_SELECTOR_MIX) + public ModelAndView getMaterialSelectorFragment(@PathVariable int recipeID, @PathVariable int mixID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(MATERIAL_SELECTOR_FRAGMENT); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + return modelResponseBuilder + .withView("") + .build(); + } + + Optional optionalMix = mixService.getByID(mixID); + boolean mixExist = optionalMix.isPresent(); + + List associatedMixTypes = recipeService.getAssociatedMixesTypes(optionalRecipe.get()); + // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette + List materials = materialService + .getAll() + .stream() + .filter(m -> !m.isMixType() || (!mixExist || !m.equals(optionalMix.get().getMixType().getMaterial())) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get())) + .sorted(Comparator.comparing(Material::getMaterialCode)) + .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName())) + .collect(Collectors.toList()); + + return modelResponseBuilder + .addAttribute(MATERIALS, materials) + .build(); + } + + @GetMapping(TOUCHUP) + public ModelAndView getTouchUpPdf() { + return new ModelResponseBuilder().withRedirect("pdf/touchup.pdf").build(); + } + + @GetMapping(RECIPE_XLS) + public ResponseEntity getXlsForRecipe(HttpServletRequest request, @PathVariable int recipeID) { + HttpHeaders headers = new HttpHeaders(); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + headers.add(HttpHeaders.LOCATION, request.getHeader("referer")); + return new ResponseEntity<>(headers, HttpStatus.FOUND); + } + + byte[] recipeXLS = new XlsxExporter().generate(optionalRecipe.get()); + if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + + return ResponseEntity.ok() + .headers(headers) + .contentLength(recipeXLS.length) + .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) + .body(recipeXLS); + } + + @GetMapping(value = ALL_RECIPES_XLS, produces = "application/zip") + public ResponseEntity getAllXls() throws IOException { + HttpHeaders headers = new HttpHeaders(); + + ColorRecipesExplorerApplication.LOGGER.info("Exportation de toutes les couleurs en XLS"); + + ByteArrayOutputStream byteOS = new ByteArrayOutputStream(); + ZipOutputStream out = new ZipOutputStream(byteOS); + + Collection recipes = recipeService.getAll(); + for (Recipe recipe : recipes) { + byte[] recipeXLS = new XlsxExporter().generate(recipe); + if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + + out.putNextEntry(new ZipEntry(String.format("%s_%s.xlsx", recipe.getCompany().getCompanyName(), recipe.getRecipeCode()))); + out.write(recipeXLS, 0, recipeXLS.length); + out.closeEntry(); + } + + out.close(); + + byte[] zipContent = byteOS.toByteArray(); + byteOS.close(); + + return ResponseEntity.ok() + .headers(headers) + .contentLength(zipContent.length) + .contentType(MediaType.parseMediaType("application/zip")) + .body(zipContent); + } + + @GetMapping(value = UPDATES) + public ModelAndView showUpdates() { + return new ModelResponseBuilder(UPDATES).build(); + } + + @GetMapping(value = UPDATES_GET, produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public ResponseEntity getUpdates() throws IOException { + String fileContent = FileUtils.readClasspathFile(resourceLoader, "classpath:updates.md"); + if (fileContent == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + + Parser parser = Parser.builder().build(); + Node document = parser.parse(fileContent); + HtmlRenderer renderer = HtmlRenderer.builder().build(); + + return new ResponseEntity<>(renderer.render(document), HttpStatus.OK); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java new file mode 100644 index 0000000..1e41a3b --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java @@ -0,0 +1,112 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.util.*; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class RecipeExplorerController { + + private RecipeService recipeService; + private MixService mixService; + + @Autowired + public RecipeExplorerController(RecipeService recipeService, MixService mixService) { + this.recipeService = recipeService; + this.mixService = mixService; + } + + /** + * Affiche la recette. + * Cette méthode requiert l'identifiant de la recette à affiche dans l'URL. + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + * - recipe: Contient la recette + * - mixes: Contient les mélanges associées à la recette + * - images: Contient la liste des noms des images associées à la recette + * + * @param recipeID L'identifiant de la recette + * @return La page à afficher. + */ + @GetMapping(EXPLORER_RECIPE_SPECIFIC) + public ModelAndView showRecipe(@PathVariable int recipeID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(EXPLORER_RECIPE); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + return modelResponseBuilder + .withView(INDEX) + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID) + .build(); + } + + Recipe recipe = optionalRecipe.get(); + List mixes = new ArrayList<>(recipe.getRecipeMixes()); // Convertit le PersistentBag en ArrayList + mixes.sort(Comparator.comparing(Mix::getMixID)); + + return modelResponseBuilder + .addResponseData(ResponseDataType.RECIPE, recipe) + .addResponseData(ResponseDataType.MIXES, mixes) + .addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe)) + .build(); + } + + @PostMapping(value = EXPLORER_RECIPE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Map saveRecipeInformations(@RequestBody Map form) { + JSONResponseBuilder responseBuilder = new JSONResponseBuilder(); + + int recipeID = Integer.parseInt(form.get("recipeID").toString()); + Map location = (Map) form.get("locations"); + String note = form.get("note").toString(); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + responseBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID); + } else { + Recipe recipe = optionalRecipe.get(); + + recipe.setNote(note); + recipeService.save(recipe); + } + + for (String mixIDStr : location.keySet()) { + int mixID = Integer.parseInt(mixIDStr); + + Optional optionalMix = mixService.getByID(mixID); + if (!optionalMix.isPresent()) { + responseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID); + } else { + Mix mix = optionalMix.get(); + + if (mix.getRecipe().getRecipeID() != recipeID) { + responseBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, mixID, recipeID); + } else { + mix.setLocation(location.get(mixIDStr)); + mixService.update(mix); + } + } + } + + if (!responseBuilder.containsErrors()) { + responseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_RECIPE_INFORMATIONS); + } + + return responseBuilder.build(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java new file mode 100644 index 0000000..0c2f046 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java @@ -0,0 +1,62 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.servlet.http.HttpServletRequest; +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CLOSE_TAB; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.SIMDUT_FILES; + +@Controller +public class SIMDUTFilesController { + + private MaterialService materialService; + + @Autowired + public SIMDUTFilesController(MaterialService materialService) { + this.materialService = materialService; + } + + @GetMapping(SIMDUT_FILES) + public ResponseEntity getFile(HttpServletRequest request, @PathVariable int materialID) { + Optional optionalMaterial = materialService.getByID(materialID); + HttpHeaders headers = new HttpHeaders(); + + if (!optionalMaterial.isPresent()) { + headers.add("Location", request.getHeader("referer")); + return new ResponseEntity<>(headers, HttpStatus.FOUND); + } + + FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF); + if (!fileHandler.isValid()) { + headers.add("Location", "/" + CLOSE_TAB); + return new ResponseEntity<>(headers, HttpStatus.FOUND); + } + + byte[] fileContent = fileHandler.readFile(); + headers.setContentType(MediaType.APPLICATION_PDF); + return new ResponseEntity<>(fileContent, headers, HttpStatus.OK); + } + + @PostMapping(SIMDUT_FILES) + public ResponseEntity getFile(@PathVariable int materialID) { + Optional optionalMaterial = materialService.getByID(materialID); + if (!optionalMaterial.isPresent()) return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + + FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF); + if (!fileHandler.isValid()) return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + return ResponseEntity.status(HttpStatus.FOUND).build(); + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java similarity index 54% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java index 7fc6e19..69c5328 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java @@ -1,10 +1,10 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.creators; +package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Company; -import fyloz.trial.ColorRecipesExplorer.services.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; @@ -14,9 +14,10 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.ModelAndView; import javax.validation.Valid; +import java.util.Optional; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS; @Controller public class CompanyCreatorController { @@ -28,16 +29,11 @@ public class CompanyCreatorController { this.companyService = companyService; } - /** - * Affiche la page de création d'une bannière. - * - * @return La page à afficher. - */ @GetMapping(CREATOR_COMPANY) public ModelAndView showCreationPage(ModelAndView model, Company company) { - return new ModelBuilder(model) - .setView(CREATOR_COMPANY) - .addData(ModelDataType.COMPANY, company) + return new ModelResponseBuilder(model) + .withView(CREATOR_COMPANY) + .addResponseData(ResponseDataType.COMPANY, company) .build(); } @@ -60,20 +56,22 @@ public class CompanyCreatorController { */ @PostMapping(value = CREATOR_COMPANY, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public ModelAndView createCompany(@ModelAttribute @Valid Company company) { - ModelBuilder modelBuilder = new ModelBuilder(CREATOR_COMPANY_SUCCESS); + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_COMPANY_SUCCESS); if (companyService.isValidForCreation(company)) { - if ((company = companyService.save(company)) != null) { - return modelBuilder - .addData(ModelDataType.COMPANY_NAME, company.getCompanyName()) + Optional savedCompany = companyService.save(company); + + if (savedCompany.isPresent()) { + return modelResponseBuilder + .addResponseData(ResponseDataType.COMPANY_NAME, savedCompany.get().getCompanyName()) .build(); } else { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); } } else { - modelBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, company.getCompanyName(), null); + modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_ALREADY_EXIST, company.getCompanyName()); } - return showCreationPage(modelBuilder.build(), company); + return showCreationPage(modelResponseBuilder.build(), company); } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java new file mode 100644 index 0000000..556ed6d --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java @@ -0,0 +1,89 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL; + +@Controller +public class MaterialCreatorController { + + private MaterialService materialService; + private MaterialTypeService materialTypeService; + + @Autowired + public MaterialCreatorController(MaterialService materialService, MaterialTypeService materialTypeService) { + this.materialService = materialService; + this.materialTypeService = materialTypeService; + } + + @GetMapping(CREATOR_MATERIAL) + public ModelAndView showCreationPage(ModelAndView model, Material material) { + return new ModelResponseBuilder(model) + .withView(CREATOR_MATERIAL) + .addResponseData(ResponseDataType.MATERIAL, material != null ? material : new Material()) + .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll()) + .build(); + } + + /** + * Permet à l'utilisateur de créer un produit. + *

+ * La création échouera si: + * - L'utilisateur n'est pas autorisé à effectuer cette action + * - Le produit existe déjà + * - Une erreur est survenue lors de la sauvegarde dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + * - materialCode: Contient le code de produit du produit créé + *

+ * REQUIERT UNE AUTORISATION + * + * @param material Le produit à créer + * @param simdut Le fichier SIMDUT du produit (optionnel) + * @return La page à afficher. + */ + @PostMapping(value = CREATOR_MATERIAL, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ModelAndView create(@Valid Material material, MultipartFile simdut) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(); + + if (!materialService.exists(material)) { + Optional savedMaterial = materialService.save(material); + + if (savedMaterial.isPresent()) { + material = savedMaterial.get(); + + modelResponseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode()); + + if (simdut.getSize() > 0 && !materialService.addSimdut(simdut, material)) { + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); + } + + return showCreationPage(modelResponseBuilder + .addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode()) + .build(), null); + } else { + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + } + } else { + modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode()); + } + + return showCreationPage(modelResponseBuilder.build(), material); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java new file mode 100644 index 0000000..3ffa255 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java @@ -0,0 +1,54 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL_TYPE; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.INDEX; + +@Controller +public class MaterialTypeCreatorController { + + private MaterialTypeService materialTypeService; + + @Autowired + public MaterialTypeCreatorController(MaterialTypeService materialTypeService) { + this.materialTypeService = materialTypeService; + } + + @GetMapping(CREATOR_MATERIAL_TYPE) + public ModelAndView showPage(ModelAndView model, MaterialType materialType) { + return new ModelResponseBuilder(model) + .withView(CREATOR_MATERIAL_TYPE) + .addResponseData(ResponseDataType.MATERIAL_TYPE, materialType == null ? new MaterialType() : materialType) + .build(); + } + + @PostMapping(CREATOR_MATERIAL_TYPE) + public ModelAndView create(@Valid MaterialType materialType) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(INDEX)); + + if (materialTypeService.isValidForCreation(materialType)) { + if (materialTypeService.save(materialType) != null) { + return modelResponseBuilder.build(); + } else { + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + } + } else { + modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName()); + } + + return showPage(modelResponseBuilder.build(), materialType); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java new file mode 100644 index 0000000..edfbee0 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java @@ -0,0 +1,128 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class MixCreatorController { + + private MixService mixService; + private RecipeService recipeService; + private MaterialService materialService; + private MixTypeService mixTypeService; + + @Autowired + public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService) { + this.mixService = mixService; + this.recipeService = recipeService; + this.materialService = materialService; + this.mixTypeService = mixTypeService; + } + + /** + * Affiche la page de création d'un mélange. + * Cette méthode requiert l'identifiant d'une recette dans l'URL. + * + * @param model Le Model injecté par Thymeleaf + * @param recipeID L'identifiant de la recette + * @return La page à afficher. + */ + @GetMapping(CREATOR_MIX_SPECIFIC) + public ModelAndView showCreationPage(ModelAndView model, @PathVariable int recipeID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model) + .withView(CREATOR_MIX); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + return modelResponseBuilder + .withView(ControllerUtils.redirect(EDITOR_RECIPE)) + .build(); + } + + Recipe recipe = optionalRecipe.get(); + + List associatedMixTypes = recipeService.getAssociatedMixesTypes(recipe); + // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette + List materials = materialService + .getAll() + .stream() + .filter(m -> !m.isMixType() || associatedMixTypes.contains(mixTypeService.getByMaterial(m).get())) + .sorted(Comparator.comparing(Material::getMaterialCode)) + .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName())) + .collect(Collectors.toList()); + + ModelResponseBuilder responseBuilder = modelResponseBuilder + .addResponseData(ResponseDataType.RECIPE, recipe) + .addAttribute("materialsJson", materialService.asJson(materials)); + + if (materialService.getAll().isEmpty()) { + responseBuilder.addResponseCode(ResponseCode.NO_MATERIAL) + .addResponseData(ResponseDataType.BLOCK_BUTTON, true); + } + + return responseBuilder.build(); + } + + /** + * Permet à l'utilisateur de créer un mélange. + *

+ * La création échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - La recette n'existe pas + * - Un des produits n'existe pas + * - Une erreur est survenue lors de la sauvegarde du type de mélange + * - Une erreur est survenue lors de la sauvegarde du mélange + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + *

+ * REQUIERT UNE AUTORISATION + * + * @param form La formulaire du mélange entré par l'utilisateur + * @return La page à afficher. + */ + @PostMapping(value = CREATOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public ModelAndView createMix(@ModelAttribute @Valid MixCreationFormDto formDto) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(); + + Recipe recipe = formDto.getRecipe(); + if (recipe == null) return modelResponseBuilder + .withRedirect(EDITOR_RECIPE) + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND_NO_PARAMS) + .build(); + + ModelResponseBuilder mixCreationResponse = mixService.create(formDto, recipe); + if (mixCreationResponse != null) + return showCreationPage(mixCreationResponse.build(), formDto.getRecipe().getRecipeID()); + + return modelResponseBuilder + .withRedirect(EDITOR_RECIPE_SPECIFIC, recipe.getRecipeID()) + .build(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java new file mode 100644 index 0000000..750a237 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java @@ -0,0 +1,77 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE_SUCCESS; + +@Controller +public class RecipeCreatorController { + + private RecipeService recipeService; + private CompanyService companyService; + + @Autowired + public RecipeCreatorController(RecipeService recipeService, CompanyService companyService) { + this.recipeService = recipeService; + this.companyService = companyService; + } + + @GetMapping(CREATOR_RECIPE) + public ModelAndView showCreationPage(ModelAndView model, Recipe recipe) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model) + .withView(CREATOR_RECIPE) + .addResponseData(ResponseDataType.COMPANIES, companyService.getAll()) + .addResponseData(ResponseDataType.RECIPE, recipe == null ? new Recipe() : recipe); + + if (companyService.getAll().isEmpty()) { + responseBuilder.addResponseCode(ResponseCode.NO_COMPANY) + .addResponseData(ResponseDataType.BLOCK_BUTTON, true); + } + + return responseBuilder.build(); + } + + /** + * Permet à l'utilisateur de créer une nouvelle recette. + *

+ * La création échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - Une erreur est survenue lors de la sauvegarde dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + *

+ * REQUIERT UNE AUTORISATION + * + * @param recipe La recette à créer + * @return La page à afficher. + */ + @PostMapping(value = CREATOR_RECIPE) + public ModelAndView createRecipe(@Valid Recipe recipe) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_RECIPE_SUCCESS); + + Optional savedRecipe = recipeService.save(recipe); + if (savedRecipe.isPresent()) { + return modelResponseBuilder + .addResponseData(ResponseDataType.RECIPE, savedRecipe.get()) + .build(); + } + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + + return showCreationPage(modelResponseBuilder.build(), recipe); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java new file mode 100644 index 0000000..17ca51f --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java @@ -0,0 +1,178 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Optional; +import java.util.stream.Collectors; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class MaterialEditorController { + + private MaterialService materialService; + private MaterialTypeService materialTypeService; + + @Autowired + public MaterialEditorController(MaterialService materialService, MaterialTypeService materialTypeService) { + this.materialService = materialService; + this.materialTypeService = materialTypeService; + } + + /** + * Affiche la page de tous les produits. + *

+ * Modèle de la page: + * - materials: La liste de tous les produits + * + * @param model Le Model injecté par Thymeleaf + * @return La page à afficher. + */ + @GetMapping(EDITOR_MATERIAL) + public ModelAndView listMaterials(ModelAndView model) { + return new ModelResponseBuilder(model) + .withView(EDITOR_MATERIAL) + .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) + .build(); + } + + @GetMapping(EDITOR_MATERIAL_SPECIFIC) + public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialID, Material material) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model) + .withView(EDITOR_MATERIAL_EDITOR); + + if (material.getMaterialCode() == null) { + Optional optionalMaterial = materialService.getByID(materialID); + + if (!optionalMaterial.isPresent()) { + return listMaterials( + responseBuilder + .addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID) + .build() + ); + } + + material = optionalMaterial.get(); + } + + return responseBuilder + .addResponseData(ResponseDataType.MATERIAL, material) + .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll()) + .build(); + } + + /** + * Permet à l'utilisateur de modifier un produit. + *

+ * La modification échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - Il n'y a aucun produit avec l'identifiant passé en paramètre + * - Une erreur est survenue lors de la mise à jour dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + * - materialCode: Contient le code du produit mit à jour + *

+ * REQUIERT UNE AUTORISATION + * + * @param material Le produit à mettre à jour + * @return La page à afficher. + */ + @PostMapping(value = EDITOR_MATERIAL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public ModelAndView saveEditedMaterial(Material material) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(""); + int materialID = material.getMaterialID(); + + if (!materialService.existsById(materialID)) { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID); + } else if (!materialService.isValidForUpdate(material)) { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode()); + + return showEditPage( + responseBuilder + .addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode()) + .build(), + materialID, material); + } else { + Optional updatedMaterial = materialService.update(material); + if (updatedMaterial.isPresent()) { + responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, updatedMaterial.get().getMaterialCode()); + } else { + return showEditPage( + responseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build(), + materialID, null); + } + } + + return listMaterials(responseBuilder.build()); + } + + /** + * Affiche la page d'upload d'un fichier SIMDUT pour un produit + * Cette méthode requiert l'identifiant du produit dans l'URL + *

+ * Modèle de la page: + * - materialID: Contient l'identifiant du produit + * + * @param model Le Model injecté par Thymeleaf + * @param materialID L'identifiant du produit à modifier le SIMDUT + * @return La page à afficher. + */ + @GetMapping(value = EDIT_MATERIAL_SIMDUT_SPECIFIC) + public ModelAndView chooseSIMDUTFile(ModelAndView model, @PathVariable int materialID) { + return new ModelResponseBuilder(model) + .withView(EDIT_MATERIAL_SIMDUT) + .addResponseData(ResponseDataType.MATERIAL_ID, materialID) + .build(); + } + + /** + * Sauvegarde le fichier SIMDUT d'un produit. + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + *

+ * REQUIERT UNE AUTORISATION + * + * @param materialID L'identifiant du produit + * @param simdut Le fichier SIMDUT uploadé + * @return La page à afficher. + */ + @PostMapping(value = EDIT_MATERIAL_SIMDUT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ModelAndView saveSIMDUT(int materialID, MultipartFile simdut) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect("material/editor/" + materialID)); + + Optional optionalMaterial = materialService.getByID(materialID); + if (!optionalMaterial.isPresent()) { + return chooseSIMDUTFile(modelResponseBuilder + .addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID) + .build(), + materialID); + } + + Material material = optionalMaterial.get(); + if (!materialService.removeSimdut(material) || !materialService.addSimdut(simdut, material)) { + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); + + return chooseSIMDUTFile(modelResponseBuilder.build(), materialID); + } + + return modelResponseBuilder.build(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java new file mode 100644 index 0000000..60e572d --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java @@ -0,0 +1,96 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class MaterialTypeEditorController { + + private MaterialTypeService materialTypeService; + + @Autowired + public MaterialTypeEditorController(MaterialTypeService materialTypeService) { + this.materialTypeService = materialTypeService; + } + + @GetMapping(EDITOR_MATERIAL_TYPE) + public ModelAndView listMaterialTypes(ModelAndView model) { + return new ModelResponseBuilder(model) + .withView(EDITOR_MATERIAL_TYPE) + .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll()) + .build(); + } + + @GetMapping(EDITOR_MATERIAL_TYPE_SPECIFIC) + public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialTypeID, MaterialType materialType) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model) + .withView(EDITOR_MATERIAL_TYPE_EDITOR); + + if (materialType.getMaterialTypeName() == null) { + Optional optionalMaterialType = materialTypeService.getByID(materialTypeID); + + if (!optionalMaterialType.isPresent()) { + return listMaterialTypes( + responseBuilder + .addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID) + .build() + ); + } + + materialType = optionalMaterialType.get(); + } + + return responseBuilder + .addResponseData(ResponseDataType.MATERIAL_TYPE, materialType) + .build(); + } + + @PostMapping(value = EDITOR_MATERIAL_TYPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public ModelAndView saveEditedMaterialType(MaterialType materialType) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(""); + int materialTypeID = materialType.getMaterialTypeID(); + + if (!materialTypeService.getByID(materialTypeID).isPresent()) { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID); + } else if (!materialTypeService.isValidForUpdateName(materialType)) { + return showEditPage( + responseBuilder + .addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName()) + .build(), + materialTypeID, materialType); + } else if (!materialTypeService.isValidForUpdatePrefix(materialType)) { + return showEditPage( + responseBuilder + .addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST_PREFIX, materialType.getPrefix()) + .build(), + materialTypeID, materialType); + } else { + Optional updatedMaterialType = materialTypeService.update(materialType); + if (updatedMaterialType.isPresent()) { + responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, updatedMaterialType.get().getMaterialTypeName()); + } else { + return showEditPage( + responseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build(), + materialTypeID, null); + } + } + + return listMaterialTypes(responseBuilder.build()); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java new file mode 100644 index 0000000..387f16f --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java @@ -0,0 +1,154 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; +import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MIX_ID; + +@Controller +public class MixEditorController { + + private MixService mixService; + private MaterialService materialService; + private RecipeService recipeService; + private MixTypeService mixTypeService; + + @Autowired + public MixEditorController(MixService mixService, MaterialService materialService, RecipeService recipeService, MixTypeService mixTypeService) { + this.mixService = mixService; + this.materialService = materialService; + this.recipeService = recipeService; + this.mixTypeService = mixTypeService; + } + + /** + * Affiche la page d'édition d'un mélange. + * Cette méthode requiert l'identifiant du mélange à modifier dans l'URL. + * + * @param model Le Model injecté par Thymeleaf + * @param mixID L'identifiant du mélange à modifier + * @return La page à afficher. + */ + @GetMapping(EDITOR_MIX_SPECIFIC) + public ModelAndView showPage(ModelAndView model, @PathVariable int mixID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model) + .withView(EDITOR_MIX_SPECIFIC.replaceAll("/\\{" + MIX_ID + "}", "")); + + Optional optionalMix = mixService.getByID(mixID); + if (!optionalMix.isPresent()) { + return modelResponseBuilder + .withView(ControllerUtils.redirect(EDITOR_RECIPE)) + .build(); + } + + Mix mix = optionalMix.get(); + List associatedMixTypes = recipeService.getAssociatedMixesTypes(mix.getRecipe()); + // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette + List materials = materialService + .getAll() + .stream() + .filter(m -> !m.isMixType() || (!m.equals(mix.getMixType().getMaterial()) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get()))) + .sorted(Comparator.comparing(Material::getMaterialCode)) + .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName())) + .collect(Collectors.toList()); + + return modelResponseBuilder + .addResponseData(ResponseDataType.MIX, mix) + .addResponseData(ResponseDataType.RECIPE_CODE, mix.getRecipe().getRecipeCode()) + .addAttribute("mixJson", materialService.asJson(mix)) + .addAttribute("materialsJson", materialService.asJson(materials)) + .build(); + } + + /** + * Permet à l'utilisateur de modifier un mélange. + *

+ * La mise à jour échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - Le mélange n'existe pas + * - Un des produits n'existe pas + * - Une erreur est survenue lors de la mise à jour dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + *

+ * REQUIERT UNE AUTORISATION + * + * @param form Le formulaire du mélange entré par l'utilisateur + * @return La page à afficher. + */ + @PostMapping(value = EDITOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public ModelAndView saveMix(@ModelAttribute @Valid MixCreationFormDto formDto, int mixID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(); + + Optional optionalMix = mixService.getByID(mixID); + if (!optionalMix.isPresent()) { + modelResponseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID); + + return showPage(modelResponseBuilder.build(), mixID); + } + + Mix mix = optionalMix.get(); + modelResponseBuilder.withRedirect(EDITOR_RECIPE_SPECIFIC, mix.getRecipe().getRecipeID()); + + ModelResponseBuilder editResult = mixService.edit(mix, formDto); + if (editResult != null) { + return showPage( + modelResponseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build(), + mixID); + } + + return modelResponseBuilder.build(); + } + + @GetMapping(REMOVER_MIX_SPECIFIC) + public ModelAndView deleteMix(@PathVariable int mixID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(""); + + Optional optionalMix = mixService.getByID(mixID); + if (!optionalMix.isPresent()) { + return showPage(modelResponseBuilder + .addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID) + .build(), + mixID); + } + + Mix mix = optionalMix.get(); + modelResponseBuilder.withView(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID())))); + + if (!mixService.deleteMix(mix)) { + modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING); + + return showPage(modelResponseBuilder.build(), mixID); + } + + return modelResponseBuilder.build(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java new file mode 100644 index 0000000..d26afc9 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java @@ -0,0 +1,125 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.servlet.ModelAndView; + +import java.util.ArrayList; +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*; + +@Controller +public class RecipeEditorController { + + private RecipeService recipeService; + private CompanyService companyService; + + @Autowired + public RecipeEditorController(RecipeService recipeService, CompanyService companyService) { + this.recipeService = recipeService; + this.companyService = companyService; + } + + /** + * Affiche la page listant toutes les recettes. + *

+ * Modèle de la page: + * - recipes: Contient un Map de toutes les recettes triées par compagnie + * + * @param model Le Model injecté par Thymeleaf + * @return La page à afficher. + */ + @GetMapping(EDITOR_RECIPE) + public ModelAndView listRecipes(ModelAndView model) { + return new ModelResponseBuilder(model) + .withView(EDITOR_RECIPE) + .addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany()) + .build(); + } + + @GetMapping(EDITOR_RECIPE_SPECIFIC) + public ModelAndView showEditPage(ModelAndView model, @PathVariable int recipeID, Recipe recipe) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model) + .withView(EDITOR_RECIPE_EDITOR); + + if (recipe.getRecipeCode() == null || recipe.getCompany() == null) { + Optional optionalRecipe = recipeService.getByID(recipeID); + + if (!optionalRecipe.isPresent()) { + return listRecipes( + modelResponseBuilder + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID) + .build() + ); + } + + recipe = optionalRecipe.get(); + } + + return modelResponseBuilder + .addResponseData(ResponseDataType.RECIPE, recipe) + .addResponseData(ResponseDataType.COMPANIES, companyService.getAll()) + .addResponseData(ResponseDataType.MIXES, new ArrayList<>(recipeService.getSortedMixes(recipe))) // Convertit le PersistentBag en ArrayList + .addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe)) + .addAttribute("recipeJSON", recipeService.asJson(recipe)) + .build(); + } + + /** + * Permet à l'utilisateur de modifier une recette. + *

+ * La mise à jour échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - La recette n'existe pas + * - Une erreur est survenue lors de la mise à jour dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + * - recipeCode: Contient la couleur d'une recette + *

+ * REQUIERT UNE AUTORISATION + * + * @param recipe La recette à modifier + * @param form Le formulaire entré par l'utilisateur + * @return La page à afficher. + */ + @PostMapping(value = EDITOR_RECIPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @Transactional + public ModelAndView saveRecipe(Recipe recipe, @RequestBody MultiValueMap form) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(""); + int recipeID = recipe.getRecipeID(); + + Optional optionalStoredRecipe = recipeService.getByID(recipeID); + if (!optionalStoredRecipe.isPresent()) { + return listRecipes( + modelResponseBuilder + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID) + .build()); + } + + Optional optionalRecipe = recipeService.updateRecipe(recipe, optionalStoredRecipe.get(), form); + if (optionalRecipe.isPresent()) { + modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, optionalRecipe.get().getRecipeCode()); + return listRecipes(modelResponseBuilder.build()); + } + + return listRecipes( + modelResponseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build()); + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java similarity index 56% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java index 30d9ae2..2d3212a 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java @@ -1,10 +1,10 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.removers; +package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Company; -import fyloz.trial.ColorRecipesExplorer.services.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -12,8 +12,10 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.ModelAndView; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC; +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC; @Controller public class CompanyRemoverController { @@ -36,9 +38,9 @@ public class CompanyRemoverController { */ @GetMapping(REMOVER_COMPANY) public ModelAndView showPage(ModelAndView model) { - return new ModelBuilder(model) - .setView(REMOVER_COMPANY) - .addData(ModelDataType.COMPANIES, companyService.getAll()) + return new ModelResponseBuilder(model) + .withView(REMOVER_COMPANY) + .addResponseData(ResponseDataType.COMPANIES, companyService.getAll()) .build(); } @@ -63,19 +65,21 @@ public class CompanyRemoverController { @PostMapping(REMOVER_COMPANY_SPECIFIC) public ModelAndView removeCompany(@PathVariable int companyID) { - ModelBuilder modelBuilder = new ModelBuilder(""); - Company company = companyService.getByID(companyID); + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(""); + + Optional optionalCompany = companyService.getByID(companyID); + if (optionalCompany.isPresent()) { + Company company = optionalCompany.get(); - if (companyService.exists(company)) { if (companyService.deleteIfNotLinked(company)) { - modelBuilder.addData(ModelDataType.COMPANY_NAME, company.getCompanyName()); + modelResponseBuilder.addResponseData(ResponseDataType.COMPANY_NAME, company.getCompanyName()); } else { - modelBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName()); + modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName()); } } else { - modelBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, String.valueOf(companyID)); + modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, companyID); } - return showPage(modelBuilder.build()); + return showPage(modelResponseBuilder.build()); } } diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java similarity index 54% rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java index 599a3c8..8e8f581 100644 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java @@ -1,10 +1,10 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.removers; +package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -12,10 +12,11 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.ModelAndView; +import java.util.Optional; import java.util.stream.Collectors; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC; @Controller public class MaterialRemoverController { @@ -35,9 +36,9 @@ public class MaterialRemoverController { */ @GetMapping(REMOVER_MATERIAL) public ModelAndView showPage(ModelAndView model) { - return new ModelBuilder(model) - .setView(REMOVER_MATERIAL) - .addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) + return new ModelResponseBuilder(model) + .withView(REMOVER_MATERIAL) + .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) .build(); } @@ -61,23 +62,25 @@ public class MaterialRemoverController { */ @PostMapping(REMOVER_MATERIAL_SPECIFIC) public ModelAndView removeMaterial(@PathVariable int materialID) { - ModelBuilder modelBuilder = new ModelBuilder(""); - Material material = materialService.getByID(materialID); + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(""); - if (material == null) { - modelBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, String.valueOf(materialID)); + Optional optionalMaterial = materialService.getByID(materialID); + if (!optionalMaterial.isPresent()) { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID); } else { + Material material = optionalMaterial.get(); + if (materialService.deleteIfNotLinked(material)) { - modelBuilder.addData(ModelDataType.MATERIAL_CODE, material.getMaterialCode()); + responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode()); if (!materialService.removeSimdut(material)) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); + responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); } } else { - modelBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode()); + responseBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode()); } } - return showPage(modelBuilder.build()); + return showPage(responseBuilder.build()); } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java new file mode 100644 index 0000000..facf9eb --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java @@ -0,0 +1,58 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE_SPECIFIC; + +@Controller +public class MaterialTypeRemoverController { + + private MaterialTypeService materialTypeService; + + @Autowired + + public MaterialTypeRemoverController(MaterialTypeService materialTypeService) { + this.materialTypeService = materialTypeService; + } + + @GetMapping(REMOVER_MATERIAL_TYPE) + public ModelAndView showPage(ModelAndView model) { + return new ModelResponseBuilder(model) + .withView(REMOVER_MATERIAL_TYPE) + .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll()) + .build(); + } + + @PostMapping(REMOVER_MATERIAL_TYPE_SPECIFIC) + public ModelAndView removeMaterialType(@PathVariable int materialTypeID) { + ModelResponseBuilder responseBuilder = new ModelResponseBuilder(""); + + Optional optionalMaterialType = materialTypeService.getByID(materialTypeID); + if (!optionalMaterialType.isPresent()) { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID); + } else { + MaterialType materialType = optionalMaterialType.get(); + + if (materialTypeService.deleteIfNotLinked(materialType)) { + responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, materialType.getMaterialTypeName()); + } else { + responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_LINKED, materialType.getMaterialTypeName()); + } + } + + return showPage(responseBuilder.build()); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java new file mode 100644 index 0000000..2bbc64c --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java @@ -0,0 +1,83 @@ +package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers; + +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode; +import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Optional; + +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE; +import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE_SPECIFIC; + +@Controller +public class RecipeRemoverController { + + private RecipeService recipeService; + + public RecipeRemoverController(RecipeService recipeService) { + this.recipeService = recipeService; + } + + /** + * Affiche la liste de toutes les recettes. + * + * @param model Le Model injecté par Thymeleaf + * @return La page à afficher. + */ + @GetMapping(REMOVER_RECIPE) + public ModelAndView listRecipes(ModelAndView model) { + return new ModelResponseBuilder(model) + .withView(REMOVER_RECIPE) + .addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany()) + .build(); + } + + /** + * Permet à l'utilisateur de supprimer une recette. + * Cette méthode requiert l'identifiant de la recette dans l'URL. + *

+ * La suppression échouera si: + * - L'utilisateur n'est pas autorisé à exécuter cette action + * - La recette n'existe pas + * - Une erreur est survenue lors de la suppression dans la base de données + *

+ * Modèle de la page: + * - error: Contient le message d'erreur, s'il y a lieu + * - recipeCode: Contient la couleur de la recette + *

+ * REQUIERT UNE AUTORISATION + * + * @param recipeID L'identifiant de la recette + * @return La page à afficher. + */ + @PostMapping(REMOVER_RECIPE_SPECIFIC) + public ModelAndView removeRecipe(@PathVariable int recipeID) { + ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(""); + + Optional optionalRecipe = recipeService.getByID(recipeID); + if (!optionalRecipe.isPresent()) { + return listRecipes( + modelResponseBuilder + .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID) + .build()); + } + + Recipe recipe = optionalRecipe.get(); + if (!recipeService.deleteRecipe(recipe)) { + return listRecipes( + modelResponseBuilder + .addResponseCode(ResponseCode.ERROR_SAVING) + .build()); + } + + modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode()); + return listRecipes(modelResponseBuilder.build()); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java new file mode 100644 index 0000000..3743cd0 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java @@ -0,0 +1,101 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Catalog; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Table; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.DescriptionCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.NoteCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.SectionTitleCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.TitleCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collection; + +public class XlsxExporter { + + public byte[] generate(Recipe recipe) { + ColorRecipesExplorerApplication.LOGGER.info(String.format("Génération du XLS de la couleur %s (%s)", recipe.getRecipeCode(), recipe.getRecipeID())); + + Document document = new Document(recipe.getRecipeCode()); + Sheet sheet = document.getSheet(); + registerCells(recipe, sheet); + + document.buildSheet(); + + byte[] output; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + document.write(outputStream); + output = outputStream.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return new byte[0]; + } + + return output; + } + + private void registerCells(Recipe recipe, Sheet sheet) { + // Header + sheet.registerCell(new TitleCell(recipe.getRecipeCode())); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Bannière")); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getCompany().getCompanyName())); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Description")); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRecipeDescription())); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Échantillon")); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_NUM, recipe.getSample())); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Date d'approbation")); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getApprobationDate())); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Remarque")); + sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRemark())); + + // Mélanges + Collection recipeMixes = recipe.getRecipeMixes(); + if (recipeMixes.size() > 0) { + sheet.registerCell(new SectionTitleCell("Recette")); + + for (Mix mix : recipeMixes) { + Table mixTable = new Table(4, mix.getMixQuantities().size() + 1, mix.getMixType().getTypeName()); + mixTable.setColumnName(0, "Quantité"); + mixTable.setColumnName(2, "Unités"); + + int row = 0; + for (MixQuantity mixQuantity : mix.getMixQuantities()) { + mixTable.setRowName(row, mixQuantity.getMaterial().getMaterialCode()); + mixTable.setContent(new Position(1, row + 1), mixQuantity.getQuantity()); + mixTable.setContent(new Position(3, row + 1), mixQuantity.getMaterial().getMaterialType().getUsePercentages() ? "%" : "mL"); + + row++; + } + + sheet.registerAllCells(mixTable.getCells()); + } + } + + // Étapes + Collection steps = recipe.getRecipeSteps(); + if (steps.size() > 0) { + sheet.registerCell(new SectionTitleCell("Étapes")); + Catalog stepsCatalog = new Catalog(); + + for (RecipeStep step : recipe.getRecipeSteps()) stepsCatalog.addContent(step.getStepMessage()); + + sheet.registerAllCells(stepsCatalog.getCells()); + } + + // Note + String note = recipe.getNote(); + if (note != null) { + sheet.registerCell(new SectionTitleCell("Note")); + sheet.registerCell(new NoteCell(recipe.getNote())); + } + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java new file mode 100644 index 0000000..43d2f21 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java @@ -0,0 +1,69 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFFont; + +public class CellBuilder { + + private Document document; + private Cell cell; + private XSSFCell xcell; + + public CellBuilder(Document document, Cell cell, int x, int y) { + this.document = document; + this.cell = cell; + + xcell = document.getSheet().getCell(cell, x, y, true); + } + + private void applyColor(IColoredCell cell, XSSFCellStyle style) { + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(cell.getBackgroundColor().getIndex()); + } + + private void applyFont(IFontCell cell, XSSFCellStyle style) { + XSSFFont font = document.createFont(); + font.setBold(cell.isBold()); + font.setColor(cell.getFontColor().getIndex()); + font.setFontHeightInPoints(cell.getFontHeight()); + + style.setFont(font); + if (cell.isCentered()) style.setAlignment(HorizontalAlignment.CENTER); + } + + private void applyStyle() { + XSSFCellStyle style = document.createCellStyle(); + style.setWrapText(true); + + if (cell instanceof IColoredCell) applyColor((IColoredCell) cell, style); + if (cell instanceof IFontCell) applyFont((IFontCell) cell, style); + + xcell.setCellStyle(style); + } + + private void applyContent() throws InvalidCellTypeException { + switch (cell.getType()) { + case STRING: + xcell.setCellValue(cell.getContentText()); + break; + case NUMERIC: + xcell.setCellValue(cell.getContentNum()); + break; + default: + throw new InvalidCellTypeException(cell.getType()); + } + } + + public void build() throws InvalidCellTypeException { + applyStyle(); + applyContent(); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java new file mode 100644 index 0000000..3269f39 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java @@ -0,0 +1,60 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.CellUtils; +import org.apache.poi.ss.util.CellRangeAddress; + +public class SheetBuilder { + + private Sheet sheet; + private Iterable cells; + + public SheetBuilder(Sheet sheet) { + this.sheet = sheet; + + cells = sheet.getRegisteredCells(); + } + + private void applyCellMerge(IBiggerCell cell, int x, int y) { + int width = cell.getWidth() - 1; + int height = cell.getHeight() - 1; + + sheet.getXSheet().addMergedRegion(new CellRangeAddress(y, y + height, x, x + width)); + } + + public void build() throws InvalidCellTypeException { + int x = 0; + int y = 0; + + for (Cell cell : cells) { + while (!CellUtils.isCellEmpty(sheet, x, y) || CellUtils.isCellInMergedCell(sheet, x, y)) { + x++; + + if (x >= Document.WIDTH) { + x = 0; + y++; + } + } + + new CellBuilder(sheet.getDocument(), cell, x, y).build(); + if (cell instanceof IBiggerCell) { + IBiggerCell biggerCell = (IBiggerCell) cell; + + applyCellMerge(biggerCell, x, y); + + x += biggerCell.getWidth() - 1; + } else { + x++; + } + + if (x >= Document.WIDTH) { + x = 0; + y++; + } + } + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java new file mode 100644 index 0000000..6a135bf --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java @@ -0,0 +1,73 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import org.apache.poi.ss.usermodel.CellType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class Catalog { + + private List content; + + public Catalog() { + content = new ArrayList<>(); + } + + public void addContent(String value) { + content.add(value); + } + + public Collection getCells() { + Collection cells = new ArrayList<>(); + + int index = 1; + for (String value : content) { + cells.add(new CatalogValueCell(String.format("%s. %s", index, value))); + + index++; + } + + return cells; + } + + private class CatalogValueCell extends Cell implements IBiggerCell, IFontCell { + + private String value; + + public CatalogValueCell(String value) { + super(CellType.STRING); + + this.value = value; + } + + @Override + public int getWidth() { + return Document.WIDTH; + } + + @Override + public int getHeight() { + return 1; + } + + @Override + public String getContentText() { + return value; + } + + @Override + public boolean isCentered() { + return false; + } + + @Override + public boolean isBold() { + return false; + } + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java new file mode 100644 index 0000000..93a9f65 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java @@ -0,0 +1,33 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component; + +import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.builder.SheetBuilder; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbookType; + +public class Document extends XSSFWorkbook { + + public static final int WIDTH = 8; + private static final XSSFWorkbookType WORKBOOK_TYPE = XSSFWorkbookType.XLSX; + + private Sheet sheet; + + public Document(String name) { + super(WORKBOOK_TYPE); + + sheet = new Sheet(this, createSheet(name)); + } + + public void buildSheet() { + try { + new SheetBuilder(sheet).build(); + } catch (InvalidCellTypeException e) { + ColorRecipesExplorerApplication.LOGGER.error("Une erreur est survenue lors de la génération du document: " + e.getLocalizedMessage()); + } + } + + public Sheet getSheet() { + return sheet; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java new file mode 100644 index 0000000..c006464 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java @@ -0,0 +1,84 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; + +import java.util.*; + +public class Sheet { + + private Document document; + private XSSFSheet xsheet; + + private Map rows; + private List registeredCells; + + Sheet(Document document, XSSFSheet xsheet) { + this.document = document; + this.xsheet = xsheet; + xsheet.setDefaultColumnWidth(xsheet.getDefaultColumnWidth() * 2); + + rows = new HashMap<>(); + registeredCells = new ArrayList<>(); + } + + public void registerCell(Cell cell) { + registeredCells.add(cell); + } + + public void registerAllCells(Collection cells) { + registeredCells.addAll(cells); + } + + public List getRegisteredCells() { + return registeredCells; + } + + public XSSFRow getRow(int rownum, boolean create) { + int rowSize = rows.keySet().size(); + + if (rowSize <= rownum) { + if (!create) return null; + + for (int i = rowSize; i <= rownum; i++) { + rows.put(i, xsheet.createRow(i)); + } + } + + return rows.get(rownum); + } + + public XSSFCell getCell(int rownum, int columnnum, CellType type, boolean create) { + XSSFRow row = getRow(rownum, create); +// List columns = rows.get(row); + int columnsSize = row.getLastCellNum(); + + if (columnsSize == -1) columnsSize = 0; + + if (columnsSize <= columnnum) { + if (!create) return null; + + for (int i = columnsSize; i <= columnnum; i++) { + row.createCell(i, type); + } + } + + return row.getCell(columnnum); + } + + public XSSFCell getCell(Cell cell, int x, int y, boolean create) { + return getCell(y, x, cell.getType(), create); + } + + public XSSFSheet getXSheet() { + return xsheet; + } + + public Document getDocument() { + return document; + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java new file mode 100644 index 0000000..01d84da --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java @@ -0,0 +1,276 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.IndexOutOfTableBoundsException; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.IndexedColors; + +import java.text.DecimalFormat; +import java.util.*; + +public class Table { + + private static DecimalFormat format = new DecimalFormat("#.###"); + + private int width; + private int height; + private int cellWidth; + + private Map content; + + private List columns; + private List rows; + + public Table(int width, int height, String name) { + this.width = width; + this.height = height; + + cellWidth = Document.WIDTH / width; + + content = new HashMap<>(); + columns = new ArrayList<>(); + rows = new ArrayList<>(); + + for (int row = 0; row < this.height; row++) { + for (int col = 0; col < this.width; col++) { + Position pos = new Position(col, row); + Cell cell; + + if (col == 0 && row == 0) { // Titre + cell = new TableNameCell(name, cellWidth); + } else if (col == 0 || row == 0) { // Colonnes/Rangée + cell = new TableSubNameCell("", cellWidth); + + if (col > 0) columns.add((TableSubNameCell) cell); + else rows.add((TableSubNameCell) cell); + } else { + cell = new TableStringValueCell("", cellWidth); + } + + content.put(pos, cell); + } + } + } + + public void setColumnName(int index, String name) { + int columnnum = columns.size() - 1; + if (columnnum < index) throw new IndexOutOfTableBoundsException(index, columnnum); + + columns.get(index).setName(name); + } + + /** + * @param index Index de la rangée (à partir de 0) + * @param name Nouveau nom de la rangée + * @throws IndexOutOfTableBoundsException La rangée à l'index défini est en dehors de la portée du tableau. + * @author + */ + public void setRowName(int index, String name) { + int rownum = rows.size() - 1; + if (rownum < index) throw new IndexOutOfTableBoundsException(index, rownum); + + rows.get(index).setName(name); + } + + public void setContent(Position position, String value) { + if (isInTableRange(position, this)) { + content.put(position, new TableStringValueCell(value, cellWidth)); + } + } + + public void setContent(Position position, double value) { + if (isInTableRange(position, this)) { + value = Double.parseDouble(format.format(value).replace(',', '.')); + content.put(position, new TableNumValueCell(value, cellWidth)); + } + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public Collection getCells() { + int col = 0; + int row = 0; + + Collection cells = new ArrayList<>(); + while (row < height) { + + while (col < width) { + Position pos = new Position(col, row); + + cells.add(content.get(pos)); + + col++; + } + + col = 0; + row++; + } + + return cells; + } + + public static boolean isInTableRange(Position position, Table table) { + int col = position.getColumn(); + int columnnum = table.getWidth() - 1; + if (col > columnnum) throw new IndexOutOfTableBoundsException(col, columnnum); + + int row = position.getRow(); + int rownum = table.getHeight() - 1; + if (row > rownum) throw new IndexOutOfTableBoundsException(row, rownum); + + return true; + } + + private class TableNameCell extends Cell implements IColoredCell, IFontCell, IBiggerCell { + + private final IndexedColors COLOR = IndexedColors.GREY_40_PERCENT; + + private String name; + private int width; + private int height = 2; + + public TableNameCell(String name, int width) { + super(CellType.STRING); + + this.name = name; + this.width = width; + } + + @Override + public String getContentText() { + return name; + } + + @Override + public IndexedColors getBackgroundColor() { + return COLOR; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + } + + private class TableSubNameCell extends Cell implements IFontCell, IBiggerCell, IColoredCell { + + private String name; + private int width; + private int height = 2; + + public TableSubNameCell(String name, int width) { + super(CellType.STRING); + + this.name = name; + this.width = width; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String getContentText() { + return name; + } + + @Override + public IndexedColors getBackgroundColor() { + return IndexedColors.GREY_25_PERCENT; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + } + + private class TableStringValueCell extends Cell implements IFontCell, IBiggerCell { + + private String value; + private int width; + private int height = 2; + + public TableStringValueCell(String value, int width) { + super(CellType.STRING); + + this.value = value; + this.width = width; + } + + @Override + public String getContentText() { + return value; + } + + @Override + public boolean isBold() { + return false; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + } + + private class TableNumValueCell extends Cell implements IFontCell, IBiggerCell { + + private double value; + private int width; + private int height = 2; + + public TableNumValueCell(double value, int width) { + super(CellType.NUMERIC); + + this.value = value; + this.width = width; + } + + @Override + public double getContentNum() { + return value; + } + + @Override + public boolean isBold() { + return false; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java new file mode 100644 index 0000000..1b2ee7d --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java @@ -0,0 +1,24 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells; + +import org.apache.poi.ss.usermodel.CellType; + +public class Cell { + + protected CellType type; + + public Cell(CellType type) { + this.type = type; + } + + public CellType getType() { + return type; + } + + public String getContentText() { + return ""; + } + + public double getContentNum() { + return 0.0d; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java new file mode 100644 index 0000000..0a1192b --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java @@ -0,0 +1,68 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.IndexedColors; + +public class DescriptionCell extends Cell implements IColoredCell, IBiggerCell, IFontCell { + + private static final int WIDTH_NAME = 2; + private static final int WIDTH_VALUE = 6; + private static final int HEIGHT = 2; + private static final IndexedColors BG_COLOR_NAME = IndexedColors.GREY_40_PERCENT; + private static final short FONT_HEIGHT = 18; + + private DescriptionCellType type; + private String valueStr; + private double valueNbr; + + public DescriptionCell(DescriptionCellType type, String value) { + super(CellType.STRING); + + this.type = type; + this.valueStr = value; + } + + public DescriptionCell(DescriptionCellType type, double value) { + super(CellType.NUMERIC); + + this.type = type; + this.valueNbr = value; + } + + @Override + public int getWidth() { + return type == DescriptionCellType.NAME ? WIDTH_NAME : WIDTH_VALUE; + } + + @Override + public int getHeight() { + return HEIGHT; + } + + @Override + public IndexedColors getBackgroundColor() { + return type == DescriptionCellType.NAME ? BG_COLOR_NAME : IndexedColors.WHITE1; + } + + @Override + public short getFontHeight() { + return FONT_HEIGHT; + } + + @Override + public String getContentText() { + return type != DescriptionCellType.VALUE_NUM ? valueStr : ""; + } + + @Override + public double getContentNum() { + return type == DescriptionCellType.VALUE_NUM ? valueNbr : 0.0d; + } + + public enum DescriptionCellType { + NAME, VALUE_STR, VALUE_NUM + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java new file mode 100644 index 0000000..c62bb09 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java @@ -0,0 +1,37 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import org.apache.poi.ss.usermodel.CellType; + +public class NoteCell extends Cell implements IBiggerCell, IFontCell { + + private String value; + + public NoteCell(String value) { + super(CellType.STRING); + + this.value = value; + } + + @Override + public int getWidth() { + return Document.WIDTH; + } + + @Override + public int getHeight() { + return Math.max(Math.abs(value.length() / 100), 1); + } + + @Override + public boolean isBold() { + return false; + } + + @Override + public String getContentText() { + return value.replaceAll("(.{100})", "$1\n"); + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java new file mode 100644 index 0000000..34e99ad --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java @@ -0,0 +1,56 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.IndexedColors; + + +public class SectionTitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell { + + private static final int WIDTH = Document.WIDTH; + private static final int HEIGHT = 2; + private static final IndexedColors BG_COLOR = IndexedColors.BLACK; + private static final IndexedColors FONT_COLOR = IndexedColors.WHITE; + private static final int FONT_HEIGHT = 24; + + private String title; + + public SectionTitleCell(String title) { + super(CellType.STRING); + + this.title = title.toUpperCase(); + } + + @Override + public int getWidth() { + return WIDTH; + } + + @Override + public int getHeight() { + return HEIGHT; + } + + @Override + public IndexedColors getBackgroundColor() { + return BG_COLOR; + } + + @Override + public IndexedColors getFontColor() { + return FONT_COLOR; + } + + @Override + public short getFontHeight() { + return FONT_HEIGHT; + } + + @Override + public String getContentText() { + return title; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java new file mode 100644 index 0000000..f215989 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java @@ -0,0 +1,60 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.IndexedColors; + +public class TitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell { + + private static final int WIDTH = Document.WIDTH; + private static final int HEIGHT = 3; + private static final CellType TYPE = CellType.STRING; + private static final IndexedColors FONT_COLOR = IndexedColors.WHITE; + private static IndexedColors BACKGROUND_COLOR = IndexedColors.BLACK; + + private String title; + + public TitleCell(String title) { + super(TYPE); + + this.title = title; + } + + @Override + public IndexedColors getBackgroundColor() { + return BACKGROUND_COLOR; + } + + @Override + public IndexedColors getFontColor() { + return FONT_COLOR; + } + + public Cell setColor(IndexedColors color) { + BACKGROUND_COLOR = color; + return this; + } + + @Override + public short getFontHeight() { + return 36; + } + + @Override + public int getWidth() { + return WIDTH; + } + + @Override + public int getHeight() { + return HEIGHT; + } + + @Override + public String getContentText() { + return title; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java new file mode 100644 index 0000000..4548a5e --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java @@ -0,0 +1,7 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles; + +public interface IBiggerCell { + int getWidth(); + + int getHeight(); +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java new file mode 100644 index 0000000..5bb741a --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java @@ -0,0 +1,7 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles; + +import org.apache.poi.ss.usermodel.IndexedColors; + +public interface IColoredCell { + IndexedColors getBackgroundColor(); +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java new file mode 100644 index 0000000..68bb7ec --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java @@ -0,0 +1,23 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles; + +import org.apache.poi.ss.usermodel.IndexedColors; + +public interface IFontCell { + + default IndexedColors getFontColor() { + return IndexedColors.BLACK; + } + + default short getFontHeight() { + return 14; + } + + default boolean isBold() { + return true; + } + + default boolean isCentered() { + return true; + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java new file mode 100644 index 0000000..ddd984a --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java @@ -0,0 +1,9 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception; + +public class IndexOutOfTableBoundsException extends RuntimeException { + + public IndexOutOfTableBoundsException(int current, int max) { + super(String.format("L'index '%s' se trouve hors de portée du tableau (maximum: %s)", current, max)); + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java new file mode 100644 index 0000000..57ed8d0 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java @@ -0,0 +1,11 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception; + +import org.apache.poi.ss.usermodel.CellType; + +public class InvalidCellTypeException extends Exception { + + public InvalidCellTypeException(CellType type) { + super(String.format("Les recettes ne peuvent contenir que des cellules de type STRING et NUMERIC. Actuel: %s", type.name())); + } + +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java new file mode 100644 index 0000000..ead3106 --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java @@ -0,0 +1,52 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.util; + +import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.*; + +public class CellUtils { + public static XSSFColor getXSSFColor(int[] rgb) { + return new XSSFColor(new byte[]{(byte) rgb[0], (byte) rgb[1], (byte) rgb[2]}, new DefaultIndexedColorMap()); + } + + public static boolean isCellEmpty(Sheet sheet, int x, int y) { + XSSFRow row = sheet.getRow(y, false); + + if (row == null) { + return true; + } + + XSSFCell cell = row.getCell(x); + + if (cell == null) { // use row.getCell(x, Row.CREATE_NULL_AS_BLANK) to avoid null cells + return true; + } + + if (cell.getCellType() == CellType.BLANK) { + return true; + } + + if (cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty()) { + return true; + } + + return false; + } + + public static boolean isCellInMergedCell(Sheet sheet, int x, int y) { + XSSFSheet xsheet = sheet.getXSheet(); + + int numberOfMergedRegions = xsheet.getNumMergedRegions(); + + for (int i = 0; i < numberOfMergedRegions; i++) { + CellRangeAddress mergedCell = xsheet.getMergedRegion(i); + + if (mergedCell.isInRange(y, x)) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java new file mode 100644 index 0000000..5c4ba0c --- /dev/null +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java @@ -0,0 +1,49 @@ +package dev.fyloz.trial.colorrecipesexplorer.xlsx.util; + +import java.util.Objects; + +public class Position { + + private int column; + private int row; + + public Position(int column, int row) { + this.column = column; + this.row = row; + } + + public int getColumn() { + return column; + } + + public void setColumn(int column) { + this.column = column; + } + + public int getRow() { + return row; + } + + public void setRow(int row) { + this.row = row; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Position position = (Position) o; + return column == position.column && + row == position.row; + } + + @Override + public int hashCode() { + return Objects.hash(column, row); + } + + @Override + public String toString() { + return String.format("%s, %s", column, row); + } +} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java deleted file mode 100644 index deb400a..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java +++ /dev/null @@ -1,112 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.core; - -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.constraints.NotNull; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ModelBuilder { - - private static String RESPONSE_PREFIX = "response."; - private static String ERROR_ATTRIBUTE_NAME = "error"; - private static String SUCCESS_ATTRIBUTE_NAME = "success"; - - private ModelAndView model; - private Map modelAttributes; - - public ModelBuilder(String view) { - this(new ModelAndView(view)); - } - - public ModelBuilder(ModelAndView model) { - this.model = model == null ? new ModelAndView() : model; - - modelAttributes = new HashMap<>(); - } - - public ModelBuilder setView(String view) { - model.setViewName(view); - - return this; - } - - public ModelBuilder addAttribute(String attributeName, Object content) { - modelAttributes.put(attributeName, content); - - return this; - } - - public ModelBuilder addResponseCode(ResponseCode responseCode, String... parameters) { - int requiredParametersNumber = responseCode.getParametersNumber(); - int givenParametersNumber = parameters.length; - StringBuilder builder = new StringBuilder(); - - if (requiredParametersNumber != givenParametersNumber) { - throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans un réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber)); - } - - // Construit le code de réponse - builder.append(RESPONSE_PREFIX); - builder.append(responseCode.getCode()); - - // Ajoute les paramètres, si nécessaire - if (requiredParametersNumber > 0) { - builder.append("('"); - - for (int i = 0; i < givenParametersNumber; i++) { - builder.append(parameters[i]); - - if (i < givenParametersNumber - 1) { - builder.append("','"); - } - } - - builder.append("')"); - } - - // Ajoute l'attribut dans le Map - addAttribute(responseCode.getType() == ResponseCode.ResponseCodeType.ERROR ? ERROR_ATTRIBUTE_NAME : SUCCESS_ATTRIBUTE_NAME, builder.toString()); - addAttribute("arg1", "Bathia"); - addAttribute("arg2", "test"); - - return this; - } - - public ModelBuilder addData(ModelDataType modelDataType, @NotNull Object data) { - Class modelDataTypeClass = modelDataType.getDataType(); - Class modelListDataTypeClass = modelDataType.getListDataType(); - Class givenDataTypeClass = data.getClass(); - - // Vérifie le type de l'objet - if (!modelDataTypeClass.equals(givenDataTypeClass)) { - throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", modelDataTypeClass.getName(), givenDataTypeClass.getName())); - } - - // Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type - if (modelDataTypeClass.equals(List.class) && modelListDataTypeClass != null) { - List listData = (List) data; - - if (listData.size() < 1) { - throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément"); - } - - Class givenListDataTypeClass = listData.get(0).getClass(); - if (givenDataTypeClass.equals(modelListDataTypeClass)) { - throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", modelListDataTypeClass.getName(), givenListDataTypeClass.getName())); - } - } - - // Ajoute l'attribut dans le Map - addAttribute(modelDataType.getDataTypeName(), data); - - return this; - } - - public ModelAndView build() { - model.addAllObjects(modelAttributes); - - return model; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java deleted file mode 100644 index 1e098d7..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java +++ /dev/null @@ -1,8 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.core.utils; - -public class ControllerUtils { - - public static String redirect(String viewName) { - return String.format("redirect:/%s", viewName); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java deleted file mode 100644 index ce494dc..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java +++ /dev/null @@ -1,12 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.dao; - -import fyloz.trial.ColorRecipesExplorer.model.Material; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface MaterialDao extends JpaRepository { - Material findByMaterialID(int materialID); - - Material findByMaterialCode(String materialCode); -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java deleted file mode 100644 index dedbc81..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java +++ /dev/null @@ -1,10 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.dao; - -import fyloz.trial.ColorRecipesExplorer.model.MaterialType; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MaterialTypeDao extends JpaRepository { - - MaterialType findByMaterialTypeName(String name); - -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java deleted file mode 100644 index fe7d839..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.dao; - -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.MixType; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface MixTypeDao extends JpaRepository { - MixType findByTypeID(int id); - - MixType findByTypeName(String typeName); - - MixType findByMaterial(Material material); -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java deleted file mode 100644 index 4c87f35..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java +++ /dev/null @@ -1,18 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.dao; - -import fyloz.trial.ColorRecipesExplorer.model.Company; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface RecipeDao extends JpaRepository { - - List findAllByCompany(Company company); - - Recipe findByRecipeCode(String recipeCode); - - Recipe findByRecipeID(int recipeID); -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java deleted file mode 100644 index 17a40bd..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.factory.files; - -import com.itextpdf.text.Document; -import com.itextpdf.text.DocumentException; -import com.itextpdf.text.pdf.PdfWriter; -import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; - -public class PdfFactory { - - protected Document document; - - private String fileName; - private FileHandler fileHandler; - - public PdfFactory(String fileName) { - this(fileName, FileHandler.FileContext.OTHERS); - } - - public PdfFactory(String fileName, FileHandler.FileContext context) { - this.fileName = fileName; - - fileHandler = new FileHandler(fileName, context, FileHandler.FileExtension.PDF); - } - - public PdfFactory open() throws FileNotFoundException, DocumentException { - document = new Document(); - PdfWriter.getInstance(document, new FileOutputStream(fileHandler.getPath().toString())); - - document.open(); - - return this; - } - - public void write() { - document.close(); - } - - public FileHandler getFileHandler() { - return fileHandler; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java deleted file mode 100644 index ba7bff0..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.factory.files; - -import com.itextpdf.text.*; -import com.itextpdf.text.pdf.PdfWriter; -import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class TouchUpKitPdfFactory { - - private String kitName; - private ByteArrayOutputStream pdfContent; - private Document document; - - public TouchUpKitPdfFactory(String kitName) { - this.kitName = kitName.toUpperCase(); - - pdfContent = new ByteArrayOutputStream(); - document = new Document(); - } - - public TouchUpKitPdfFactory build() throws DocumentException { - ColorRecipesExplorerApplication.logger.info(String.format("Génération d'un PDF pour le kit de retouche '%s'", kitName)); - - PdfWriter.getInstance(document, pdfContent); - - Font descFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 48, BaseColor.BLACK); - Font kitNameFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, kitName.length() > 22 ? 32 : 38, BaseColor.BLACK); - - Paragraph descFr = new Paragraph("KIT DE RETOUCHE", descFont); - Paragraph descEn = new Paragraph("TOUCH UP KIT", descFont); - Paragraph touchUpKitName = new Paragraph(kitName, kitNameFont); - - descFr.setAlignment(Element.ALIGN_CENTER); - descEn.setAlignment(Element.ALIGN_CENTER); - touchUpKitName.setAlignment(Element.ALIGN_CENTER); - - document.open(); - document.add(descFr); - document.add(descEn); - document.add(touchUpKitName); - document.close(); - - return this; - } - - public byte[] toByteArray() { - byte[] content = pdfContent.toByteArray(); - - try { - pdfContent.close(); - } catch (IOException e) { - ColorRecipesExplorerApplication.logger.error("Une erreur est survenue lors de la fermeture d'un ByteArrayOutputStream", e); - } - - return content; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java deleted file mode 100644 index ed4ceb6..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java +++ /dev/null @@ -1,12 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.model.form; - -import org.springframework.web.multipart.MultipartFile; - -public class MaterialForm { - - private String materialCode; - - private int inventoryQuantity; - - private MultipartFile file; -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java deleted file mode 100644 index 2bb8fad..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java +++ /dev/null @@ -1,46 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.dao.CompanyDao; -import fyloz.trial.ColorRecipesExplorer.dao.RecipeDao; -import fyloz.trial.ColorRecipesExplorer.model.Company; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class CompanyService extends GenericService { - - private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...) - - @Autowired - public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) { - super(companyDao); - this.recipeDao = recipeDao; - } - - @Override - public boolean isValidForCreation(Company entity) { - return super.isValidForCreation(entity) && getByName(entity.getCompanyName()) == null; - } - - public Company getByName(String name) { - return ((CompanyDao) dao).findByCompanyName(name); - } - - /** - * Vérifie si une bannière est liée à une ou plusieurs recettes en faisant une requête dans la base de données, - * pour retourner s'il y a des résultats ou non. - * - * @return Si la bannière est liée à une ou plusieurs recettes. - */ - public boolean isLinkedToRecipes(Company company) { - return !recipeDao.findAllByCompany(company).isEmpty(); - } - - public boolean deleteIfNotLinked(Company company) { - if (!isLinkedToRecipes(company)) { - return super.delete(company); - } - - return false; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java deleted file mode 100644 index 30f0433..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java +++ /dev/null @@ -1,42 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.dao.MaterialTypeDao; -import fyloz.trial.ColorRecipesExplorer.model.MaterialType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class MaterialTypeService extends GenericService { - - private MaterialTypeDao materialTypeDao; - - @Autowired - public MaterialTypeService(MaterialTypeDao materialTypeDao) { - super(materialTypeDao); - this.materialTypeDao = materialTypeDao; - } - - @Override - public boolean isValidForCreation(MaterialType entity) { - return entity != null && !existsByName(entity); - } - - public MaterialType getByName(String name) { - return materialTypeDao.findByMaterialTypeName(name); - } - - public MaterialType getDefaultMaterialType() { - MaterialType defaultType = getByName("Aucun"); - - if (defaultType == null) { - defaultType = new MaterialType("Aucun", "", false); - save(defaultType); - } - - return defaultType; - } - - public boolean existsByName(MaterialType entity) { - return getByName(entity.getMaterialTypeName()) != null; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java deleted file mode 100644 index ca69086..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java +++ /dev/null @@ -1,31 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.dao.MixQuantityDao; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.MixQuantity; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class MixQuantityService extends GenericService { - - private MixQuantityDao mixQuantityDao; - - @Autowired - public MixQuantityService(MixQuantityDao mixQuantityDao) { - super(mixQuantityDao); - this.mixQuantityDao = mixQuantityDao; - } - - /** - * Récupère la liste des MixQuantity liées à un produit. - * - * @param material Le produit - * @return La page à afficher. - */ - public List getByMaterial(Material material) { - return mixQuantityDao.findAllByMaterial(material); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java deleted file mode 100644 index bd6d56b..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java +++ /dev/null @@ -1,114 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.dao.MixDao; -import fyloz.trial.ColorRecipesExplorer.model.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.ArrayList; -import java.util.List; - -@Service -public class MixService extends GenericService { - - private MaterialService materialService; - private MixQuantityService mixQuantityService; - - @Autowired - public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService) { - super(mixDao); - this.materialService = materialService; - this.mixQuantityService = mixQuantityService; - } - - /** - * Crée un mélange, ainsi que tous ses sous-éléments. - *

- * materials & quantities doivent avoir le même ordre. - * - * @param materials La liste des identifiants des matériaux - * @param quantities La liste des quantités de matériaux - * @param recipe La recette associée au mélange - * @param mixType Le type du mélange - * @return Le message d'erreur, s'il y a lieu - */ - @Transactional - public ModelBuilder create(ModelBuilder modelBuilder, List materials, List quantities, Recipe recipe, MixType mixType) { - // Crée le mélange en premier pour avoir accès à son ID pour les autres éléments - Mix mix = new Mix(recipe, mixType, null); - - if ((mix = save(mix)) != null) { - List mixQuantities = createMixQuantities(mix, materials, quantities); - if (mixQuantities == null) { - return modelBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND); - } - - if (mixQuantityService.saveAll(mixQuantities)) return null; - } - - return modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - } - - /** - * Modifie un mélange, ainsi que ses sous-éléments. - *

- * materials & quantities doivent avoir le même ordre. - * - * @param mix Le mélange à modifier - * @param materials La liste des identifiants des matériaux - * @param quantities La liste des quantités de matériaux - * @return Si le mélange a été modifier. - */ - public boolean edit(Mix mix, List materials, List quantities) { - List mixQuantities = createMixQuantities(mix, materials, quantities); - if (mixQuantities == null) return false; - - // Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données - if (!mixQuantityService.deleteAll(mix.getMixQuantities())) { - return false; - } - - return mixQuantityService.saveAll(mixQuantities); - } - - public boolean deleteMix(Mix mix) { - if (mixQuantityService.deleteAll(mix.getMixQuantities())) { - return super.delete(mix); - } - - return false; - } - - /** - * Crée une liste de MixQuantity, pour la création d'un mélange - * - * @param mix Le mélange associé aux MixQuantity - * @param materials Les matériaux - * @param quantities Les quantités - * @return La liste des MixQuantity créés. - */ - private List createMixQuantities(Mix mix, List materials, List quantities) { - List mixQuantities = new ArrayList<>(); - - int i = 0; - for (int materialID : materials) { - Material material = materialService.getByID(materialID); - - if (material == null) { - return null; - } - - float associatedQuantity = quantities.get(i); - - MixQuantity quantity = new MixQuantity(mix, material, associatedQuantity); - mixQuantities.add(quantity); - - i++; - } - - return mixQuantities; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java deleted file mode 100644 index 4eaf2c3..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java +++ /dev/null @@ -1,41 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.dao.MixTypeDao; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.MixType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class MixTypeService extends GenericService { - - private MixTypeDao mixTypeDao; - private MaterialTypeService materialTypeService; - - @Autowired - public MixTypeService(MixTypeDao mixTypeDao, MaterialTypeService materialTypeService) { - super(mixTypeDao); - this.mixTypeDao = mixTypeDao; - this.materialTypeService = materialTypeService; - } - - public MixType getByName(String name) { - return mixTypeDao.findByTypeName(name); - } - - public MixType getByMaterial(Material material) { - return mixTypeDao.findByMaterial(material); - } - - public MixType createByName(String name) { - Material mixTypeMaterial = new Material(name, 0, true, materialTypeService.getDefaultMaterialType()); - MixType mixType = new MixType(name, mixTypeMaterial); - - mixType = save(mixType); - if (mixType == null) { - return getByName(name); - } - - return mixType; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java deleted file mode 100644 index c2209a4..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java +++ /dev/null @@ -1,145 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler; -import fyloz.trial.ColorRecipesExplorer.dao.RecipeDao; -import fyloz.trial.ColorRecipesExplorer.model.*; -import fyloz.trial.ColorRecipesExplorer.web.StringBank; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.MultiValueMap; - -import java.io.File; -import java.util.*; -import java.util.stream.Collectors; - -@Service -public class RecipeService extends GenericService { - - private RecipeDao recipeDao; - private CompanyService companyService; - private StepService stepService; - private MixService mixService; - - @Autowired - public RecipeService(RecipeDao recipeDao, CompanyService companyService, StepService stepService, MixService mixService) { - super(recipeDao); - this.recipeDao = recipeDao; - this.companyService = companyService; - this.stepService = stepService; - this.mixService = mixService; - } - - /** - * Récupère la liste des recettes associées à une compagnie. - * - * @param company La compagnie. - * @return La liste des recettes associées à cette compagnie. - */ - public List getByCompany(Company company) { - return recipeDao.findAllByCompany(company); - } - - /** - * Crée et assigne des étapes à une recette, en se basant sur l'entrée de utilisateur. - * - * @param recipe La recette à assigner les étapes - * @param input L'entrée de l'utilisateur, contenant les étapes (key = "step_*") - * @return La recette avec les étapes. - */ - public Recipe createAndSetSteps(Recipe recipe, MultiValueMap input) { - List steps = new ArrayList<>(); - for (String key : input.keySet()) { - Object field = input.get(key); - if (key.startsWith("step_") && field instanceof LinkedList) { - steps.add(new RecipeStep(recipe, ((LinkedList) field).get(0).toString())); - } - } - - List recipeSteps = recipe.getRecipeSteps(); - if (recipeSteps != null) { - stepService.deleteAll(recipeSteps); - } - recipe.setRecipeSteps(steps); - save(recipe); - - return recipe; - } - - /** - * Supprime complètement une recette ainsi que les éléments qui y sont attachés de la base de données. - * - * @param recipe La recette à supprimer - */ - public void deleteRecipe(Recipe recipe) { - List mixes = recipe.getRecipeMixes(); - mixService.deleteAll(mixes); - - stepService.deleteAll(recipe.getRecipeSteps()); - delete(recipe); - - FileHandler fileHandler; - for (String image : getImageFiles(recipe)) { - fileHandler = new FileHandler(image.replace(".jpeg", ""), FileHandler.FileContext.IMAGE, FileHandler.FileExtension.JPEG); - fileHandler.deleteFile(); - } - } - - /** - * Récupère une liste triée des mélanges pour une recette. - * - * @param recipe La recette dont on veut récupérer les mélanges - * @return Une liste triée des mélanges. - */ - public List getSortedMixes(Recipe recipe) { - List mixes = recipe.getRecipeMixes(); - mixes.sort(Comparator.comparing(Mix::getMixID)); - return mixes; - } - - /** - * Récupère toutes les recettes dans la base de données et les classes par compagnie. - * - * @return Un Map contenant les recettes classées par compagnie. - */ - public Map> getRecipesByCompany() { - List companies = companyService.getAll(); - List recipes = getAll(); - - Map> mappedRecipes = new HashMap<>(); - - for (Company company : companies) { - mappedRecipes.put(company, recipes.stream().filter(r -> r.getCompany().equals(company)).collect(Collectors.toList())); - } - - return mappedRecipes; - } - - /** - * Récupère le nom des images liées à une recette. - * - * @param recipe La recette dont on veut récupérer les images - * @return Une liste contenant le nom des images liées à la recette. - */ - public List getImageFiles(Recipe recipe) { - int recipeID = recipe.getRecipeID(); - String recipeCode = recipe.getRecipeCode(); - String fileName = String.format("%s_%s", recipeID, recipeCode); - - File imageLocation = new File(StringBank.IMAGES_LOCATION); - File[] result = imageLocation.listFiles((d, n) -> n.startsWith(fileName) && n.endsWith("jpeg")); - - if (result == null) return null; - - return Arrays.stream(result).map(File::getName).collect(Collectors.toList()); - } - - /** - * Récupère les types de mélanges associés à la recette. - * - * @param recipe La recette dont on veut récupérer les types de mélange - * @return Une liste contenant les types de mélanges. - */ - public List getAssociatedMixesTypes(Recipe recipe) { - return recipe.getRecipeMixes().stream().map(Mix::getMixType).collect(Collectors.toList()); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/StepService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/StepService.java deleted file mode 100644 index f8dc210..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/StepService.java +++ /dev/null @@ -1,15 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.services; - -import fyloz.trial.ColorRecipesExplorer.dao.StepDao; -import fyloz.trial.ColorRecipesExplorer.model.RecipeStep; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class StepService extends GenericService { - - @Autowired - public StepService(StepDao stepDao) { - super(stepDao); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/IndexController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/IndexController.java deleted file mode 100644 index 4920e89..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/IndexController.java +++ /dev/null @@ -1,69 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; - -import fyloz.trial.ColorRecipesExplorer.PasswordValidator; -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.model.Company; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.CompanyService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.servlet.ModelAndView; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.INDEX; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.PASSWORD_VALIDATION; - -@Controller -public class IndexController { - - private CompanyService companyService; - private RecipeService recipeService; - - @Autowired - public IndexController(CompanyService companyService, RecipeService recipeService) { - this.companyService = companyService; - this.recipeService = recipeService; - } - - /** - * Affiche la page d'acceuil. - * - * @param model Le Model injecté par Thymeleaf - * @return La page à afficher. - */ - @GetMapping({INDEX, "/"}) - public ModelAndView showPage() { - List companies = companyService.getAll(); - Map> recipes = new HashMap<>(); - - for (Company company : companies) { - recipes.put(company, recipeService.getByCompany(company)); - } - - return new ModelBuilder(INDEX) - .addData(ModelDataType.RECIPE_MAP, recipes) - .build(); - } - - /** - * Valide un mot de passe reçu dans une requête HTTP POST, dans le champ "password". - * - * @param data Corps de la requête HTTP - * @return Si le mot de passe est valide. - */ - @PostMapping(value = PASSWORD_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public boolean validatePassword(@RequestBody Map data) { - return PasswordValidator.isValid((String) data.get("password")); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/OthersController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/OthersController.java deleted file mode 100644 index 3be55f5..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/OthersController.java +++ /dev/null @@ -1,17 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.servlet.ModelAndView; - -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.TOUCHUP; - -@Controller -public class OthersController { - @GetMapping(TOUCHUP) - public ModelAndView getTouchUpPdf() { - return new ModelBuilder(redirect("pdf/touchup.pdf")).build(); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/RecipeExplorerController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/RecipeExplorerController.java deleted file mode 100644 index 7f0471b..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/RecipeExplorerController.java +++ /dev/null @@ -1,120 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Mix; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.MixService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; - -import java.util.*; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*; - -@Controller -public class RecipeExplorerController { - - private RecipeService recipeService; - private MixService mixService; - - @Autowired - public RecipeExplorerController(RecipeService recipeService, MixService mixService) { - this.recipeService = recipeService; - this.mixService = mixService; - } - - /** - * Affiche la recette. - * Cette méthode requiert l'identifiant de la recette à affiche dans l'URL. - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - recipe: Contient la recette - * - mixes: Contient les mélanges associées à la recette - * - images: Contient la liste des noms des images associées à la recette - * - * @param recipeID L'identifiant de la recette - * @return La page à afficher. - */ - @GetMapping(EXPLORER_RECIPE_SPECIFIC) - public ModelAndView showRecipe(@PathVariable int recipeID) { - ModelBuilder modelBuilder = new ModelBuilder(EXPLORER_RECIPE); - Recipe recipe = recipeService.getByID(recipeID); - - if (recipe == null) { - return modelBuilder - .setView(INDEX) - .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)) - .build(); - } - - List mixes = new ArrayList<>(recipe.getRecipeMixes()); // Convertit le PersistentBag en ArrayList - mixes.sort(Comparator.comparing(Mix::getMixID)); - - return modelBuilder - .addData(ModelDataType.RECIPE, recipe) - .addData(ModelDataType.MIXES, mixes) - .addData(ModelDataType.IMAGES, recipeService.getImageFiles(recipe)) - .build(); - } - - /** - * Sauvegarde les informations de la recette. - *

- * Certaines parties de la sauvegarde échouera si: - * - La recette n'existe pas - * - Un des mélanges n'existe pas - * - Un des mélanges n'est pas associé à la recette - *

- * Réponse de la méthode: - * - error: Contient le message d'erreur, s'il y a lieu - * - success: Contient le message à afficher lors du succès de la méthode - * - * @param form Le formulaire contenant les informations de la recette - * @return La réponse sous forme de Map (-> Json) - */ - @PostMapping(value = EXPLORER_RECIPE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public Map saveRecipeInformations(@RequestBody Map form) { - int recipeID = Integer.parseInt(form.get("recipeID").toString()); - Map location = (Map) form.get("locations"); - String note = form.get("note").toString(); - - Map response = new HashMap<>(); - - Recipe recipe = recipeService.getByID(recipeID); - if (recipe == null) { - response.put(RESPONSE_ERROR, String.format(RECIPE_NOT_FOUND, recipeID)); - } else { - recipe.setNote(note); - recipeService.save(recipe); - } - - for (String mixIDStr : location.keySet()) { - int mixID = Integer.parseInt(mixIDStr); - - Mix mix = mixService.getByID(mixID); - if (mix == null) { - response.put(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID)); - } else if (mix.getRecipe().getRecipeID() != recipeID) { - response.put(RESPONSE_ERROR, String.format(MIX_NOT_ASSOCIATED_WITH_RECIPE, mixID, recipeID)); - } else { - mix.setLocation(location.get(mixIDStr)); - mixService.update(mix); - } - } - - if (response.get(RESPONSE_ERROR) == null) { - response.put(RESPONSE_SUCCESS, SUCCESS_SAVING_RECIPE_INFORMATIONS); - } - - return response; - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/SIMDUTFilesController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/SIMDUTFilesController.java deleted file mode 100644 index 7046482..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/SIMDUTFilesController.java +++ /dev/null @@ -1,53 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller; - -import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.SIMDUT_FILES; - -@Controller -public class SIMDUTFilesController { - - private MaterialService materialService; - - @Autowired - public SIMDUTFilesController(MaterialService materialService) { - this.materialService = materialService; - } - - /** - * Récupère le fichier SIMDUT voulu sous forme PDF. - * Cette méthode requiert l'identifiant du produit dans l'URL. - * - * @param materialID L'identifiant du produit - * @return Le fichier SIMDUT en PDF. - */ - @GetMapping(SIMDUT_FILES) - public ResponseEntity getFile(@PathVariable int materialID) { - Material material = materialService.getByID(materialID); - - if (material == null) { - return ResponseEntity.notFound().build(); - } - - HttpHeaders headers = new HttpHeaders(); - - FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, material.getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF); - if (!fileHandler.isValid()) { - return ResponseEntity.notFound().build(); - } - - byte[] fileContent = fileHandler.readFile(); - headers.setContentType(MediaType.APPLICATION_PDF); - return new ResponseEntity<>(fileContent, headers, HttpStatus.OK); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialCreatorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialCreatorController.java deleted file mode 100644 index 97dfd86..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialCreatorController.java +++ /dev/null @@ -1,88 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.creators; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.Valid; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_MATERIAL; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_MATERIAL_SUCCESS; - -@Controller -public class MaterialCreatorController { - - private MaterialService materialService; - private MaterialTypeService materialTypeService; - - @Autowired - public MaterialCreatorController(MaterialService materialService, MaterialTypeService materialTypeService) { - this.materialService = materialService; - this.materialTypeService = materialTypeService; - } - - /** - * Affiche la page de création d'un produit. - * - * @return La page à afficher. - */ - @GetMapping(CREATOR_MATERIAL) - public ModelAndView showCreationPage(ModelAndView model, Material material) { - return new ModelBuilder(model) - .setView(CREATOR_MATERIAL) - .addData(ModelDataType.MATERIAL, material != null ? material : new Material()) - .addData(ModelDataType.MATERIAL_TYPES, materialTypeService.getAll()) - .build(); - } - - /** - * Permet à l'utilisateur de créer un produit. - *

- * La création échouera si: - * - L'utilisateur n'est pas autorisé à effectuer cette action - * - Le produit existe déjà - * - Une erreur est survenue lors de la sauvegarde dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - materialCode: Contient le code de produit du produit créé - *

- * REQUIERT UNE AUTORISATION - * - * @param material Le produit à créer - * @param simdut Le fichier SIMDUT du produit (optionnel) - * @return La page à afficher. - */ - @PostMapping(value = CREATOR_MATERIAL, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ModelAndView create(@Valid Material material, MultipartFile simdut) { - ModelBuilder modelBuilder = new ModelBuilder(CREATOR_MATERIAL_SUCCESS); - - if (!materialService.exists(material)) { - if ((material = materialService.save(material)) != null) { - modelBuilder.addData(ModelDataType.MATERIAL_CODE, material.getMaterialCode()); - - if (!materialService.addSimdut(simdut, material)) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); - } - - return modelBuilder.build(); - } else { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - } - } else { - modelBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode()); - } - - return showCreationPage(modelBuilder.build(), material); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialTypeCreatorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialTypeCreatorController.java deleted file mode 100644 index e135c45..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MaterialTypeCreatorController.java +++ /dev/null @@ -1,54 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.creators; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.MaterialType; -import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.Valid; - -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_MATERIAL_TYPE; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.INDEX; - -@Controller -public class MaterialTypeCreatorController { - - private MaterialTypeService materialTypeService; - - @Autowired - public MaterialTypeCreatorController(MaterialTypeService materialTypeService) { - this.materialTypeService = materialTypeService; - } - - @GetMapping(CREATOR_MATERIAL_TYPE) - public ModelAndView showPage(ModelAndView model, MaterialType materialType) { - return new ModelBuilder(model) - .setView(CREATOR_MATERIAL_TYPE) - .addData(ModelDataType.MATERIAL_TYPE, materialType == null ? new MaterialType() : materialType) - .build(); - } - - @PostMapping(CREATOR_MATERIAL_TYPE) - public ModelAndView create(@Valid MaterialType materialType) { - ModelBuilder modelBuilder = new ModelBuilder(redirect(INDEX)); - - if (materialTypeService.isValidForCreation(materialType)) { - if (materialTypeService.save(materialType) != null) { - return modelBuilder.build(); - } else { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - } - } else { - modelBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, materialType.getMaterialTypeName()); - } - - return showPage(modelBuilder.build(), materialType); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MixCreatorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MixCreatorController.java deleted file mode 100644 index b63e950..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/MixCreatorController.java +++ /dev/null @@ -1,145 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.creators; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.MixType; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import fyloz.trial.ColorRecipesExplorer.services.MixService; -import fyloz.trial.ColorRecipesExplorer.services.MixTypeService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.servlet.ModelAndView; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.MIX_TYPE; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.RECIPE_ID; - -@Controller -public class MixCreatorController { - - private MixService mixService; - private RecipeService recipeService; - private MaterialService materialService; - private MixTypeService mixTypeService; - - @Autowired - public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService) { - this.mixService = mixService; - this.recipeService = recipeService; - this.materialService = materialService; - this.mixTypeService = mixTypeService; - } - - /** - * Affiche la page de création d'un mélange. - * Cette méthode requiert l'identifiant d'une recette dans l'URL. - * - * @param model Le Model injecté par Thymeleaf - * @param recipeID L'identifiant de la recette - * @return La page à afficher. - */ - @GetMapping(CREATOR_MIX_SPECIFIC) - public ModelAndView showCreationPage(ModelAndView model, @PathVariable int recipeID) { - ModelBuilder modelBuilder = new ModelBuilder(model) - .setView(CREATOR_MIX); - Recipe recipe = recipeService.getByID(recipeID); - - if (recipe == null) { - return modelBuilder - .setView(redirect(EDITOR_RECIPE)) - .build(); - } - - List associatedMixTypes = recipeService.getAssociatedMixesTypes(recipe); - // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette - List materials = materialService.getAll().stream().filter(m -> !m.isMixType() || associatedMixTypes.contains(mixTypeService.getByMaterial(m))).collect(Collectors.toList()); - - return modelBuilder - .addData(ModelDataType.RECIPE, recipe) - .addData(ModelDataType.MATERIALS, materials) - .addAttribute("materialsJson", materialService.asJson(materials)) - .build(); - } - - /** - * Permet à l'utilisateur de créer un mélange. - *

- * La création échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - La recette n'existe pas - * - Un des produits n'existe pas - * - Une erreur est survenue lors de la sauvegarde du type de mélange - * - Une erreur est survenue lors de la sauvegarde du mélange - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - *

- * REQUIERT UNE AUTORISATION - * - * @param form La formulaire du mélange entré par l'utilisateur - * @return La page à afficher. - */ - @PostMapping(value = CREATOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - public ModelAndView createMix(@RequestBody LinkedMultiValueMap form) { - String mixTypeName = form.get(MIX_TYPE).get(0); - int recipeID = Integer.parseInt(form.get(RECIPE_ID).get(0)); - - List materials = new ArrayList<>(); - List quantities = new ArrayList<>(); - // Trie les valeurs du formulaire de création du mélange - for (String key : form.keySet()) { - LinkedList value = (LinkedList) form.get(key); - - if (key.equals("product")) { - value.forEach(m -> materials.add(Integer.parseInt(m))); - } else if (key.equals("inventoryQuantity")) { - value.forEach(q -> quantities.add(Float.parseFloat(q))); - } - } - - ModelBuilder modelBuilder = new ModelBuilder(redirect(EDITOR_RECIPE_SPECIFIC.replaceAll("\\{" + RECIPE_ID + "}", String.valueOf(recipeID)))); - - Recipe recipe = recipeService.getByID(recipeID); - if (recipe == null) { - return modelBuilder - .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)) - .build(); - } - - MixType mixType = mixTypeService.createByName(mixTypeName); - if (mixType == null) { - return modelBuilder - .setView(EDITOR_RECIPE) - .addResponseCode(ResponseCode.ERROR_SAVING) - .build(); - } else if (recipeService.getAssociatedMixesTypes(recipe).contains(mixType)) { - return modelBuilder - .setView(EDITOR_RECIPE) - .addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED) - .build(); - } - - ModelBuilder creationResult = mixService.create(modelBuilder, materials, quantities, recipe, mixType); - if (creationResult != null) { - return showCreationPage(modelBuilder.build(), recipeID); - } - - return modelBuilder.build(); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/RecipeCreatorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/RecipeCreatorController.java deleted file mode 100644 index 4fa77db..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/RecipeCreatorController.java +++ /dev/null @@ -1,75 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.creators; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.CompanyService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.Valid; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_RECIPE; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_RECIPE_SUCCESS; - -@Controller -public class RecipeCreatorController { - - private RecipeService recipeService; - private CompanyService companyService; - - @Autowired - public RecipeCreatorController(RecipeService recipeService, CompanyService companyService) { - this.recipeService = recipeService; - this.companyService = companyService; - } - - /** - * Affiche la page de création d'une recette. - * - * @param model Le Model injecté par Thymeleaf - * @return La page à afficher. - */ - @GetMapping(CREATOR_RECIPE) - public ModelAndView showCreationPage(ModelAndView model, Recipe recipe) { - return new ModelBuilder(model) - .setView(CREATOR_RECIPE) - .addData(ModelDataType.COMPANIES, companyService.getAll()) - .addData(ModelDataType.RECIPE, recipe == null ? new Recipe() : recipe) - .build(); - } - - /** - * Permet à l'utilisateur de créer une nouvelle recette. - *

- * La création échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - Une erreur est survenue lors de la sauvegarde dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - *

- * REQUIERT UNE AUTORISATION - * - * @param recipe La recette à créer - * @return La page à afficher. - */ - @PostMapping(value = CREATOR_RECIPE) - public ModelAndView createRecipe(@Valid Recipe recipe) { - ModelBuilder modelBuilder = new ModelBuilder(CREATOR_RECIPE_SUCCESS); - - if ((recipe = recipeService.save(recipe)) != null) { - return modelBuilder - .addData(ModelDataType.RECIPE, recipe) - .build(); - } - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - - return showCreationPage(modelBuilder.build(), recipe); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MaterialEditorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MaterialEditorController.java deleted file mode 100644 index 4e02287..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MaterialEditorController.java +++ /dev/null @@ -1,165 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.editors; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.servlet.ModelAndView; - -import java.util.stream.Collectors; - -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; - -@Controller -public class MaterialEditorController { - - private MaterialService materialService; - private MaterialTypeService materialTypeService; - - @Autowired - public MaterialEditorController(MaterialService materialService, MaterialTypeService materialTypeService) { - this.materialService = materialService; - this.materialTypeService = materialTypeService; - } - - /** - * Affiche la page de tous les produits. - *

- * Modèle de la page: - * - materials: La liste de tous les produits - * - * @param model Le Model injecté par Thymeleaf - * @return La page à afficher. - */ - @GetMapping(EDITOR_MATERIAL) - public ModelAndView listMaterials(ModelAndView model) { - return new ModelBuilder(model) - .setView(EDITOR_MATERIAL) - .addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList())) - .build(); - } - - /** - * Affiche la page d'édition d'un produit. - * La méthode requiert l'identifiant du produit à modifier dans l'URL. - * - * @param model Le Model injecté par Thymeleaf - * @param materialID L'identifiant du produit à modifier - * @return La page à afficher. - */ - @GetMapping(EDITOR_MATERIAL_SPECIFIC) - public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialID) { - ModelBuilder modelBuilder = new ModelBuilder(model) - .setView(EDITOR_MATERIAL_EDITOR); - Material material = materialService.getByID(materialID); - - if (material == null) { - modelBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, String.valueOf(materialID)); - - return listMaterials(modelBuilder.build()); - } - - return modelBuilder - .addData(ModelDataType.MATERIAL, material) - .addData(ModelDataType.MATERIAL_TYPES, materialTypeService.getAll()) - .build(); - } - - /** - * Affiche la page d'upload d'un fichier SIMDUT pour un produit - * Cette méthode requiert l'identifiant du produit dans l'URL - *

- * Modèle de la page: - * - materialID: Contient l'identifiant du produit - * - * @param model Le Model injecté par Thymeleaf - * @param materialID L'identifiant du produit à modifier le SIMDUT - * @return La page à afficher. - */ - @GetMapping(value = EDIT_MATERIAL_SIMDUT_SPECIFIC) - public ModelAndView chooseSIMDUTFile(ModelAndView model, @PathVariable int materialID) { - return new ModelBuilder(model) - .setView(EDIT_MATERIAL_SIMDUT) - .addData(ModelDataType.MATERIAL_ID, materialID) - .build(); - } - - /** - * Sauvegarde le fichier SIMDUT d'un produit. - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - *

- * REQUIERT UNE AUTORISATION - * - * @param materialID L'identifiant du produit - * @param simdut Le fichier SIMDUT uploadé - * @return La page à afficher. - */ - @PostMapping(value = EDIT_MATERIAL_SIMDUT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ModelAndView saveSIMDUT(int materialID, MultipartFile simdut) { - ModelBuilder modelBuilder = new ModelBuilder(redirect("material/editor/" + materialID)); - Material material = materialService.getByID(materialID); - - if (material == null) { - modelBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, String.valueOf(materialID)); - - return chooseSIMDUTFile(modelBuilder.build(), materialID); - } - - if (!materialService.removeSimdut(material) || !materialService.addSimdut(simdut, material)) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT); - - return chooseSIMDUTFile(modelBuilder.build(), materialID); - } - - return modelBuilder.build(); - } - - /** - * Permet à l'utilisateur de modifier un produit. - *

- * La modification échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - Il n'y a aucun produit avec l'identifiant passé en paramètre - * - Une erreur est survenue lors de la mise à jour dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - materialCode: Contient le code du produit mit à jour - *

- * REQUIERT UNE AUTORISATION - * - * @param material Le produit à mettre à jour - * @return La page à afficher. - */ - @PostMapping(value = EDITOR_MATERIAL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - public ModelAndView saveEditedMaterial(Material material) { - ModelBuilder modelBuilder = new ModelBuilder(""); - int materialID = material.getMaterialID(); - - if (materialService.getByID(materialID) == null) { - modelBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, String.valueOf(materialID)); - } - - if ((material = materialService.update(material)) != null) { - modelBuilder.addData(ModelDataType.MATERIAL_CODE, material.getMaterialCode()); - } else { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - - return showEditPage(modelBuilder.build(), materialID); - } - - return listMaterials(modelBuilder.build()); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MixEditorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MixEditorController.java deleted file mode 100644 index eb92e3e..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/MixEditorController.java +++ /dev/null @@ -1,160 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.editors; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Material; -import fyloz.trial.ColorRecipesExplorer.model.Mix; -import fyloz.trial.ColorRecipesExplorer.model.MixType; -import fyloz.trial.ColorRecipesExplorer.services.MaterialService; -import fyloz.trial.ColorRecipesExplorer.services.MixService; -import fyloz.trial.ColorRecipesExplorer.services.MixTypeService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.servlet.ModelAndView; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; -import static fyloz.trial.ColorRecipesExplorer.web.StringBank.MIX_ID; - -@Controller -public class MixEditorController { - - private MixService mixService; - private MaterialService materialService; - private RecipeService recipeService; - private MixTypeService mixTypeService; - - @Autowired - public MixEditorController(MixService mixService, MaterialService materialService, RecipeService recipeService, MixTypeService mixTypeService) { - this.mixService = mixService; - this.materialService = materialService; - this.recipeService = recipeService; - this.mixTypeService = mixTypeService; - } - - /** - * Affiche la page d'édition d'un mélange. - * Cette méthode requiert l'identifiant du mélange à modifier dans l'URL. - * - * @param model Le Model injecté par Thymeleaf - * @param mixID L'identifiant du mélange à modifier - * @return La page à afficher. - */ - @GetMapping(EDITOR_MIX_SPECIFIC) - public ModelAndView showPage(ModelAndView model, @PathVariable int mixID) { - ModelBuilder modelBuilder = new ModelBuilder(model) - .setView(EDITOR_MIX_SPECIFIC.replaceAll("/\\{" + MIX_ID + "}", "")); - Mix mix = mixService.getByID(mixID); - - // Renvoie l'utilisateur à la page d'édition des recettes si le mélange n'est pas trouvé - if (mix == null) { - return modelBuilder - .setView(redirect(EDITOR_RECIPE)) - .build(); - } - - List materials = new ArrayList<>(); - List associatedMixTypes = recipeService.getAssociatedMixesTypes(mix.getRecipe()); - for (Material material : materialService.getAll()) { - if (!material.isMixType() || (!mix.getMixType().getMaterial().equals(material) && associatedMixTypes.contains(mixTypeService.getByMaterial(material)))) { - materials.add(material); - } - } - - return modelBuilder - .addData(ModelDataType.MIX, mix) - .addData(ModelDataType.RECIPE_CODE, mix.getRecipe().getRecipeCode()) - .addAttribute("mixJson", materialService.asJson(mix)) - .addAttribute("materialsJson", materialService.asJson(materials)) - .build(); - } - - /** - * Permet à l'utilisateur de modifier un mélange. - *

- * La mise à jour échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - Le mélange n'existe pas - * - Un des produits n'existe pas - * - Une erreur est survenue lors de la mise à jour dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - *

- * REQUIERT UNE AUTORISATION - * - * @param form Le formulaire du mélange entré par l'utilisateur - * @return La page à afficher. - */ - @PostMapping(value = EDITOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - public ModelAndView saveMix(@RequestBody LinkedMultiValueMap form) { - ModelBuilder modelBuilder = new ModelBuilder(""); - int mixID = Integer.parseInt((String) form.get(MIX_ID).get(0)); - - Mix mix = mixService.getByID(mixID); - if (mix == null) { - modelBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, String.valueOf(mixID)); - - return showPage(modelBuilder.build(), mixID); - } - - modelBuilder.setView(redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID())))); - - List materials = new ArrayList<>(); - List quantities = new ArrayList<>(); - - for (String key : form.keySet()) { - LinkedList value = (LinkedList) form.get(key); - // TODO Laisser ? - assert value != null : "Une valeur du formulaire d'édition d'un mélange est nulle."; - - if (key.equals("product")) { - value.forEach(m -> materials.add(Integer.parseInt(m))); - } else if (key.equals("inventoryQuantity")) { - value.forEach(q -> quantities.add(Float.parseFloat(q))); - } - } - - if (!mixService.edit(mix, materials, quantities)) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - - return showPage(modelBuilder.build(), mixID); - } - - return modelBuilder.build(); - } - - @GetMapping(REMOVER_MIX_SPECIFIC) - public ModelAndView deleteMix(@PathVariable int mixID) { - ModelBuilder modelBuilder = new ModelBuilder(""); - Mix mix = mixService.getByID(mixID); - - if (mix == null) { - modelBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, String.valueOf(mixID)); - - return showPage(modelBuilder.build(), mixID); - } - - modelBuilder.setView(redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID())))); - - if (!mixService.deleteMix(mix)) { - modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING); - - return showPage(modelBuilder.build(), mixID); - } - - return modelBuilder.build(); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/RecipeEditorController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/RecipeEditorController.java deleted file mode 100644 index a1d4cf6..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/editors/RecipeEditorController.java +++ /dev/null @@ -1,123 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.editors; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.CompanyService; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.Valid; -import java.util.ArrayList; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*; - -@Controller -public class RecipeEditorController { - - private RecipeService recipeService; - private CompanyService companyService; - - @Autowired - public RecipeEditorController(RecipeService recipeService, CompanyService companyService) { - this.recipeService = recipeService; - this.companyService = companyService; - } - - /** - * Affiche la page listant toutes les recettes. - *

- * Modèle de la page: - * - recipes: Contient un Map de toutes les recettes triées par compagnie - * - * @param model Le Model injecté par Thymeleaf - * @return La page à afficher. - */ - @GetMapping(EDITOR_RECIPE) - public ModelAndView listRecipes(ModelAndView model) { - return new ModelBuilder(model) - .addData(ModelDataType.RECIPE_MAP, recipeService.getRecipesByCompany()) - .build(); - } - - /** - * Affiche la page d'édition d'une recette. - * Cette méthode requiert l'identifiant de la recette dans l'URL. - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - recipe: Contient la recette - * - recipeJSON: Contient la recette sous forme de JSON - * - companies: Contient la liste des compagnies - * - mixes: Contient la liste des mélanges de la recettes, classées - * - images: Contient la liste des noms des images liées à la recette - * - * @param model Le Model injecté par Thymeleaf - * @param recipeID L'identifiant de la recette - * @return La page à afficher. - */ - @GetMapping(EDITOR_RECIPE_SPECIFIC) - public ModelAndView showEditPage(ModelAndView model, @PathVariable int recipeID) { - ModelBuilder modelBuilder = new ModelBuilder(model) - .setView(EDITOR_RECIPE_EDITOR); - Recipe recipe = recipeService.getByID(recipeID); - - if (recipe == null) { - modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)); - - return listRecipes(modelBuilder.build()); - } - - return modelBuilder - .addData(ModelDataType.RECIPE, recipe) - .addData(ModelDataType.COMPANIES, companyService.getAll()) - .addData(ModelDataType.MIXES, new ArrayList<>(recipeService.getSortedMixes(recipe))) // Convertit le PersistentBag en ArrayList - .addData(ModelDataType.IMAGES, recipeService.getImageFiles(recipe)) - .addAttribute("recipeJSON", recipeService.asJson(recipe)) - .build(); - } - - /** - * Permet à l'utilisateur de modifier une recette. - *

- * La mise à jour échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - La recette n'existe pas - * - Une erreur est survenue lors de la mise à jour dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - recipeCode: Contient la couleur d'une recette - *

- * REQUIERT UNE AUTORISATION - * - * @param recipe La recette à modifier - * @param form Le formulaire entré par l'utilisateur - * @return La page à afficher. - */ - @PostMapping(value = EDITOR_RECIPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - public ModelAndView saveRecipe(@Valid Recipe recipe, @RequestBody MultiValueMap form) { - ModelBuilder modelBuilder = new ModelBuilder(""); - int recipeID = recipe.getRecipeID(); - - if (recipeService.getByID(recipeID) == null) { - modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)); - - return listRecipes(modelBuilder.build()); - } - - recipe = recipeService.createAndSetSteps(recipe, form); - - modelBuilder.addData(ModelDataType.RECIPE_CODE, recipe.getRecipeCode()); - return listRecipes(modelBuilder.build()); - } -} diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/RecipeRemoverController.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/RecipeRemoverController.java deleted file mode 100644 index 05e2424..0000000 --- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/RecipeRemoverController.java +++ /dev/null @@ -1,76 +0,0 @@ -package fyloz.trial.ColorRecipesExplorer.web.controller.removers; - -import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder; -import fyloz.trial.ColorRecipesExplorer.core.ModelDataType; -import fyloz.trial.ColorRecipesExplorer.core.ResponseCode; -import fyloz.trial.ColorRecipesExplorer.model.Recipe; -import fyloz.trial.ColorRecipesExplorer.services.RecipeService; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.servlet.ModelAndView; - -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_RECIPE; -import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_RECIPE_SPECIFIC; - -@Controller -public class RecipeRemoverController { - - private RecipeService recipeService; - - public RecipeRemoverController(RecipeService recipeService) { - this.recipeService = recipeService; - } - - /** - * Affiche la liste de toutes les recettes. - * - * @param model Le Model injecté par Thymeleaf - * @return La page à afficher. - */ - @GetMapping(REMOVER_RECIPE) - public ModelAndView listRecipes(ModelAndView model) { - return new ModelBuilder(model) - .setView(REMOVER_RECIPE) - .addData(ModelDataType.RECIPES, recipeService.getRecipesByCompany()) - .build(); - } - - /** - * Permet à l'utilisateur de supprimer une recette. - * Cette méthode requiert l'identifiant de la recette dans l'URL. - *

- * La suppression échouera si: - * - L'utilisateur n'est pas autorisé à exécuter cette action - * - La recette n'existe pas - * - Une erreur est survenue lors de la suppression dans la base de données - *

- * Modèle de la page: - * - error: Contient le message d'erreur, s'il y a lieu - * - recipeCode: Contient la couleur de la recette - *

- * REQUIERT UNE AUTORISATION - * - * @param recipeID L'identifiant de la recette - * @return La page à afficher. - */ - @PostMapping(REMOVER_RECIPE_SPECIFIC) - public ModelAndView removeRecipe(@PathVariable int recipeID) { - ModelBuilder modelBuilder = new ModelBuilder(""); - Recipe recipe = recipeService.getByID(recipeID); - - // Affiche un erreur si le recette n'est pas trouvée - if (recipe == null) { - modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID)); - - return listRecipes(modelBuilder.build()); - } - - // TODO erreur dans cette méthode - recipeService.deleteRecipe(recipe); - - modelBuilder.addData(ModelDataType.RECIPE_CODE, recipe.getRecipeCode()); - return listRecipes(modelBuilder.build()); - } -} diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..6af452d --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,9 @@ +{ + "properties": [ + { + "name": "http.port", + "type": "java.lang.String", + "description": "Port HTTP." + } + ] +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 98716f3..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,33 +0,0 @@ -# Tomcat -server.port=8081 -# Favicon -spring.mvc.favicon.enabled=false -# H2 -spring.datasource.url=jdbc:h2:file:./recipes -spring.datasource.username=sa -spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect -spring.datasource.driver-class-name=org.h2.Driver -# JPA -#spring.jpa.show-sql=true -spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.format_sql=false -# Thymeleaf -spring.thymeleaf.template-loader-path=classpath:/templates -spring.thymeleaf.suffix=.html -spring.thymeleaf.cache=false -# Messages -spring.messages.fallback-to-system-locale=false -#spring.messages.basename=lang/messages -#spring.messages.encoding=UTF-8 -#server.tomcat.uri-encoding=UTF-8 -#spring.http.encoding.charset=UTF-8 -#spring.thymeleaf.encoding=UTF-8 -# Max file size. -spring.servlet.multipart.max-file-size=10MB -# Max request size. -spring.servlet.multipart.max-request-size=15MB -# DEBUG -logging.level.org.springframework.web=DEBUG -#logging.level.com.zaxxer.hikari=DEBUG -spring.h2.console.enabled=true \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..d12f327 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,27 @@ +spring: + datasource: + url: "jdbc:h2:file:./workdir/recipes" + username: "sa" + password: "LWK4Y7TvEbNyhu1yCoG3" + thymeleaf: + template-loader-path: "classpath:/src/main/java/resources/templates" + suffix: ".html" + messages: + fallback-to-system-locale: true + servlet: + multipart: + max-file-size: 10MB + max-request-size: 15MB + jpa: + hibernate: + ddl-auto: update + h2: + console: + enabled: true +server: + port: 9090 + error: + whitelabel: + enabled: false +response: + useport: true \ No newline at end of file diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql deleted file mode 100644 index 0787bff..0000000 --- a/src/main/resources/import.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO MATERIAL_TYPE -VALUES (0, 'Aucun', '', FALSE); \ No newline at end of file diff --git a/src/main/resources/lang/messages_en.properties b/src/main/resources/lang/messages_en.properties index ecb4d71..f8205fc 100644 --- a/src/main/resources/lang/messages_en.properties +++ b/src/main/resources/lang/messages_en.properties @@ -54,7 +54,7 @@ material.success.saved=The material {0} has been saved. material.edit.title=Edit materials material.simdut.choose=Choose material's SIMDUT file materialType.add.title=Add a material type -materialType.name=Material type name +materialType.name=Name materialType.prefix=Prefix keyword.characters=characters materialType.usePercents=Use percentages @@ -79,5 +79,18 @@ recipe.edit.title=Edit a recipe recipe.explore.title={0} color recipe.warning.notApproved.short=Not approved recipe.image.corrupted=Image deleted or corrupted -recipe.remove.title=Delete recipes -recipe.success.deleted=The recipe {0} has been deleted. \ No newline at end of file +recipe.delete.title=Delete recipes +recipe.success.deleted=The recipe {0} has been deleted. +keyword.search=Search +materialType.editor.title=Edit material types +materialType.editing.title=Editing {0} +keyword.id=ID +materialType.success.saved=The material type {0} has been saved. +materialType.delete.title=Delete material types +materialType.success.deleted=The material type {0} has been deleted. +materialType.error.anyFound=Any material type has been found. +keyword.calculation=Calculation +recipe.error.anyFound=No recipes were found. +recipe.exportAllXLS=Export all colors (XLSX) +recipe.xlsVersion=XLSX version +keyword.updates=Updates history diff --git a/src/main/resources/lang/messages_fr.properties b/src/main/resources/lang/messages_fr.properties index 5c60891..6288ab2 100644 --- a/src/main/resources/lang/messages_fr.properties +++ b/src/main/resources/lang/messages_fr.properties @@ -54,7 +54,7 @@ material.success.saved=Le produit {0} a bien été sauvegardé. material.edit.title=Modifer des produits material.simdut.choose=Choisissez le fichier SIMDUT du produit materialType.add.title=Ajout d'un type de produit -materialType.name=Nom du type de produit +materialType.name=Nom materialType.prefix=Préfix keyword.characters=caractères materialType.usePercents=Utiliser les pourcentages @@ -79,5 +79,19 @@ recipe.edit.title=Modifier une recette recipe.explore.title=Couleur {0} recipe.warning.notApproved.short=Non approuvée recipe.image.corrupted=Image supprimée ou corrompue -recipe.remove.title=Supprimer des recettes +recipe.delete.title=Supprimer des recettes recipe.success.deleted=La recette {0} a bien été supprimée. +keyword.search=Rechercher +materialType.editor.title=Modifier un type de produit +materialType.editing.title=Modification de {0} +keyword.id=Identifiant +materialType.success.saved=Le type de produit {0} a bien été sauvegardé. +materialType.delete.title=Supprimer des types de produit +materialType.success.deleted=Le type de produit {0} a bien été supprimé. +materialType.error.anyFound=Aucun type de produit n'a été trouvé. +keyword.calculation=Calcul +recipe.error.anyFound=Aucune recette n'a été trouvée. +recipe.exportAllXLS=Exporter toutes les couleurs (XLSX) +recipe.xlsVersion=Version XLSX +keyword.updates=Historique des mises à jour + diff --git a/src/main/resources/lang/responses_en.properties b/src/main/resources/lang/responses_en.properties index 85f91d1..cf314b5 100644 --- a/src/main/resources/lang/responses_en.properties +++ b/src/main/resources/lang/responses_en.properties @@ -1,18 +1,29 @@ response.1=The quantities of each material used have been deducted from the inventory response.10=There is already a material with the code {0} response.11=There is already a material type named {0} -response.12=Any banner with the identifier {0} has been found +response.12=Any banner with the ID {0} has been found response.13=There is already a banner named {0} -response.14=The material {0} is linked to one or more recipes, delete them first +response.14=The material {0} is linked to one or more recipes, edit them first response.15=The banner {0} is linked to one or more recipes, delete them first -response.16=The mix with the identifier {0} is not linked to the recipe with the identifier {1} +response.16=The mix with the ID {0} is not linked to the recipe with the ID {1} response.17=There is not enough {0} in inventory for this recipe response.18=This recipe already contains a mix of the type {0} -response.2=The recipe''s informations have been saved +response.19=Any material type with the ID {0} has been found +response.2=The recipe's informations have been saved response.3=An error has occurred while saving response.4=An error has occurred while saving the image response.5=An error has occurred while saving the SIMDUT file response.6=Your password is not valid -response.7=Any recipe with the identifier {0} has been found -response.8=Any mix with the identifier {0} has been found -response.9=Any material with the identifier {0} has been found \ No newline at end of file +response.7=Any recipe with the ID {0} has been found +response.8=Any mix with the ID {0} has been found +response.9=Any material with the ID {0} has been found +response.20=There is already a material type with the prefix {0} +response.21=The material type {0} is linked to one or more materials, delete them first. +response.101=The requested page could not be found +response.100=An internal error as happened +response.102=You do not have autorization to see this page +response.22=No companies were found +response.23=No materials were found. +response.24=This file need to be an image +response.25=The recipe was not found +response.26=The material with the code {0} was not found \ No newline at end of file diff --git a/src/main/resources/lang/responses_fr.properties b/src/main/resources/lang/responses_fr.properties index 3f58875..978b402 100644 --- a/src/main/resources/lang/responses_fr.properties +++ b/src/main/resources/lang/responses_fr.properties @@ -1,18 +1,29 @@ -response.1=Les quantités de chaque produits utilisés ont été déduites de l''inventaire +response.1=Les quantités de chaque produits utilisés ont été déduites de l'inventaire response.10=Il y a déjà un produit ayant le code {0} response.11=Il y a déjà un type de produit s''appellant {0} -response.12=Aucune bannière ayant l'identifiant {0} n''a été trouvée +response.12=Aucune bannière ayant l''identifiant {0} n''a été trouvée response.13=Il y a déjà une bannière s''appellant {0} -response.14=Le produit {0} est lié à une ou plusieurs recettes, veuillez les supprimer d'abord +response.14=Le produit {0} est lié à une ou plusieurs recettes, veuillez les modifier d'abord response.15=La bannière {0} est liée à une ou plusieurs recettes, veuillez les supprimer d'abord response.16=Le mélange ayant l''identifiant {0} n''est pas associé à la recette ayant l''identifiant {1} response.17=Il n''y a pas assez de {0} en inventaire pour cette recette response.18=Cette recette contient déjà un mélange du type {0} +response.19=Aucun type de produit ayant l''identifiant {0} n''a été trouvée response.2=Les informations de la recette ont été sauvegardées response.3=Une erreur est survenue lors de l''enregistrement -response.4=Une erreur est survenue lors de l''enregistrement de l''image -response.5=Une erreur est survenue lors de l''enregistrement du fichier SIMDUT +response.4=Une erreur est survenue lors de l'enregistrement de l'image +response.5=Une erreur est survenue lors de l'enregistrement du fichier SIMDUT response.6=Votre mot de passe n'est pas valide response.7=Aucune recette ayant l''identifiant {0} n''a été trouvée response.8=Aucun mélange ayant l''identifiant {0} n''a été trouvé -response.9=Aucun produit ayant l''identifiant {0} n''a été trouvé \ No newline at end of file +response.9=Aucun produit ayant l''identifiant {0} n''a été trouvé +response.20=Il y a déjà un type de produit ayant le préfix {0} +response.21=Le type de produit {0} est lié à un ou plusieurs produits, veuillez les supprimer d'abord. +response.101=La page demandée n'a pas été trouvée +response.100=Une erreur interne est survenue +response.102=Vous n'avez pas l'autorisation de consulter cette page +response.22=Aucune compagnie n'a été trouvée +response.23=Aucun produit n'a été trouvée. +response.24=Ce fichier doit être une image +response.25=La recette n'a pas été trouvée +response.26=Le produit ayant le code {0} n''a pas été trouvé \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..b9b70ff --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,33 @@ + + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + logs/cre.log + + + logs/archived/cre_%d{dd-MM-yyyy}.log + 10 + 100MB + + + + + %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/css/main.css b/src/main/resources/static/css/main.css index a25fbba..7bc0c8d 100644 --- a/src/main/resources/static/css/main.css +++ b/src/main/resources/static/css/main.css @@ -3,6 +3,10 @@ body { font-family: 'Open Sans', sans-serif; } +td { + vertical-align: top; +} + h1 { text-decoration: underline; } @@ -119,3 +123,12 @@ nav a:hover, .dropdown:hover .dropbtn { .unapproved { background-color: #fff0b3; } + +#researchBoxContainer { + text-align: right; +} + +#researchBox { + margin-top: 10px; + margin-right: 50px; +} \ No newline at end of file diff --git a/src/main/resources/static/css/mix.css b/src/main/resources/static/css/mix.css new file mode 100644 index 0000000..dc687cb --- /dev/null +++ b/src/main/resources/static/css/mix.css @@ -0,0 +1,37 @@ +#materials input { + height: 20px; + padding: 5px; + width: 150px; +} + +.materialSelector .materialList { + border-color: #7a7a7a; + border-width: 1px; + border-style: solid; + display: none; + max-height: 300px; + overflow: auto; + overflow-x: hidden; + position: fixed; + width: 150px; + z-index: 99; +} + +.materialSelector .materialList.show { + display: block; +} + +.materialSelector p { + background-color: #fafafa; + margin: 0; + padding: 5px; + text-align: left; +} + +.materialSelector p:nth-child(even) { + background-color: #f5f5f5; +} + +.materialSelector p:hover { + background-color: #e6e6e6; +} \ No newline at end of file diff --git a/src/main/resources/static/js/main.js b/src/main/resources/static/js/main.js index c5f3be5..dd916f6 100644 --- a/src/main/resources/static/js/main.js +++ b/src/main/resources/static/js/main.js @@ -1,7 +1,7 @@ -(() => { - const body = document.querySelector("body"); - const errorP = document.querySelector(".error"); +const body = document.querySelector("body"); +const errorP = document.querySelector(".error"); +(() => { // Ajoute Axios const axiosElement = document.createElement("script"); axiosElement.src = "/js/libs/axios.min.js"; @@ -11,13 +11,11 @@ // Vérifie si les SIMDUTs sont présents document.querySelectorAll(".materialCode").forEach(e => { const materialID = e.getAttribute("data-materialID"); - axios.get(`/simdut/${materialID}`) + axios.post(`/simdut/${materialID}`) .catch(err => { if (err.response.status === 404) { e.parentElement.classList.add("nosimdut"); e.parentElement.title = "Aucun fichier SIMDUT trouvé"; - } else { - console.log(e); } }); }); @@ -37,23 +35,26 @@ }); document.querySelectorAll("img").forEach((e) => { - e.addEventListener("click", () => { - window.open(e.src, "_blank"); - }); + if (e.id !== "logo") { + e.addEventListener("click", () => { + window.open(e.src, "_blank"); + }); + } }); document.querySelectorAll(".requireAuth").forEach((e) => { e.onsubmit = () => { - checkPassword(e); - return false; + return checkPassword(e); }; }); document.querySelectorAll(".requireAuth-remover").forEach((e) => { e.querySelectorAll(".remover").forEach(elem => { elem.addEventListener("click", () => { - e.action += elem.getAttribute("data-recipeID"); - checkPassword(e); + e.action += elem.getAttribute("data-entityID"); + e.onsubmit = () => { + return checkPassword(e); + } }); }); }); @@ -76,62 +77,73 @@ faviconElement.rel = "icon"; faviconElement.href = "/favicon.png"; document.querySelector("head").appendChild(faviconElement); - - function checkPassword(form) { - errorP.innerHTML = ""; - - const password = prompt("Quel est votre mot de passe?"); - - let data = {}; - data.password = password; - - axios.post("/password/valid", data) - .then(r => { - console.log(r); - if (r.data) { - form.submit(); - } else { - errorP.innerHTML = "Votre mot de passe n'est pas valide"; - } - }) - .catch(e => { - errorP.innerHTML = "Une erreur est survenue lors de l'envoie des informations vers le serveur."; - console.log(e); - }); - } })(); +function askDatabaseExport() { + return confirm("Voulez-vous vraiment exporter toutes les couleurs? Cela peut prendre un certain temps et ralentir l'application pendant un certain temps."); +} + +function checkPassword(form) { + errorP.innerHTML = ""; + + const password = prompt("Quel est votre mot de passe?"); + + let data = {}; + data.password = password; + + axios.post("/password/valid", data) + .then(r => { + if (r.data) { + form.submit(); + return true; + } else { + errorP.innerHTML = "Votre mot de passe n'est pas valide"; + } + }) + .catch(e => { + errorP.innerHTML = "Une erreur est survenue lors de l'envoie des informations vers le serveur."; + console.log(e); + }); + + return false; +} const lTomL = 1000; const galTomL = 3785.41; +let currentUnit = "mL"; + // Change les unités selon la sélection de l'utilisateur function changeUnits(unitSelect, quantitiesSelector, unitsSelector) { - const newUnit = unitSelect.value; + currentUnit = unitSelect.value; document.querySelectorAll(unitsSelector).forEach(e => { - e.innerText = newUnit; + e.innerText = currentUnit; // Modifie la quantitée const quantityElem = e.parentElement.parentElement.querySelector(quantitiesSelector); const originalQuantity = parseInt(quantityElem.dataset.quantityml); - quantityElem.innerText = convertMlToUnit(newUnit, originalQuantity); + quantityElem.innerText = convertMlToUnit(originalQuantity); }); } // Convertit une quantité en millilitres vers une autre unité de volume -function convertMlToUnit(unit, quantity) { - let newQuantity = unit === "L" ? quantity / lTomL : unit === "gal" ? quantity / galTomL : quantity; +function convertMlToUnit(quantity) { + let newQuantity = currentUnit === "L" ? quantity / lTomL : currentUnit === "gal" ? quantity / galTomL : quantity; return round(newQuantity); } // Convertit une quantité d'une autre unité vers des millilitres -function convertUnitToMl(unit, quantity) { - let newQuantity = unit === "L" ? quantity * lTomL : unit === "gal" ? quantity * galTomL : quantity; +function convertUnitToMl(quantity) { + let newQuantity = currentUnit === "L" ? quantity * lTomL : currentUnit === "gal" ? quantity * galTomL : quantity; return round(newQuantity); } function round(x) { - return Math.round(x * 100) / 100; + return Math.round(x * 1000) / 1000; +} + +function percentageOf(percentage, number) { + return (percentage / 100) * number; } \ No newline at end of file diff --git a/src/main/resources/static/js/main.js.bak b/src/main/resources/static/js/main.js.bak deleted file mode 100644 index a5bebd8..0000000 --- a/src/main/resources/static/js/main.js.bak +++ /dev/null @@ -1,150 +0,0 @@ -(() => { - - // Ajoute Axios - const axiosElement = document.createElement("script"); - axiosElement.src = "/js/libs/axios.min.js"; - body.appendChild(axiosElement); - - // Ajoute jQuery - const jqueryElement = document.createElement("script"); - jqueryElement.src = "/js/libs/jquery-3.4.1.min.js"; - body.appendChild(jqueryElement); - - const body = $("body"); - const errorP = $(".error"); - - axiosElement.onload = () => { - // Ajoute le header - axios.get('/header.html') - .then(r => { - const header = document.createElement("header"); - header.innerHTML = r.data; - body.insertBefore(header, document.querySelector("section")); - }) - .catch(e => { - console.log(e); - errorP.innerHTML = "Une erreur est survenue lors de la récupération de l'entête"; - }); - - // Vérifie si les SIMDUTs sont présents - document.querySelectorAll(".materialCode").forEach(e => { - const materialID = e.getAttribute("data-materialID"); - axios.get(`/simdut/${materialID}`) - .catch(err => { - if (err.response.status === 404) { - e.parentElement.classList.add("nosimdut"); - e.parentElement.title = "Aucun fichier SIMDUT trouvé"; - } else { - console.log(e); - } - }); - }); - }; - - document.querySelectorAll(".returnIndex").forEach((e) => { - e.addEventListener("click", () => { - document.location.href = "/"; - }); - }); - - document.querySelectorAll(".materialCode").forEach((e) => { - const materialID = e.getAttribute("data-materialID"); - e.addEventListener("click", () => { - window.open("/simdut/" + materialID, "_blank"); - }); - }); - - document.querySelectorAll("img").forEach((e) => { - e.addEventListener("click", () => { - window.open(e.src, "_blank"); - }); - }); - - document.querySelectorAll(".requireAuth").forEach((e) => { - e.onsubmit = () => { - checkPassword(e); - return false; - }; - }); - - document.querySelectorAll(".requireAuth-remover").forEach((e) => { - e.querySelectorAll(".remover").forEach(elem => { - elem.addEventListener("click", () => { - e.action += elem.getAttribute("data-recipeID"); - checkPassword(e); - }); - }); - }); - - document.querySelectorAll(".companyTabTitle").forEach(e => { - e.addEventListener("click", () => { - const companyName = e.getAttribute("data-companyName"); - const table = document.getElementById("recipes_" + companyName); - - if (table.style.display === "none") { - table.style.display = "table"; - } else { - table.style.display = "none"; - } - }); - }); - - // Ajoute le favicon - let faviconElement = document.createElement("link"); - faviconElement.rel = "icon"; - faviconElement.href = "/favicon.png"; - document.querySelector("head").appendChild(faviconElement); - - function checkPassword(form) { - errorP.innerHTML = ""; - - const password = prompt("Quel est votre mot de passe?"); - - let data = {}; - data.password = password; - - axios.post("/password/valid", data) - .then(r => { - console.log(r); - if (r.data) { - form.submit(); - } else { - errorP.innerHTML = "Votre mot de passe n'est pas valide"; - } - }) - .catch(e => { - errorP.innerHTML = "Une erreur est survenue lors de l'envoie des informations vers le serveur."; - console.log(e); - }); - } -})(); - - -const lTomL = 1000; -const galTomL = 3785.41; - -// Change les unités selon la sélection de l'utilisateur -function changeUnits(unitSelect, quantitiesSelector, unitsSelector) { - document.querySelectorAll(unitsSelector).forEach(e => { - e.innerText = unitSelect.value; - - // Modifie la quantitée - const quantityElem = e.parentElement.parentElement.querySelector(quantitiesSelector); - const originalQuantity = parseInt(quantityElem.dataset.quantityml); - - switch (unitSelect.value) { - case "L": - quantityElem.innerText = originalQuantity / lTomL; - break; - case "gal": - quantityElem.innerText = originalQuantity / galTomL; - break; - default: - quantityElem.innerText = originalQuantity; - break; - } - - // Arrondi à deux décimaux - quantityElem.innerText = Math.round(quantityElem.innerText * 100) / 100; - }); -} \ No newline at end of file diff --git a/src/main/resources/static/js/mix.js b/src/main/resources/static/js/mix.js new file mode 100644 index 0000000..52c1a81 --- /dev/null +++ b/src/main/resources/static/js/mix.js @@ -0,0 +1,168 @@ +// Compteurs des produits +let materialNbr = 0; +// Liste des produits +let materials; + +let removeText; +let materialSelectorHtml; +let recipeID; + +window.addEventListener("load", () => { + recipeID = document.querySelector("#recipeID").value; + + axios.get(`/mix/selector/${recipeID}/-1`) + .then(r => { + materialSelectorHtml = r.data; + init(); + }) + .catch(e => { + errorP.innerHTML = "Une erreur est survenue lors de la récupération des produits"; + console.log(e); + }); +}); + +window.addEventListener("click", e => { + if (e.target) { + if (e.target.classList.contains("rowRemover")) { + document.querySelector(`#row_${e.target.dataset.remove}`).remove(); + return; + } + + const materialSelector = e.target.parentElement; + if (materialSelector == null || materialSelector.parentElement == null) { + hideMaterialList(); + return; + } + if (!materialSelector.classList.contains("materialSelector") && !materialSelector.parentElement.classList.contains("materialSelector")) hideMaterialList(); + } +}); + +document.querySelector("#materials button").addEventListener("click", () => { + addMaterial(null, null); +}); + +function addMaterial(materialCode, quantity) { + let row = addRow(); + + let materialSelectionColumn = addColumn(row); + let quantityInputColumn = addColumn(row); + + let removeButtonColumn = addColumn(row); + + addInput(quantityInputColumn, quantity); + addSpan(quantityInputColumn); + addButton(removeButtonColumn); + + materialSelectionColumn.innerHTML = materialSelectorHtml; + const input = materialSelectionColumn.querySelector("input"); + if (materialCode) { + const material = materialSelectionColumn.querySelector(`.materialList p[data-materialcode="${materialCode}"]`); + + if (material) { + input.value = material.dataset.materialcode; + input.dataset.usepercentages = material.dataset.usepercentages; + } + } + + document.querySelector("#materials tbody").appendChild(row); + materialNbr++; + + checkUnits(input, row); +} + +function addInput(parent, quantity) { + let input = document.createElement("input"); + + if (quantity === null) quantity = 0; + + input.type = "number"; + input.name = "quantities"; + input.value = quantity; + input.step = 0.001; + input.required = true; + + parent.appendChild(input); + return input; +} + +function addSpan(parent) { + let span = document.createElement("span"); + + span.className = "quantityUnit"; + span.innerText = "mL"; + + parent.appendChild(span); + return span; +} + +function addButton(parent) { + let button = document.createElement("button"); + + button.type = "button"; + button.dataset.remove = materialNbr; + button.className = "rowRemover"; + button.innerText = removeText; + + parent.appendChild(button); + return button; +} + +function addRow() { + let row = document.createElement("tr"); + row.id = `row_${materialNbr}`; + + return row; +} + +function addColumn(parent) { + let column = document.createElement("td"); + + parent.appendChild(column); + return column; +} + +function showMaterialList(input) { + hideMaterialList(); + input.parentElement.querySelector(".materialSelector .materialList").classList.add("show"); +} + +function hideMaterialList() { + const list = document.querySelector(".materialSelector .materialList.show"); + + if (list != null) list.classList.remove("show"); +} + +function selectMaterial(material) { + const materialName = material.dataset.materialcode; + const input = material.parentElement.parentElement.querySelector("input"); + + input.value = materialName; + + hideMaterialList(); + checkUnits(material, input.parentElement.parentElement.parentElement) +} + +function searchMaterial(input) { + let filter, filterUpper, materials; + + filter = input.value; + filterUpper = filter.toUpperCase(); + materials = input.parentElement.querySelectorAll(".materialList p"); + + materials.forEach(e => { + if (e.innerText.toUpperCase().indexOf(filterUpper) > -1 || + e.dataset.materialtype.toUpperCase().indexOf(filterUpper) > -1) e.style.display = ""; + else e.style.display = "none"; + }); + + const found = input.parentElement.querySelector(`.materialList p[data-materialcode="${filter}"]`); + if (found) input.dataset.usepercentages = found.dataset.usepercentages; + + checkUnits(input, input.parentElement.parentElement.parentElement); +} + +function checkUnits(materialSelector, row) { + const quantityUnits = row.querySelector(".quantityUnit"); + if (materialSelector.dataset.usepercentages === "true") quantityUnits.innerText = "%"; + else quantityUnits.innerText = "mL"; +} \ No newline at end of file diff --git a/src/main/resources/templates/closeTab.html b/src/main/resources/templates/closeTab.html new file mode 100644 index 0000000..9153319 --- /dev/null +++ b/src/main/resources/templates/closeTab.html @@ -0,0 +1,12 @@ + + + + + Fermeture de l'onglet... + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/company/created.html b/src/main/resources/templates/company/created.html index e4660db..beaa5fa 100644 --- a/src/main/resources/templates/company/created.html +++ b/src/main/resources/templates/company/created.html @@ -16,7 +16,7 @@ -

+
diff --git a/src/main/resources/templates/company/creator.html b/src/main/resources/templates/company/creator.html index ab0b494..09bc65e 100644 --- a/src/main/resources/templates/company/creator.html +++ b/src/main/resources/templates/company/creator.html @@ -12,7 +12,6 @@
-

@@ -37,7 +36,7 @@
-
+
diff --git a/src/main/resources/templates/company/remover.html b/src/main/resources/templates/company/remover.html index 26419d2..6690fcd 100644 --- a/src/main/resources/templates/company/remover.html +++ b/src/main/resources/templates/company/remover.html @@ -25,7 +25,7 @@
-

+

@@ -42,7 +42,7 @@ @@ -55,7 +55,7 @@
-
+
diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 0000000..ef4c6be --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,29 @@ + + + + + + + +
+ +
+

+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments.html b/src/main/resources/templates/fragments.html index 3a795a6..a4b4d0b 100644 --- a/src/main/resources/templates/fragments.html +++ b/src/main/resources/templates/fragments.html @@ -1,15 +1,15 @@ - + - +
-
-

+
+

+

@@ -60,12 +67,11 @@
-
- - - - - + + +
diff --git a/src/main/resources/templates/images/add.html b/src/main/resources/templates/images/add.html index 0b7bf4b..744e0cf 100644 --- a/src/main/resources/templates/images/add.html +++ b/src/main/resources/templates/images/add.html @@ -9,7 +9,7 @@
-

+

@@ -20,7 +20,7 @@
-
+
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 1a1339f..56be013 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -9,26 +9,23 @@ } th { - padding: 15px; + padding: 0 15px; } td { padding: 0 20px; } - .centerCell { - border-left-color: #e6e6e6; - border-left-style: solid; - border-left-width: 2px; - + .descriptionCell { border-right-color: #e6e6e6; border-right-style: solid; border-right-width: 2px; } table { - border-collapse: collapse; - margin: 0px auto; + border-collapse: separate; + border-spacing: 0 10px; + margin: 0 auto; text-align: center; } @@ -39,6 +36,10 @@ .recipeDescription { max-width: 400px; } + + .researchEnabled .companyTab:not(.researchResult), .researchEnabled .recipeRow:not(.researchResult) { + display: none; + } @@ -46,43 +47,42 @@
-

+
+ +
-
- - -

+

- - - - - - - - - - - - - - - -
- -
-
-
-
- - - +
+
+

+ + + + + + + + + + + + + + +
+
-
- +
diff --git a/src/main/resources/templates/inventory.html b/src/main/resources/templates/inventory.html index 686333f..daaedec 100644 --- a/src/main/resources/templates/inventory.html +++ b/src/main/resources/templates/inventory.html @@ -13,15 +13,23 @@ table { margin: 50px auto; text-align: left; + border-collapse: collapse; } section { text-align: center; } + .materialRow { + background-color: #fafafa; + } + + .materialRow:nth-child(even) { + background-color: #f5f5f5; + } + .materialRow:hover td { - background-color: #f0f0f0; - font-weight: bolder; + background-color: #e6e6e6; } .lowQuantity td { @@ -31,6 +39,10 @@ .hidden, .hiddenWrongType { display: none; } + + .researchEnabled .materialRow:not(.researchResult) { + display: none; + } @@ -45,81 +57,83 @@

- - +
+ +
- - - - +

- - +
- - + + + + - - - - -
-
+ + - - - + + + + +
+
- - - - - - - - - - + + + -
- - -
- -
-
+ +
+ + +
+ +
+
-
- -
-
- - - + + + + + + + mL + + + + + + + + -
+
diff --git a/src/main/resources/templates/material/created.html b/src/main/resources/templates/material/created.html index 99d7e8f..4f81808 100644 --- a/src/main/resources/templates/material/created.html +++ b/src/main/resources/templates/material/created.html @@ -11,12 +11,13 @@
-

+

+
-
+
diff --git a/src/main/resources/templates/material/creator.html b/src/main/resources/templates/material/creator.html index ec2fd31..409996d 100644 --- a/src/main/resources/templates/material/creator.html +++ b/src/main/resources/templates/material/creator.html @@ -12,7 +12,8 @@
-

+

+

@@ -75,7 +76,7 @@
-
+
diff --git a/src/main/resources/templates/material/remover.html b/src/main/resources/templates/material/remover.html index d07b6cd..3f9af80 100644 --- a/src/main/resources/templates/material/remover.html +++ b/src/main/resources/templates/material/remover.html @@ -20,12 +20,12 @@
-

+

-
+ @@ -37,7 +37,7 @@ @@ -48,7 +48,7 @@ -
+
diff --git a/src/main/resources/templates/material/simdut.html b/src/main/resources/templates/material/simdut.html index 1d028a4..2626266 100644 --- a/src/main/resources/templates/material/simdut.html +++ b/src/main/resources/templates/material/simdut.html @@ -9,6 +9,8 @@
+

+

@@ -20,13 +22,13 @@

- + +
-
- +
diff --git a/src/main/resources/templates/materialType/creator.html b/src/main/resources/templates/materialType/creator.html index e9f446b..6092ab7 100644 --- a/src/main/resources/templates/materialType/creator.html +++ b/src/main/resources/templates/materialType/creator.html @@ -3,7 +3,7 @@ - + @@ -11,7 +11,7 @@
-

+

@@ -47,7 +47,7 @@
-
+
diff --git a/src/main/resources/templates/materialType/edit.html b/src/main/resources/templates/materialType/edit.html new file mode 100644 index 0000000..0a10ed1 --- /dev/null +++ b/src/main/resources/templates/materialType/edit.html @@ -0,0 +1,60 @@ + + + + + + + + + + +
+ +
+

+ +

+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/materialType/editor.html b/src/main/resources/templates/materialType/editor.html new file mode 100644 index 0000000..1f67c3e --- /dev/null +++ b/src/main/resources/templates/materialType/editor.html @@ -0,0 +1,63 @@ + + + + + + + + + + +
+ +
+

+

+

+

+ + + + + + + + + +
+ +
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/materialType/remover.html b/src/main/resources/templates/materialType/remover.html new file mode 100644 index 0000000..8d73514 --- /dev/null +++ b/src/main/resources/templates/materialType/remover.html @@ -0,0 +1,53 @@ + + + + + + + + + + +
+ +
+

+

+

+ +
+ + + + + + + + +
+ +
+
+ + + +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/mix/creator.html b/src/main/resources/templates/mix/creator.html index 75aead1..de71e1e 100644 --- a/src/main/resources/templates/mix/creator.html +++ b/src/main/resources/templates/mix/creator.html @@ -4,6 +4,7 @@ + - - + + +
+ +
+

+

+ +
+
- -
- -
-

-

- -
-
+
+
+ + + + -
- - - - - - - - - - - - -
- - - - - -
- - -
-
- - - -
- -
-
- -
+ + + + + + + + +
+ + + + + +
+ + +
+
+ + + +
+ + +
+ +
- - + + -
+ /*]]*/ + \ No newline at end of file diff --git a/src/main/resources/templates/mix/selector.html b/src/main/resources/templates/mix/selector.html new file mode 100644 index 0000000..467e30a --- /dev/null +++ b/src/main/resources/templates/mix/selector.html @@ -0,0 +1,29 @@ + + + + +
+ + +
+

+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/created.html b/src/main/resources/templates/recipe/created.html index 756396c..9810c84 100644 --- a/src/main/resources/templates/recipe/created.html +++ b/src/main/resources/templates/recipe/created.html @@ -9,7 +9,7 @@
-

+

@@ -17,7 +17,7 @@ th:text="#{keyword.continue}">
-
+
diff --git a/src/main/resources/templates/recipe/creator.html b/src/main/resources/templates/recipe/creator.html index 8d2edeb..1baf468 100644 --- a/src/main/resources/templates/recipe/creator.html +++ b/src/main/resources/templates/recipe/creator.html @@ -11,7 +11,7 @@
-

+

@@ -31,16 +31,16 @@ - + - + - + @@ -51,7 +51,7 @@ - + @@ -59,7 +59,7 @@
-
+
diff --git a/src/main/resources/templates/recipe/edit.html b/src/main/resources/templates/recipe/edit.html index 95bae9a..190f844 100644 --- a/src/main/resources/templates/recipe/edit.html +++ b/src/main/resources/templates/recipe/edit.html @@ -11,14 +11,28 @@ } .recipe table { - border: 1px solid black; + background-color: #fafafa; + border: 1px solid #7a7a7a; border-collapse: collapse; } .recipe td, .recipe th { min-width: 100px; text-align: center; - border: 1px solid black; + } + + .recipe tr:nth-child(odd) { + background-color: #f5f5f5; + } + + .mixNameColumn { + max-width: 200px; + text-align: left; + } + + .mixNameColumn { + display: inline-block; + min-width: 150px; } @@ -28,7 +42,7 @@
-

+

@@ -38,12 +52,22 @@
- + + + - - - - @@ -171,12 +215,15 @@ -
+
diff --git a/src/main/resources/templates/recipe/editor.html b/src/main/resources/templates/recipe/editor.html index 7cd3a41..621abf5 100644 --- a/src/main/resources/templates/recipe/editor.html +++ b/src/main/resources/templates/recipe/editor.html @@ -5,16 +5,37 @@ @@ -24,7 +45,7 @@
-

+

@@ -42,9 +63,9 @@
- - - + + +
+ + + + + + + + + + - - -
@@ -88,8 +112,9 @@ - - +
+ +
@@ -112,7 +137,7 @@

@@ -127,29 +152,48 @@
- - - - -
- -
+
+
+ + + + +
+ Image supprimée ou corrompue + +
- Image supprimée ou corrompue - - + + + + + + + + + + +
+

+
+ +
+ + +
+
@@ -52,10 +73,10 @@
- +
-
+
diff --git a/src/main/resources/templates/recipe/explore.html b/src/main/resources/templates/recipe/explore.html index 8547566..bd5f2a8 100644 --- a/src/main/resources/templates/recipe/explore.html +++ b/src/main/resources/templates/recipe/explore.html @@ -1,11 +1,6 @@ - - - - - + + @@ -50,25 +78,29 @@
-

+

-
+
+
+ - - - - - -
+ @@ -108,13 +140,20 @@ + + + +
+ +
- - - + + +

- - - - + +


+


-

mL

+
+ +

+
+

mL

+

%

@@ -165,43 +213,39 @@
- - -
    - -
  1. -
    -
-
- + - + + + + + + + +
+

+
    + +
  1. +
    +
+
- - - - - - - - +
-
+
diff --git a/src/main/resources/templates/recipe/remover.html b/src/main/resources/templates/recipe/remover.html index c5423d7..e41ffc0 100644 --- a/src/main/resources/templates/recipe/remover.html +++ b/src/main/resources/templates/recipe/remover.html @@ -1,19 +1,40 @@ - + @@ -23,41 +44,41 @@
-

+

-

+

- +

- - - - - + + +
- +
-
+
diff --git a/src/main/resources/templates/touchup.html b/src/main/resources/templates/touchup.html deleted file mode 100644 index 34afc45..0000000 --- a/src/main/resources/templates/touchup.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Génération du PDF d'un kit de retouche - - - - - - -
- -
-

Génération du PDF d'un kit de retouche

- -
- - -
- - -
- -
- - - - \ No newline at end of file diff --git a/src/main/resources/templates/updates.html b/src/main/resources/templates/updates.html new file mode 100644 index 0000000..30c3c8b --- /dev/null +++ b/src/main/resources/templates/updates.html @@ -0,0 +1,44 @@ + + + + + + + + + +
+ +
+

+

+ +
+
+ +
+ + + + + diff --git a/src/main/resources/updates.md b/src/main/resources/updates.md new file mode 100644 index 0000000..8c54f74 --- /dev/null +++ b/src/main/resources/updates.md @@ -0,0 +1,17 @@ +# v1.1.1 +### Corrections +* Désactivation de l'autocomplétion dans les étapes des recettes (permet d'éviter un bug qui affiche les suggestion par dessus toutes les étapes sur Edge) +* Correction d'un bug qui permettait d'envoyer les formulaires demandant des mots de passe sans donner un mot de passe valide. +* Amélioration des contrôlleurs et du service des mélanges. +* Correction d'un bug avec la création des mélanges. + +### Ajouts +* L'onglet se ferme automatiquement lorsqu'un utilisateur tente d'accéder à un fichier SIMDUT inexistant. +* Meilleure sélection des produits dans l'éditeur de mélange. +* Retravail de l'affichage de la plupart des tables, les rendant moins chargées. +* Retravail de l'affichage des étapes et des images dans l'explorateur et l'éditeur de recette. +* Ajout de la page de l'historique des mises à jour. +* Ajout de la journalisation. + +### Dépendances +* Ajout de Lombok \ No newline at end of file diff --git a/src/test/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplicationTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplicationTests.java similarity index 87% rename from src/test/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplicationTests.java rename to src/tests/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplicationTests.java index 3ae03a8..291e3a2 100644 --- a/src/test/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplicationTests.java +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplicationTests.java @@ -1,4 +1,4 @@ -package fyloz.trial.ColorRecipesExplorer; +package dev.fyloz.trial.colorrecipesexplorer; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/CompanyServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/CompanyServiceTests.java new file mode 100644 index 0000000..5f5e1b8 --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/CompanyServiceTests.java @@ -0,0 +1,546 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.dao.CompanyDao; +import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class CompanyServiceTests { + + @Mock + private CompanyDao companyDao; + + @Mock + private RecipeDao recipeDao; + + @Spy + @InjectMocks + private CompanyService companyService; + + private Company testCompany; + private Company testCompany2; + private List testCompaniesList; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testCompany = new Company("Test Company"); + testCompany.setCompanyID(0); + + testCompany2 = new Company("Test Company 2"); + testCompany.setCompanyID(1); + + testCompaniesList = new ArrayList<>(); + testCompaniesList.add(testCompany); + testCompaniesList.add(testCompany2); + } + + @Test + public void isValidForCreationTestShouldBeTrue() { + // Arrange + when(companyService.existsByName(testCompany.getCompanyName())).thenReturn(false); + when(companyService.exists(testCompany)).thenReturn(false); + + // Act + boolean actual = companyService.isValidForCreation(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void isValidForCreationTestShouldBeFalse() { + // Arrange + when(companyService.existsByName(testCompany.getCompanyName())).thenReturn(true); + when(companyService.exists(testCompany)).thenReturn(true); + + // Act + boolean actual = companyService.isValidForCreation(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForCreationTestExists() { + // Arrange + when(companyService.existsByName(testCompany.getCompanyName())).thenReturn(false); + when(companyService.exists(testCompany)).thenReturn(true); + + // Act + boolean actual = companyService.isValidForCreation(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForCreationTestNameExists() { + // Arrange + when(companyService.existsByName(testCompany.getCompanyName())).thenReturn(true); + when(companyService.exists(testCompany)).thenReturn(false); + + // Act + boolean actual = companyService.isValidForCreation(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForCreationTestNull() { + // Act + boolean actual = companyService.isValidForCreation(null); + + // Assert + assertFalse(actual); + } + + @Test + public void existsByNameTestShouldBeTrue() { + // Arrange + when(companyDao.existsByCompanyName(testCompany.getCompanyName())).thenReturn(true); + + // Act + boolean actual = companyService.existsByName(testCompany.getCompanyName()); + + // Assert + assertTrue(actual); + } + + @Test + public void existsByNameTestShouldBeFalse() { + // Arrange + when(companyDao.existsByCompanyName(testCompany.getCompanyName())).thenReturn(false); + + // Act + boolean actual = companyService.existsByName(testCompany.getCompanyName()); + + // Assert + assertFalse(actual); + } + + @Test + public void existsByNameTestNull() { + // Act + boolean actual = companyService.existsByName(null); + + // Assert + assertFalse(actual); + } + + @Test + public void isLinkedToRecipesTestShouldBeTrue() { + // Arrange + List recipesList = new ArrayList<>(); + recipesList.add(new Recipe()); + + when(recipeDao.findAllByCompany(testCompany)).thenReturn(recipesList); + + // Act + boolean actual = companyService.isLinkedToRecipes(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void isLinkedToRecipesTestShouldBeFalse() { + // Arrange + when(recipeDao.findAllByCompany(testCompany)).thenReturn(new ArrayList<>()); + + // Act + boolean actual = companyService.isLinkedToRecipes(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void isLinkedToRecipesTestNull() { + // Act + boolean actual = companyService.isLinkedToRecipes(null); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeTrue() { + // Arrange + doReturn(true).when(companyService).delete(testCompany); + doReturn(false).when(companyService).isLinkedToRecipes(testCompany); + + // Act + boolean actual = companyService.deleteIfNotLinked(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeFalse() { + // Arrange + doReturn(true).when(companyService).delete(testCompany); + doReturn(true).when(companyService).isLinkedToRecipes(testCompany); + + // Act + boolean actual = companyService.deleteIfNotLinked(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestNull() { + // Arrange + doReturn(true).when(companyService).delete(testCompany); + + // Act + boolean actual = companyService.deleteIfNotLinked(null); + + // Assert + assertFalse(actual); + } + + // Test les méthodes génériques + @Test + public void getByIDTest() { + // Arrange + doReturn(Optional.of(testCompany)).when(companyDao).findById(testCompany.getCompanyID()); + + // Act + Optional actual = companyService.getByID(testCompany.getCompanyID()); + + // Assert + assertTrue(actual.isPresent()); + assertEquals(testCompany, actual.get()); + } + + @Test + public void getByIDTestShouldBeNull() { + // Arrange + doReturn(Optional.empty()).when(companyDao).findById(testCompany.getCompanyID()); + + // Act + Optional actual = companyService.getByID(testCompany.getCompanyID()); + + // Arrange + assertFalse(actual.isPresent()); + } + + @Test + public void getAllTest() { + // Arrange + List companies = new ArrayList<>(); + companies.add(testCompany); + + doReturn(companies).when(companyDao).findAll(); + + // Act + List actual = companyService.getAll(); + + // Assert + assertTrue(actual.contains(testCompany)); + } + + @Test + public void getAllTestShouldBeEmpty() { + // Arrange + doReturn(new ArrayList<>()).when(companyDao).findAll(); + + // Act + List actual = companyService.getAll(); + + // Assert + assertTrue(actual.isEmpty()); + } + + @Test + public void saveTest() { + // Arrange + doReturn(true).when(companyService).isValidForCreation(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.save(testCompany); + + // Assert + assertTrue(actual.isPresent()); + assertEquals(testCompany, actual.get()); + } + + @Test + public void saveTestInvalidCompany() { + // Arrange + doReturn(false).when(companyService).isValidForCreation(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.save(testCompany); + + // Assert + assertFalse(actual.isPresent()); + } + + @Test + public void saveTestNull() { + // Arrange + doReturn(false).when(companyService).isValidForCreation(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.save(null); + + // Assert + assertFalse(actual.isPresent()); + } + + @Test + public void saveAllTestShouldBeTrue() { + // Arrange + doAnswer(i -> Optional.of(i.getArguments()[0])).when(companyService).save(any(Company.class)); + + // Act + boolean actual = companyService.saveAll(testCompaniesList); + + // Assert + assertTrue(actual); + } + + @Test + public void saveAllTestShouldBeFalse() { + // Arrange + doAnswer(i -> Optional.empty()).when(companyService).save(any(Company.class)); + + // Act + boolean actual = companyService.saveAll(testCompaniesList); + + // Assert + assertFalse(actual); + } + + @Test + public void saveAllTestOneSaveFalse() { + // Arrange + doReturn(Optional.of(testCompany)).when(companyService).save(testCompany); + doReturn(Optional.empty()).when(companyService).save(testCompany2); + + // Act + boolean actual = companyService.saveAll(testCompaniesList); + + // Assert + assertFalse(actual); + } + + @Test + public void saveAllTestNull() { + // Arrange + doAnswer(i -> Optional.empty()).when(companyService).save(any(Company.class)); + + // Act + boolean actual = companyService.saveAll(null); + + // Assert + assertFalse(actual); + } + + @Test + public void updateTest() { + // Arrange + doReturn(true).when(companyService).isValidForUpdate(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.update(testCompany); + + // Assert + assertTrue(actual.isPresent()); + assertEquals(testCompany, actual.get()); + } + + @Test + public void updateTestInvalidCompany() { + // Arrange + doReturn(false).when(companyService).isValidForUpdate(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.update(testCompany); + + // Assert + assertFalse(actual.isPresent()); + } + + @Test + public void updateTestNull() { + // Arrange + doReturn(false).when(companyService).isValidForUpdate(testCompany); + doReturn(testCompany).when(companyDao).save(testCompany); + + // Act + Optional actual = companyService.update(null); + + // Assert + assertFalse(actual.isPresent()); + } + + @Test + public void deleteTestShouldBeTrue() { + // Arrange + doReturn(true).when(companyService).exists(testCompany); + + // Act + boolean actual = companyService.delete(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void deleteTestShouldBeFalse() { + // Arrange + doReturn(false).when(companyService).exists(testCompany); + + // Act + boolean actual = companyService.delete(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteTestNull() { + // Arrange + doReturn(true).when(companyService).exists(testCompany); + + // Act + boolean actual = companyService.delete(null); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteAllTestShouldBeTrue() { + // Arrange + doReturn(true).when(companyService).exists(any()); + + // Act + boolean actual = companyService.deleteAll(testCompaniesList); + + // Assert + assertTrue(actual); + } + + @Test + public void deleteAllTestShouldBeFalse() { + // Arrange + doReturn(false).when(companyService).exists(any()); + + // Act + boolean actual = companyService.deleteAll(testCompaniesList); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteAllTestNull() { + // Arrange + doReturn(false).when(companyService).exists(any()); + + // Act + boolean actual = companyService.deleteAll(null); + + // Assert + assertFalse(actual); + } + + @Test + public void existsTestShouldBeTrue() { + // Arrange + doReturn(true).when(companyService).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void existsTestShouldBeFalse() { + // Arrange + doReturn(false).when(companyService).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void existsTestNull() { + // Arrange + doReturn(true).when(companyService).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(null); + + // Assert + assertFalse(actual); + } + + @Test + public void existsByIdTestShouldBeTrue() { + // Arrange + doReturn(true).when(companyDao).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(testCompany); + + // Assert + assertTrue(actual); + } + + @Test + public void existsByIdTestShouldBeFalse() { + // Arrange + doReturn(false).when(companyDao).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(testCompany); + + // Assert + assertFalse(actual); + } + + @Test + public void existsByIdTestNull() { + // Arrange + doReturn(true).when(companyDao).existsById(testCompany.getCompanyID()); + + // Act + boolean actual = companyService.exists(null); + + // Assert + assertFalse(actual); + } +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialServiceTests.java new file mode 100644 index 0000000..20c9bce --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialServiceTests.java @@ -0,0 +1,339 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixQuantityService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +public class MaterialServiceTests { + + @Mock + private MaterialDao materialDao; + + @Mock + private MixQuantityService mixQuantityService; + + @Spy + @InjectMocks + private MaterialService materialService; + + private Material testMaterial; + private MaterialType testMaterialType; + private List testMaterialsList; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testMaterial = new Material(); + testMaterial.setMaterialID(0); + testMaterial.setMaterialCode("Test Material"); + + testMaterialType = new MaterialType(); + testMaterialType.setMaterialTypeID(0); + testMaterialType.setMaterialTypeName("Test Type"); + + testMaterialsList = new ArrayList<>(); + testMaterialsList.add(testMaterial); + } + + @Test + public void getAllByMaterialTypeTest() { + // Arrange + doReturn(testMaterialsList).when(materialDao).findAllByMaterialType(testMaterialType); + + // Act + List actual = materialService.getAllByMaterialType(testMaterialType); + + // Assert + assertTrue(actual.contains(testMaterial)); + } + + @Test + public void getAllByMaterialTypeTestShouldBeEmpty() { + // Arrange + doReturn(new ArrayList<>()).when(materialDao).findAllByMaterialType(testMaterialType); + + // Act + List actual = materialService.getAllByMaterialType(testMaterialType); + + // Assert + assertTrue(actual.isEmpty()); + } + + @Test + public void getAllByMaterialTypeTestNull() { + // Arrange + doReturn(testMaterialsList).when(materialDao).findAllByMaterialType(any()); + + // Act + List actual = materialService.getAllByMaterialType(null); + + // Assert + assertTrue(actual.isEmpty()); + } + + @Test + public void isLinkedToMixesTestShouldBeTrue() { + // Arrange + doReturn(true).when(mixQuantityService).existsByMaterial(testMaterial); + + // Act + boolean actual = materialService.isLinkedToMixes(testMaterial); + + // Arrange + assertTrue(actual); + } + + @Test + public void isLinkedToMixesTestShouldBeFalse() { + // Arrange + doReturn(false).when(mixQuantityService).existsByMaterial(testMaterial); + + // Act + boolean actual = materialService.isLinkedToMixes(testMaterial); + + // Arrange + assertFalse(actual); + } + + @Test + public void isLinkedToMixesTestNull() { + // Arrange + doReturn(false).when(mixQuantityService).existsByMaterial(any()); + + // Act + boolean actual = materialService.isLinkedToMixes(null); + + // Arrange + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeTrue() { + // Arrange + doReturn(false).when(materialService).isLinkedToMixes(testMaterial); + doReturn(true).when(materialService).delete(testMaterial); + + // Act + boolean actual = materialService.deleteIfNotLinked(testMaterial); + + // Assert + assertTrue(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeFalse() { + // Arrange + doReturn(true).when(materialService).isLinkedToMixes(testMaterial); + doReturn(false).when(materialService).delete(testMaterial); + + // Act + boolean actual = materialService.deleteIfNotLinked(testMaterial); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeFalseNotLinked() { + // Arrange + doReturn(false).when(materialService).isLinkedToMixes(testMaterial); + doReturn(false).when(materialService).delete(testMaterial); + + // Act + boolean actual = materialService.deleteIfNotLinked(testMaterial); + + // Assert + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestNull() { + // Arrange + doReturn(false).when(materialService).isLinkedToMixes(testMaterial); + doReturn(true).when(materialService).delete(testMaterial); + + // Act + boolean actual = materialService.deleteIfNotLinked(null); + + // Assert + assertFalse(actual); + } + + @Test + public void existsTestShouldBeTrue() { + // Arrange + doReturn(true).when((GenericService) materialService).exists(testMaterial); + doReturn(true).when(materialDao).existsByMaterialCode(testMaterial.getMaterialCode()); + + // Act + boolean actual = materialService.exists(testMaterial); + + // Assert + assertTrue(actual); + } + + @Test + public void existsTestShouldBeFalse() { + // Arrange + doReturn(false).when((GenericService) materialService).exists(testMaterial); + doReturn(false).when(materialDao).existsByMaterialCode(testMaterial.getMaterialCode()); + + // Act + boolean actual = materialService.exists(testMaterial); + + // Assert + assertFalse(actual); + } + + @Test + public void existsTestShouldBeTrueOneConditionMet() { + // Arrange + doReturn(true).when(materialDao).existsByMaterialCode(testMaterial.getMaterialCode()); + + // Act + boolean actual = materialService.exists(testMaterial); + + // Assert + assertTrue(actual); + } + + @Test + public void existsTestNull() { + // Arrange + doReturn(true).when(materialDao).existsByMaterialCode(any()); + + // Act + boolean actual = materialService.exists(null); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForUpdateTestShouldBeTrue() { + // Arrange + doReturn(null).when(materialDao).findByMaterialCode(testMaterial.getMaterialCode()); + doReturn(true).when((GenericService) materialService).isValidForUpdate(testMaterial); + + // Act + boolean actual = materialService.isValidForUpdate(testMaterial); + + // Assert + assertTrue(actual); + } + + @Test + public void isValidForUpdateTestShouldBeTrueMaterialCodeExistsWithSameId() { + // Arrange + doReturn(testMaterial).when(materialDao).findByMaterialCode(testMaterial.getMaterialCode()); + doReturn(true).when((GenericService) materialService).isValidForUpdate(testMaterial); + + // Act + boolean actual = materialService.isValidForUpdate(testMaterial); + + // Assert + assertTrue(actual); + } + + @Test + public void isValidForUpdateTestShouldBeFalse() { + // Arrange + doReturn(testMaterial).when(materialDao).findByMaterialCode(testMaterial.getMaterialCode()); + doReturn(false).when((GenericService) materialService).isValidForUpdate(testMaterial); + + // Act + boolean actual = materialService.isValidForUpdate(testMaterial); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForUpdateTestShouldBeFalseMaterialCodeExists() { + // Arrange + Material otherMaterial = new Material(); + otherMaterial.setMaterialCode(testMaterial.getMaterialCode()); + otherMaterial.setMaterialID(1); + + doReturn(otherMaterial).when(materialDao).findByMaterialCode(testMaterial.getMaterialCode()); + + // Act + boolean actual = materialService.isValidForUpdate(testMaterial); + + // Assert + assertFalse(actual); + } + + @Test + public void isValidForUpdateShouldNull() { + // Arrange + doReturn(testMaterial).when(materialDao).findByMaterialCode(testMaterial.getMaterialCode()); + + // Act + boolean actual = materialService.isValidForUpdate(null); + + // Assert + assertFalse(actual); + } + + @Test + public void getAllBySearchStringTest() { + // Arrange + doReturn(testMaterialsList).when(materialDao).findAllByMaterialCodeContainingIgnoreCase(testMaterial.getMaterialCode()); + + // Act + List actual = materialService.getAllBySearchString(testMaterial.getMaterialCode()); + + // Assert + assertTrue(actual.contains(testMaterial)); + } + + @Test + public void getAllBySearchStringTestShouldBeEmpty() { + // Arrange + doReturn(new ArrayList<>()).when(materialDao).findAllByMaterialCodeContainingIgnoreCase(testMaterial.getMaterialCode()); + + // Act + List actual = materialService.getAllBySearchString(testMaterial.getMaterialCode()); + + // Assert + assertTrue(actual.isEmpty()); + } + + @Test + public void getAllBySearchStringTestMixType() { + // Arrange + Material mixTypeMaterial = new Material(); + mixTypeMaterial.setMaterialID(2); + mixTypeMaterial.setMaterialCode("Mix Type"); + mixTypeMaterial.setMixType(true); + + testMaterialsList.add(mixTypeMaterial); + + doReturn(testMaterialsList).when(materialDao).findAllByMaterialCodeContainingIgnoreCase(mixTypeMaterial.getMaterialCode()); + + // Act + List actual = materialService.getAllBySearchString(mixTypeMaterial.getMaterialCode()); + + // Assert + assertFalse(actual.contains(mixTypeMaterial)); + } + +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialTypeServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialTypeServiceTests.java new file mode 100644 index 0000000..7056cbb --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MaterialTypeServiceTests.java @@ -0,0 +1,238 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialTypeDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +public class MaterialTypeServiceTests { + + @Mock + private MaterialService materialService; + + @Mock + private MaterialTypeDao materialTypeDao; + + @Spy + @InjectMocks + private MaterialTypeService materialTypeService; + + private MaterialType testMaterialType; + private Material testMaterial; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testMaterialType = new MaterialType(); + testMaterialType.setMaterialTypeID(0); + testMaterialType.setMaterialTypeName("Test Type"); + + testMaterial = new Material(); + testMaterial.setMaterialID(0); + testMaterial.setMaterialCode("Test Material"); + } + + @Test + public void isLinkedToMaterialsTestShouldBeTrue() { + // Arrange + List testMaterialList = new ArrayList<>(); + testMaterialList.add(testMaterial); + + doReturn(testMaterialList).when(materialService).getAllByMaterialType(testMaterialType); + + // Act + boolean actual = materialTypeService.isLinkedToMaterials(testMaterialType); + + // Assert + assertTrue(actual); + } + + @Test + public void isLinkedToMaterialsTestShouldBeFalse() { + doReturn(new ArrayList<>()).when(materialService).getAllByMaterialType(testMaterialType); + + boolean actual = materialTypeService.isLinkedToMaterials(testMaterialType); + assertFalse(actual); + } + + @Test + public void isLinkedToMaterialsTestNull() { + doReturn(new ArrayList<>()).when(materialService).getAllByMaterialType(any()); + + boolean actual = materialTypeService.isLinkedToMaterials(testMaterialType); + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeTrue() { + doReturn(false).when(materialTypeService).isLinkedToMaterials(testMaterialType); + doReturn(true).when(materialTypeService).delete(testMaterialType); + + boolean actual = materialTypeService.deleteIfNotLinked(testMaterialType); + assertTrue(actual); + } + + @Test + public void deleteIfNotLinkedTestShouldBeFalse() { + doReturn(true).when(materialTypeService).isLinkedToMaterials(testMaterialType); + doReturn(false).when(materialTypeService).delete(testMaterialType); + + boolean actual = materialTypeService.deleteIfNotLinked(testMaterialType); + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestIsLinked() { + doReturn(true).when(materialTypeService).isLinkedToMaterials(testMaterialType); + doReturn(true).when(materialTypeService).delete(testMaterialType); + + boolean actual = materialTypeService.deleteIfNotLinked(testMaterialType); + assertFalse(actual); + } + + @Test + public void deleteIfNotLinkedTestNull() { + doReturn(true).when(materialTypeService).isLinkedToMaterials(testMaterialType); + doReturn(false).when(materialTypeService).delete(testMaterialType); + + boolean actual = materialTypeService.deleteIfNotLinked(null); + assertFalse(actual); + } + + @Test + public void isValidForCreationTestShouldBeTrue() { + doReturn(false).when(materialTypeService).existsByName(testMaterialType.getMaterialTypeName()); + + boolean actual = materialTypeService.isValidForCreation(testMaterialType); + assertTrue(actual); + } + + @Test + public void isValidForCreationTestShouldBeFalse() { + doReturn(true).when(materialTypeService).existsByName(testMaterialType.getMaterialTypeName()); + + boolean actual = materialTypeService.isValidForCreation(testMaterialType); + assertFalse(actual); + } + + @Test + public void isValidForCreationTestNull() { + doReturn(false).when(materialTypeService).existsByName(testMaterialType.getMaterialTypeName()); + + boolean actual = materialTypeService.isValidForCreation(null); + assertFalse(actual); + } + + @Test + public void isValidForUpdateTestShouldBeTrue() { + doReturn(true).when(materialTypeService).exists(testMaterialType); + doReturn(true).when(materialTypeService).isValidForUpdateName(testMaterialType); + doReturn(true).when(materialTypeService).isValidForUpdatePrefix(testMaterialType); + + boolean actual = materialTypeService.isValidForUpdate(testMaterialType); + assertTrue(actual); + } + + @Test + public void isValidForUpdateTestShouldBeFalse() { + doReturn(false).when(materialTypeService).exists(testMaterialType); + doReturn(false).when(materialTypeService).isValidForUpdateName(testMaterialType); + doReturn(false).when(materialTypeService).isValidForUpdatePrefix(testMaterialType); + + boolean actual = materialTypeService.isValidForUpdate(testMaterialType); + assertFalse(actual); + } + + @Test + public void isValidForUpdateTestNull() { + doReturn(false).when(materialTypeService).exists(any()); + doReturn(false).when(materialTypeService).isValidForUpdateName(any()); + doReturn(false).when(materialTypeService).isValidForUpdatePrefix(any()); + + boolean actual = materialTypeService.isValidForUpdate(null); + assertFalse(actual); + } + + @Test + public void getByNameTest() { + doReturn(Optional.of(testMaterialType)).when(materialTypeDao).findByMaterialTypeName(testMaterialType.getMaterialTypeName()); + + Optional actual = materialTypeService.getByName(testMaterialType.getMaterialTypeName()); + assertTrue(actual.isPresent()); + assertEquals(testMaterialType.getMaterialTypeName(), actual.get().getMaterialTypeName()); + } + + @Test + public void getByNameTestShouldBeEmpty() { + doReturn(Optional.empty()).when(materialTypeDao).findByMaterialTypeName(testMaterialType.getMaterialTypeName()); + + Optional actual = materialTypeService.getByName(testMaterialType.getMaterialTypeName()); + assertFalse(actual.isPresent()); + } + + @Test + public void getByNameTestNull() { + doReturn(Optional.empty()).when(materialTypeDao).findByMaterialTypeName(testMaterialType.getMaterialTypeName()); + + Optional actual = materialTypeService.getByName(null); + assertFalse(actual.isPresent()); + } + + @Test + public void getDefaultMaterialTypeTest() { + doReturn(Optional.of(testMaterialType)).when(materialTypeService).getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME); + + Optional actual = materialTypeService.getDefaultMaterialType(); + assertTrue(actual.isPresent()); + } + + // Test non-fonctionnel +// @Test +// public void getDefaultMaterialTypeGetByNameFail() { +// doReturn(Optional.empty()).when(materialTypeService).getByName(any()); +// +// Optional actual = materialTypeService.getDefaultMaterialType(); +// assertTrue(actual.isPresent()); +// } + + @Test + public void existsByNameTestShouldBeTrue() { + doReturn(Optional.of(testMaterialType)).when(materialTypeService).getByName(testMaterialType.getMaterialTypeName()); + + boolean actual = materialTypeService.existsByName(testMaterialType.getMaterialTypeName()); + assertTrue(actual); + } + + @Test + public void existsByNameTestShouldBeFalse() { + doReturn(Optional.empty()).when(materialTypeService).getByName(testMaterialType.getMaterialTypeName()); + + boolean actual = materialTypeService.existsByName(testMaterialType.getMaterialTypeName()); + assertFalse(actual); + } + + @Test + public void existsByNameTestNull() { + doReturn(Optional.empty()).when(materialTypeService).getByName(any()); + + boolean actual = materialTypeService.existsByName(null); + assertFalse(actual); + } + +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixQuantityServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixQuantityServiceTests.java new file mode 100644 index 0000000..2121f49 --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixQuantityServiceTests.java @@ -0,0 +1,61 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixQuantityService; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.dao.MixQuantityDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +public class MixQuantityServiceTests { + + @Mock + private MixQuantityDao mixQuantityDao; + + @Spy + @InjectMocks + private MixQuantityService mixQuantityService; + + private Material testMaterial; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testMaterial = new Material(); + testMaterial.setMaterialID(0); + testMaterial.setMaterialCode("Test Material"); + } + + @Test + public void existsByMaterialTestShouldBeTrue() { + doReturn(true).when(mixQuantityDao).existsByMaterial(testMaterial); + + boolean actual = mixQuantityService.existsByMaterial(testMaterial); + assertTrue(actual); + } + + @Test + public void existsByMaterialTestShouldBeFalse() { + doReturn(false).when(mixQuantityDao).existsByMaterial(testMaterial); + + boolean actual = mixQuantityService.existsByMaterial(testMaterial); + assertFalse(actual); + } + + @Test + public void existsByMaterialTestNull() { + doReturn(false).when(mixQuantityDao).existsByMaterial(testMaterial); + + boolean actual = mixQuantityService.existsByMaterial(null); + assertFalse(actual); + } + +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixServiceTests.java new file mode 100644 index 0000000..a589e0a --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixServiceTests.java @@ -0,0 +1,81 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixQuantityService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import org.junit.Before; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import static org.mockito.ArgumentMatchers.any; + +public class MixServiceTests { + + @Mock + private MaterialService materialService; + + @Mock + private MixQuantityService mixQuantityService; + + @Spy + @InjectMocks + private MixService mixService; + + private Mix testMix; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + Recipe recipe = new Recipe(); + recipe.setRecipeID(0); + recipe.setRecipeCode("Test Recipe"); + + testMix = new Mix(); + testMix.setMixID(0); + testMix.setRecipe(recipe); + } + +// @Test +// public void createTest() { +// List materials = new ArrayList<>(); +// materials.add(0); +// List quantities = new ArrayList<>(); +// List mquantities = new ArrayList<>(); +// mquantities.add(new MixQuantity()); +// quantities.add(1000f); +// MixType type = new MixType(); +// type.setTypeName("Test Type"); +// +// doReturn(Optional.of(testMix)).when(mixService).save(any()); +// doReturn(mquantities).when(mixService).createMixQuantities(any(), any(), any()); +// ModelResponseBuilder fakeResponseBuilder = mock(ModelResponseBuilder.class); +// verify(fakeResponseBuilder, times(0)).addResponseCode(any()); +// +// mixService.create(new ModelResponseBuilder(""), materials, quantities, testMix.getRecipe(), type); +// } + +// @Test +// public void createTestMaterialNotFound() { +// List materials = new ArrayList<>(); +// materials.add(0); +// List quantities = new ArrayList<>(); +// List mquantities = new ArrayList<>(); +// mquantities.add(new MixQuantity()); +// quantities.add(1000f); +// MixType type = new MixType(); +// type.setTypeName("Test Type"); +// +// doReturn(Optional.of(testMix)).when(mixService).save(any()); +// doReturn(mquantities).when(mixService).createMixQuantities(any(), any(), any()); +// ModelResponseBuilder fakeResponseBuilder = mock(ModelResponseBuilder.class); +// verify(fakeResponseBuilder, times(0)).addResponseCode(any()); +// +// mixService.create(new ModelResponseBuilder(""), materials, quantities, testMix.getRecipe(), type); +// } + +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixTypeServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixTypeServiceTests.java new file mode 100644 index 0000000..05ed3d3 --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/MixTypeServiceTests.java @@ -0,0 +1,146 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Material; +import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService; +import dev.fyloz.trial.colorrecipesexplorer.dao.MixTypeDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.Optional; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class MixTypeServiceTests { + + @Mock + private MaterialTypeService materialTypeService; + + @Mock + private MixTypeDao mixTypeDao; + + @Spy + @InjectMocks + private MixTypeService mixTypeService; + + private MixType testMixType; + private MaterialType testMaterialType; + private Material testMaterial; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testMaterial = new Material(); + testMaterial.setMaterialID(0); + testMaterial.setMaterialCode("Test Material"); + + testMixType = new MixType(); + testMixType.setTypeID(0); + testMixType.setTypeName("Test Type"); + testMixType.setMaterial(testMaterial); + + testMaterialType = new MaterialType(); + testMaterialType.setMaterialTypeID(0); + testMaterialType.setMaterialTypeName("Test Type"); + } + + @Test + public void getByNameTest() { + doReturn(Optional.of(testMixType)).when(mixTypeDao).findByTypeName(testMixType.getTypeName()); + + Optional actual = mixTypeService.getByName(testMixType.getTypeName()); + assertTrue(actual.isPresent()); + } + + @Test + public void getByNameTestShouldBeEmpty() { + doReturn(Optional.empty()).when(mixTypeDao).findByTypeName(testMixType.getTypeName()); + + Optional actual = mixTypeService.getByName(testMixType.getTypeName()); + assertFalse(actual.isPresent()); + } + + @Test + public void getByNameTestNull() { + doReturn(Optional.empty()).when(mixTypeDao).findByTypeName(any()); + + Optional actual = mixTypeService.getByName(null); + assertFalse(actual.isPresent()); + } + + @Test + public void getByMaterialTest() { + doReturn(Optional.of(testMixType)).when(mixTypeDao).findByMaterial(testMaterial); + + Optional actual = mixTypeService.getByMaterial(testMaterial); + assertTrue(actual.isPresent()); + } + + @Test + public void getByMaterialTestShouldBeEmpty() { + doReturn(Optional.empty()).when(mixTypeDao).findByMaterial(testMaterial); + + Optional actual = mixTypeService.getByMaterial(testMaterial); + assertFalse(actual.isPresent()); + } + + @Test + public void getByMaterialTestNull() { + doReturn(Optional.empty()).when(mixTypeDao).findByMaterial(any()); + + Optional actual = mixTypeService.getByMaterial(null); + assertFalse(actual.isPresent()); + } + + @Test + public void createByNameTest() { + doReturn(Optional.of(testMaterialType)).when(materialTypeService).getDefaultMaterialType(); + doReturn(Optional.of(testMixType)).when(mixTypeService).save(any()); + doReturn(Optional.empty()).when(mixTypeService).getByName(testMixType.getTypeName()); + + Optional actual = mixTypeService.createByName(testMixType.getTypeName()); + assertTrue(actual.isPresent()); + } + + @Test + public void createByNameTestExistsByName() { + doReturn(Optional.of(testMixType)).when(materialTypeService).getDefaultMaterialType(); + doReturn(Optional.of(testMixType)).when(mixTypeService).save(any()); + doReturn(Optional.of(testMixType)).when(mixTypeService).getByName(testMixType.getTypeName()); + + Optional actual = mixTypeService.createByName(testMixType.getTypeName()); + verify(mixTypeService, times(0)).save(any()); + assertTrue(actual.isPresent()); + } + + @Test + public void createByNameTestShouldBeEmpty() { + doReturn(Optional.empty()).when(materialTypeService).getDefaultMaterialType(); + doReturn(Optional.empty()).when(mixTypeService).save(any()); + doReturn(Optional.empty()).when(mixTypeService).getByName(testMixType.getTypeName()); + + Optional actual = mixTypeService.createByName(testMixType.getTypeName()); + assertFalse(actual.isPresent()); + } + + @Test + public void createByNameTestNull() { + doReturn(Optional.empty()).when(materialTypeService).getDefaultMaterialType(); + doReturn(Optional.empty()).when(mixTypeService).save(any()); + doReturn(Optional.empty()).when(mixTypeService).getByName(any()); + + Optional actual = mixTypeService.createByName(null); + assertFalse(actual.isPresent()); + } + +} diff --git a/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/RecipeServiceTests.java b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/RecipeServiceTests.java new file mode 100644 index 0000000..fb6e1a3 --- /dev/null +++ b/src/tests/java/dev/fyloz/trial/colorrecipesexplorer/core/services/RecipeServiceTests.java @@ -0,0 +1,223 @@ +package dev.fyloz.trial.colorrecipesexplorer.core.services; + +import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Company; +import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService; +import dev.fyloz.trial.colorrecipesexplorer.core.services.model.StepService; +import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.*; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +public class RecipeServiceTests { + + @Mock + private CompanyService companyService; + + @Mock + private StepService stepService; + + @Mock + private MixService mixService; + + @Mock + private RecipeDao recipeDao; + + @Spy + @InjectMocks + private RecipeService recipeService; + + @Mock + private Recipe testRecipe; + private Company testCompany; + private List testMixesList; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + testCompany = new Company(); + testCompany.setCompanyID(0); + testCompany.setCompanyName("Test Company"); + + testRecipe = new Recipe(); + testRecipe.setRecipeID(Integer.MAX_VALUE); + testRecipe.setRecipeCode("Test Recipe"); + testRecipe.setCompany(testCompany); + + Mix mix1 = new Mix(); + mix1.setMixID(5); + Mix mix2 = new Mix(); + mix1.setMixID(1); + testMixesList = new ArrayList<>(); + testMixesList.add(mix1); + testMixesList.add(mix2); + } + + @Test + public void getByCompanyTest() { + List testRecipesList = new ArrayList<>(); + testRecipesList.add(testRecipe); + + doReturn(testRecipesList).when(recipeDao).findAllByCompany(testCompany); + + List actual = recipeService.getByCompany(testCompany); + assertFalse(actual.isEmpty()); + } + + @Test + public void getByCompanyTestShouldBeEmpty() { + doReturn(new ArrayList<>()).when(recipeDao).findAllByCompany(testCompany); + + List actual = recipeService.getByCompany(testCompany); + assertTrue(actual.isEmpty()); + } + + @Test + public void getByCompanyTestNull() { + doReturn(new ArrayList<>()).when(recipeDao).findAllByCompany(any()); + + List actual = recipeService.getByCompany(null); + assertTrue(actual.isEmpty()); + } + + @Test + public void deleteRecipeTestShouldBeTrue() { + doReturn(true).when(recipeService).delete(testRecipe); + doReturn(new ArrayList<>()).when(recipeService).getImageFiles(testRecipe); + + boolean actual = recipeService.deleteRecipe(testRecipe); + assertTrue(actual); + } + + @Test + public void deleteRecipeTestShouldBeFalse() { + doReturn(false).when(recipeService).delete(testRecipe); + + boolean actual = recipeService.deleteRecipe(testRecipe); + assertFalse(actual); + } + + @Test + public void deleteRecipeTestNull() { + doReturn(false).when(recipeService).delete(testRecipe); + + boolean actual = recipeService.deleteRecipe(null); + assertFalse(actual); + } + +// @Test +// public void getSortedMixesTest() { +//// doReturn(testMixesList).when(testRecipe).getRecipeMixes(); +// testRecipe.setRecipeMixes(testMixesList); +// +// List actual = recipeService.getSortedMixes(testRecipe); +// assertFalse(actual.isEmpty()); +// assertEquals(testMixesList.get(1).getMixID(), actual.get(0).getMixID()); +// assertEquals(testMixesList.get(0).getMixID(), actual.get(1).getMixID()); +// } +// +// @Test +// public void getSortedMixesTestShouldBeEmpty() { +// testRecipe.setRecipeMixes(testMixesList); +// +// List actual = recipeService.getSortedMixes(testRecipe); +// assertTrue(actual.isEmpty()); +// } +// +// @Test +// public void getSortedMixesTestNull() { +// doReturn(new ArrayList<>()).when(testRecipe).getRecipeMixes(); +// +// List actual = recipeService.getSortedMixes(null); +// assertTrue(actual.isEmpty()); +// } + + @Test + public void convertAndCreateStepsTest() { + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + List testSteps = new LinkedList<>(); + testSteps.add("step 1"); + testSteps.add("step 2"); + testSteps.add("step 3"); + + multiValueMap.add("step", testSteps); + + doReturn(true).when(stepService).deleteAll(any()); + doReturn(Optional.of(testRecipe)).when(recipeService).save(any()); + + Optional actual = recipeService.convertAndCreateSteps(testRecipe, multiValueMap); + assertTrue(actual.isPresent()); + } + + @Test + public void convertAndCreateStepsTestWithPreviousSteps() { + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + List testSteps = new LinkedList<>(); + testSteps.add("step 1"); + testSteps.add("step 2"); + testSteps.add("step 3"); + + multiValueMap.add("step", testSteps); + + List previousSteps = new ArrayList<>(); + previousSteps.add(new RecipeStep(testRecipe, "previous 1")); + previousSteps.add(new RecipeStep(testRecipe, "previous 2")); + testRecipe.setRecipeSteps(previousSteps); + + doReturn(true).when(stepService).deleteAll(any()); + doReturn(Optional.of(testRecipe)).when(recipeService).save(any()); + + Optional actual = recipeService.convertAndCreateSteps(testRecipe, multiValueMap); + assertTrue(actual.isPresent()); + } + + @Test + public void convertAndCreateStepsTestShouldBeEmpty() { + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + List testSteps = new LinkedList<>(); + testSteps.add("step 1"); + testSteps.add("step 2"); + testSteps.add("step 3"); + + multiValueMap.add("step", testSteps); + + List previousSteps = new ArrayList<>(); + previousSteps.add(new RecipeStep(testRecipe, "previous 1")); + previousSteps.add(new RecipeStep(testRecipe, "previous 2")); + testRecipe.setRecipeSteps(previousSteps); + + doReturn(false).when(stepService).deleteAll(any()); + doReturn(Optional.empty()).when(recipeService).save(any()); + + Optional actual = recipeService.convertAndCreateSteps(testRecipe, multiValueMap); + assertFalse(actual.isPresent()); + } + + @Test + public void convertAndCreateStepsTestNull() { + doReturn(false).when(stepService).deleteAll(any()); + doReturn(Optional.empty()).when(recipeService).save(any()); + + Optional actual = recipeService.convertAndCreateSteps(null, null); + assertFalse(actual.isPresent()); + } + +} diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..7dfebd8 --- /dev/null +++ b/start.bat @@ -0,0 +1 @@ +java -jar ColorRecipesExplorer-0.0.1-SNAPSHOT.jar -Dupload.location=./ \ No newline at end of file diff --git a/users b/users deleted file mode 100644 index 1f7391f..0000000 --- a/users +++ /dev/null @@ -1 +0,0 @@ -master diff --git a/workdir.zip b/workdir.zip deleted file mode 100644 index ef2eb56..0000000 Binary files a/workdir.zip and /dev/null differ diff --git a/workdir/images/15_LQ-1-0.jpeg b/workdir/images/15_LQ-1-0.jpeg deleted file mode 100644 index d99ac3d..0000000 Binary files a/workdir/images/15_LQ-1-0.jpeg and /dev/null differ diff --git a/workdir/passwords.txt b/workdir/passwords.txt index 414243b..1f7391f 100644 --- a/workdir/passwords.txt +++ b/workdir/passwords.txt @@ -1,2 +1 @@ master -dom diff --git a/workdir/recipes.mv.db b/workdir/recipes.mv.db deleted file mode 100644 index c09d90a..0000000 Binary files a/workdir/recipes.mv.db and /dev/null differ diff --git a/workdir/recipes.trace.db b/workdir/recipes.trace.db deleted file mode 100644 index ab7efea..0000000 --- a/workdir/recipes.trace.db +++ /dev/null @@ -1,2160 +0,0 @@ -2019-06-24 11:41:58 jdbc[13]: exception -org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "'Catalyseur' (MATERIALS: ""MATERIAL_TYPE_MATERIAL_TYPEID"" INTEGER)"; SQL statement: -delete from MATERIAL_TYPE [22018-199] -2019-06-24 11:42:11 jdbc[13]: exception -org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "'Catalyseur' (MATERIALS: ""MATERIAL_TYPE_MATERIAL_TYPEID"" INTEGER)"; SQL statement: -DELETE FROM MATERIAL_TYPE [22018-199] -2019-06-25 20:18:42 database: flush -org.h2.message.DbException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:157) - at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:115) - at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:78) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:319) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:356) - at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.getDatabase(DatabaseLookup.java:73) - at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:142) - at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter(JpaBaseConfiguration.java:113) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$a4ce5b3d.CGLIB$jpaVendorAdapter$5() - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$a4ce5b3d$$FastClassBySpringCGLIB$$480db8e2.invoke() - at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) - at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$a4ce5b3d.jpaVendorAdapter() - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) - at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) - at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) - at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) - at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) - at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) - at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) - at fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication.main(ColorRecipesExplorerApplication.java:36) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 95 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:172) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 89 more -2019-06-25 20:18:43 database: flush -org.h2.message.DbException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) - at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) - at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) - at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) - at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:94) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) - at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243) - at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) - at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:179) - at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:119) - at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904) - at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935) - at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57) - at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) - at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390) - at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) - at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) - at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) - at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) - at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) - at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) - at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) - at fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication.main(ColorRecipesExplorerApplication.java:36) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 68 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:172) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 62 more -2019-06-25 20:18:46 database: flush -org.h2.message.DbException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) - at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) - at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:43) - at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:60) - at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl.extractMetadata(SequenceInformationExtractorH2DatabaseImpl.java:35) - at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.initializeSequences(DatabaseInformationImpl.java:65) - at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.(DatabaseInformationImpl.java:59) - at org.hibernate.tool.schema.internal.Helper.buildDatabaseInformation(Helper.java:132) - at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:96) - at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:183) - at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72) - at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:310) - at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467) - at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939) - at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57) - at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) - at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390) - at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) - at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) - at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) - at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) - at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) - at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) - at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) - at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) - at fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication.main(ColorRecipesExplorerApplication.java:36) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 66 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:/home/william/Dev/Java/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:172) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 60 more -2019-07-03 22:19:21 jdbc[13]: exception -org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "null"; SQL statement: -select * from materials where MATERIAL_TYPE_MATERIAL_TYPEID = 'null' [22018-199] -2019-08-18 22:44:14 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1237) - at org.h2.jdbc.JdbcPreparedStatement.checkClosed(JdbcPreparedStatement.java:1829) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1211) - at org.h2.jdbc.JdbcResultSet.checkClosed(JdbcResultSet.java:3245) - at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3155) - at org.h2.jdbc.JdbcResultSet.get(JdbcResultSet.java:3287) - at org.h2.jdbc.JdbcResultSet.getString(JdbcResultSet.java:314) - at com.zaxxer.hikari.pool.HikariProxyResultSet.getString(HikariProxyResultSet.java) - at org.hibernate.type.descriptor.sql.VarcharTypeDescriptor$2.doExtract(VarcharTypeDescriptor.java:62) - at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47) - at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257) - at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253) - at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243) - at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329) - at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:3010) - at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.loadFromResultSet(EntityReferenceInitializerImpl.java:305) - at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.hydrateEntityState(EntityReferenceInitializerImpl.java:233) - at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.readRow(AbstractRowReader.java:103) - at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:254) - at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:122) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) - at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:188) - at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271) - at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511) - at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481) - at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222) - at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281) - at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124) - at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92) - at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256) - at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:207) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2873) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2847) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3482) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3451) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:234) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$72091336.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 22:44:14 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1237) - at org.h2.jdbc.JdbcPreparedStatement.checkClosed(JdbcPreparedStatement.java:1829) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1211) - at org.h2.jdbc.JdbcStatement.getMaxRows(JdbcStatement.java:438) - at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.getMaxRows(HikariProxyPreparedStatement.java) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.close(ResourceRegistryStandardImpl.java:168) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.release(ResourceRegistryStandardImpl.java:96) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:144) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) - at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:188) - at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271) - at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511) - at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481) - at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222) - at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281) - at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124) - at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92) - at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256) - at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:207) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2873) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2847) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3482) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3451) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:234) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$72091336.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 22:44:14 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosedForWrite(JdbcConnection.java:1557) - at org.h2.jdbc.JdbcConnection.rollback(JdbcConnection.java:561) - at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:370) - at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java) - at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116) - at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294) - at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:145) - at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:559) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:838) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:812) - at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:551) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:298) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$72091336.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 22:47:22 database: wrong user or password; user: "SA" -org.h2.message.DbException: Mauvais nom d'utilisateur ou mot de passe -Wrong user name or password [28000-199] - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.engine.Engine.openSession(Engine.java:126) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at org.h2.util.JdbcUtils.getConnection(JdbcUtils.java:299) - at org.h2.server.web.WebServer.getConnection(WebServer.java:782) - at org.h2.server.web.WebApp.login(WebApp.java:1004) - at org.h2.server.web.WebApp.process(WebApp.java:219) - at org.h2.server.web.WebApp.processRequest(WebApp.java:169) - at org.h2.server.web.WebServlet.doGet(WebServlet.java:121) - at org.h2.server.web.WebServlet.doPost(WebServlet.java:158) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -Caused by: org.h2.jdbc.JdbcSQLInvalidAuthorizationSpecException: Mauvais nom d'utilisateur ou mot de passe -Wrong user name or password [28000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:459) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 58 more -2019-08-18 22:47:44 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1237) - at org.h2.jdbc.JdbcPreparedStatement.checkClosed(JdbcPreparedStatement.java:1829) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1211) - at org.h2.jdbc.JdbcStatement.getMaxRows(JdbcStatement.java:438) - at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.getMaxRows(HikariProxyPreparedStatement.java) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.close(ResourceRegistryStandardImpl.java:168) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.release(ResourceRegistryStandardImpl.java:96) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:144) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) - at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:188) - at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271) - at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511) - at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481) - at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222) - at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281) - at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124) - at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92) - at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256) - at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:207) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2873) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2847) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3482) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3451) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:234) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$4f223c7b.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 22:47:44 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosedForWrite(JdbcConnection.java:1557) - at org.h2.jdbc.JdbcConnection.commit(JdbcConnection.java:539) - at com.zaxxer.hikari.pool.ProxyConnection.commit(ProxyConnection.java:361) - at com.zaxxer.hikari.pool.HikariProxyConnection.commit(HikariProxyConnection.java) - at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.commit(AbstractLogicalConnectionImplementor.java:81) - at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:272) - at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104) - at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) - at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$4f223c7b.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 22:47:44 database: flush -org.h2.message.DbException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:157) - at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:115) - at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:78) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:319) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:356) - at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.getDatabase(DatabaseLookup.java:73) - at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:142) - at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter(JpaBaseConfiguration.java:113) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$769bf12e.CGLIB$jpaVendorAdapter$5() - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$769bf12e$$FastClassBySpringCGLIB$$5f289055.invoke() - at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) - at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$769bf12e.jpaVendorAdapter() - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) - at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:607) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:602) - at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:340) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:168) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:150) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy97.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.getByID(GenericService.java:24) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.RecipeService$$EnhancerBySpringCGLIB$$4f223c7b.getByID() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MixCreatorController.createMix(MixCreatorController.java:103) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 158 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:166) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 152 more -Caused by: java.nio.channels.OverlappingFileLockException - at java.base/sun.nio.ch.FileLockTable.checkList(FileLockTable.java:229) - at java.base/sun.nio.ch.FileLockTable.add(FileLockTable.java:123) - at java.base/sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:1154) - at org.h2.store.fs.FileNio.tryLock(FilePathNio.java:121) - at java.base/java.nio.channels.FileChannel.tryLock(FileChannel.java:1165) - at org.h2.mvstore.FileStore.open(FileStore.java:163) - ... 153 more -2019-08-18 23:11:49 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1237) - at org.h2.jdbc.JdbcPreparedStatement.checkClosed(JdbcPreparedStatement.java:1829) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1211) - at org.h2.jdbc.JdbcPreparedStatement.setParameter(JdbcPreparedStatement.java:1569) - at org.h2.jdbc.JdbcPreparedStatement.setInt(JdbcPreparedStatement.java:407) - at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setInt(HikariProxyPreparedStatement.java) - at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:46) - at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74) - at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276) - at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.bindPositionalParameters(AbstractLoadPlanBasedLoader.java:348) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.bindParameterValues(AbstractLoadPlanBasedLoader.java:319) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:238) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:190) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) - at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:188) - at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271) - at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511) - at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481) - at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222) - at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281) - at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124) - at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92) - at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256) - at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:207) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2873) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2847) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3482) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3451) - at jdk.internal.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at jdk.internal.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:234) - at jdk.internal.reflect.GeneratedMethodAccessor133.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.exists(GenericService.java:101) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.isValidForCreation(GenericService.java:89) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:34) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.saveAll(GenericService.java:44) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) - at fyloz.trial.ColorRecipesExplorer.services.MixQuantityService$$EnhancerBySpringCGLIB$$feed899b.saveAll() - at fyloz.trial.ColorRecipesExplorer.services.MixService.edit(MixService.java:73) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$FastClassBySpringCGLIB$$b1e6729e.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$EnhancerBySpringCGLIB$$4a12209c.edit() - at fyloz.trial.ColorRecipesExplorer.web.controller.editors.MixEditorController.saveMix(MixEditorController.java:113) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 23:11:49 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1237) - at org.h2.jdbc.JdbcPreparedStatement.checkClosed(JdbcPreparedStatement.java:1829) - at org.h2.jdbc.JdbcStatement.checkClosed(JdbcStatement.java:1211) - at org.h2.jdbc.JdbcStatement.getMaxRows(JdbcStatement.java:438) - at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.getMaxRows(HikariProxyPreparedStatement.java) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.close(ResourceRegistryStandardImpl.java:168) - at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.release(ResourceRegistryStandardImpl.java:96) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:276) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:190) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121) - at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86) - at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:188) - at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271) - at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511) - at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481) - at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222) - at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281) - at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124) - at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92) - at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256) - at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:207) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2873) - at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2847) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3482) - at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3451) - at jdk.internal.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at jdk.internal.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy92.find(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:234) - at jdk.internal.reflect.GeneratedMethodAccessor133.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.findById(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.exists(GenericService.java:101) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.isValidForCreation(GenericService.java:89) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:34) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.saveAll(GenericService.java:44) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) - at fyloz.trial.ColorRecipesExplorer.services.MixQuantityService$$EnhancerBySpringCGLIB$$feed899b.saveAll() - at fyloz.trial.ColorRecipesExplorer.services.MixService.edit(MixService.java:73) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$FastClassBySpringCGLIB$$b1e6729e.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$EnhancerBySpringCGLIB$$4a12209c.edit() - at fyloz.trial.ColorRecipesExplorer.web.controller.editors.MixEditorController.saveMix(MixEditorController.java:113) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-18 23:11:50 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosedForWrite(JdbcConnection.java:1557) - at org.h2.jdbc.JdbcConnection.rollback(JdbcConnection.java:561) - at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:370) - at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java) - at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116) - at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294) - at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:145) - at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:559) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:838) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:812) - at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:551) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:298) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) - at fyloz.trial.ColorRecipesExplorer.services.MixQuantityService$$EnhancerBySpringCGLIB$$feed899b.saveAll() - at fyloz.trial.ColorRecipesExplorer.services.MixService.edit(MixService.java:73) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$FastClassBySpringCGLIB$$b1e6729e.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MixService$$EnhancerBySpringCGLIB$$4a12209c.edit() - at fyloz.trial.ColorRecipesExplorer.web.controller.editors.MixEditorController.saveMix(MixEditorController.java:113) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-21 20:33:15 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosedForWrite(JdbcConnection.java:1557) - at org.h2.jdbc.JdbcConnection.rollback(JdbcConnection.java:561) - at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:370) - at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java) - at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116) - at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294) - at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:145) - at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:559) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:838) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:812) - at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:551) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:298) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.save(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:35) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$EnhancerBySpringCGLIB$$5ec775bf.save() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MaterialCreatorController.create(MaterialCreatorController.java:66) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-21 20:36:16 database: flush -org.h2.message.DbException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:157) - at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:115) - at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:78) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:319) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:356) - at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.getDatabase(DatabaseLookup.java:73) - at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:142) - at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter(JpaBaseConfiguration.java:113) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$404e58d0.CGLIB$jpaVendorAdapter$6() - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$404e58d0$$FastClassBySpringCGLIB$$e1ab8b8b.invoke() - at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) - at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$404e58d0.jpaVendorAdapter() - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) - at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:607) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:602) - at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:340) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:168) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:150) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.findByMaterialCode(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService.getByMaterialCode(MaterialService.java:31) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService.exists(MaterialService.java:54) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$FastClassBySpringCGLIB$$a49a3cc9.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$EnhancerBySpringCGLIB$$e9c79557.exists() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MaterialCreatorController.create(MaterialCreatorController.java:65) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 159 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:166) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 153 more -Caused by: java.nio.channels.OverlappingFileLockException - at java.base/sun.nio.ch.FileLockTable.checkList(FileLockTable.java:229) - at java.base/sun.nio.ch.FileLockTable.add(FileLockTable.java:123) - at java.base/sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:1154) - at org.h2.store.fs.FileNio.tryLock(FilePathNio.java:121) - at java.base/java.nio.channels.FileChannel.tryLock(FileChannel.java:1165) - at org.h2.mvstore.FileStore.open(FileStore.java:163) - ... 154 more -2019-08-21 20:37:27 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1547) - at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:347) - at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:311) - at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) - at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:87) - at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172) - at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:72) - at org.hibernate.id.enhanced.SequenceStructure$1.getNextValue(SequenceStructure.java:93) - at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40) - at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:482) - at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:119) - at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:255) - at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:235) - at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:173) - at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) - at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:900) - at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:886) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) - at com.sun.proxy.$Proxy93.merge(Unknown Source) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) - at com.sun.proxy.$Proxy93.merge(Unknown Source) - at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:492) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) - at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) - at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.save(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:35) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$EnhancerBySpringCGLIB$$dd5446b.save() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MaterialCreatorController.create(MaterialCreatorController.java:66) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-21 20:37:27 jdbc[3]: exception -org.h2.jdbc.JdbcSQLNonTransientConnectionException: La base de données est déjà fermée (pour désactiver la fermeture automatique à l'arrêt de la VM, ajoutez "; DB_CLOSE_ON_EXIT = FALSE" à l'URL db) -Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - at org.h2.message.DbException.get(DbException.java:205) - at org.h2.message.DbException.get(DbException.java:181) - at org.h2.message.DbException.get(DbException.java:170) - at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1571) - at org.h2.jdbc.JdbcConnection.checkClosedForWrite(JdbcConnection.java:1557) - at org.h2.jdbc.JdbcConnection.rollback(JdbcConnection.java:561) - at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:370) - at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java) - at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116) - at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294) - at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:145) - at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:559) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:838) - at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:812) - at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:551) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:298) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.save(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:35) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$EnhancerBySpringCGLIB$$dd5446b.save() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MaterialCreatorController.create(MaterialCreatorController.java:66) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -2019-08-21 20:37:27 database: flush -org.h2.message.DbException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.get(DbException.java:194) - at org.h2.message.DbException.convert(DbException.java:347) - at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:90) - at org.h2.mvstore.MVStore.handleException(MVStore.java:2787) - at org.h2.mvstore.MVStore.panic(MVStore.java:441) - at org.h2.mvstore.MVStore.(MVStore.java:404) - at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) - at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) - at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) - at org.h2.engine.Database.getPageStore(Database.java:2739) - at org.h2.engine.Database.open(Database.java:769) - at org.h2.engine.Database.openDatabase(Database.java:319) - at org.h2.engine.Database.(Database.java:313) - at org.h2.engine.Engine.openSession(Engine.java:69) - at org.h2.engine.Engine.openSession(Engine.java:201) - at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) - at org.h2.engine.Engine.createSession(Engine.java:161) - at org.h2.engine.Engine.createSession(Engine.java:31) - at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:169) - at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:148) - at org.h2.Driver.connect(Driver.java:69) - at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136) - at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369) - at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198) - at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467) - at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541) - at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115) - at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) - at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:157) - at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:115) - at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:78) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:319) - at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:356) - at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.getDatabase(DatabaseLookup.java:73) - at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:142) - at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter(JpaBaseConfiguration.java:113) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$78fa35fe.CGLIB$jpaVendorAdapter$6() - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$78fa35fe$$FastClassBySpringCGLIB$$1599e9ac.invoke() - at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) - at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) - at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$78fa35fe.jpaVendorAdapter() - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) - at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:607) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) - at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) - at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:804) - at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:430) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) - at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) - at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) - at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) - at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) - at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) - at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:602) - at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:340) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:168) - at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:150) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) - at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) - at com.sun.proxy.$Proxy99.save(Unknown Source) - at fyloz.trial.ColorRecipesExplorer.services.GenericService.save(GenericService.java:35) - at fyloz.trial.ColorRecipesExplorer.services.GenericService$$FastClassBySpringCGLIB$$b820c443.invoke() - at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) - at fyloz.trial.ColorRecipesExplorer.services.MaterialService$$EnhancerBySpringCGLIB$$dd5446b.save() - at fyloz.trial.ColorRecipesExplorer.web.controller.creators.MaterialCreatorController.create(MaterialCreatorController.java:66) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:567) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) - at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.base/java.lang.Thread.run(Thread.java:835) -Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Erreur générale: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" -General error: "java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7]" [50000-199] - at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) - at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) - ... 158 more -Caused by: java.lang.IllegalStateException: The file is locked: nio:C:/Users/William/Desktop/Dev/Java/Spring/ColorRecipesExplorer/workdir/recipes.mv.db [1.4.199/7] - at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) - at org.h2.mvstore.FileStore.open(FileStore.java:166) - at org.h2.mvstore.MVStore.(MVStore.java:390) - ... 152 more -Caused by: java.nio.channels.OverlappingFileLockException - at java.base/sun.nio.ch.FileLockTable.checkList(FileLockTable.java:229) - at java.base/sun.nio.ch.FileLockTable.add(FileLockTable.java:123) - at java.base/sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:1154) - at org.h2.store.fs.FileNio.tryLock(FilePathNio.java:121) - at java.base/java.nio.channels.FileChannel.tryLock(FileChannel.java:1165) - at org.h2.mvstore.FileStore.open(FileStore.java:163) - ... 153 more