Skip to content
Snippets Groups Projects
Commit e4d2faf6 authored by Olivier Maury's avatar Olivier Maury
Browse files

Prioriser les traitements pour AgroMetInfo. refs #5

parent 80aabe40
No related branches found
No related tags found
1 merge request!7Resolve "Prioriser le calcul pour AgroMetInfo"
Showing
with 242 additions and 17 deletions
......@@ -41,7 +41,7 @@
<log4j.version>2.22.1</log4j.version>
<lombok.version>1.18.30</lombok.version>
<picoli.version>4.7.5</picoli.version>
<season.version>1.2.4</season.version>
<season.version>1.2.6-SNAPSHOT</season.version>
<!-- Maven environment values -->
<build.date>${maven.build.timestamp}</build.date>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
......
......@@ -34,8 +34,10 @@ import java.util.StringJoiner;
import javax.naming.Context;
import fr.agrometinfo.seasonhandler.di.DiHelper;
import fr.agrometinfo.seasonhandler.error.AgroMetInfoException;
import fr.agrometinfo.seasonhandler.error.ConfigurationErrorType;
import fr.inrae.agroclim.indicators.exception.ErrorMessage;
import fr.inrae.agroclim.indicators.exception.TechnicalException;
import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.model.Evaluation;
import fr.inrae.agroclim.indicators.model.EvaluationSettings;
import fr.inrae.agroclim.indicators.resources.I18n;
......@@ -82,6 +84,10 @@ public class MainConfiguration {
* Queue for simulation end.
*/
JMS_SIMULATION_DONE_QUEUE("queue.simulationDoneQueueLookup", false),
/**
* Priority for messages in treatment queue.
*/
JMS_TREATMENT_PRIORITY("queue.treatement.priority", false),
/**
* Queue for outputs.
*/
......@@ -187,6 +193,16 @@ public class MainConfiguration {
return properties.getProperty(key.getKey());
}
/**
* Searches for the property with the specified key in the config.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
*/
public int getInt(final Property key) {
return Integer.parseInt(get(key));
}
/**
* Searches for the property with the specified key and suffix in the config.
*
......@@ -230,25 +246,22 @@ public class MainConfiguration {
*
* @param suffix suffix for the Properties key.
* @return properties for the suffix
* @throws TechnicalException if simulation config is wrong
* @throws AgroMetInfoException if simulation config is wrong
*/
private SimulationProperties getSimulationProperties(final String suffix) throws TechnicalException {
private SimulationProperties getSimulationProperties(final String suffix) throws AgroMetInfoException {
final String propsPath = get(Property.SIMULATION_PATH, suffix);
if (!new File(propsPath).exists()) {
throw new TechnicalException(
i18n.format("error.config.simulation.notexists", Property.SIMULATION_PATH.getKey(), propsPath));
throw new AgroMetInfoException(ConfigurationErrorType.EVALUATION_NOTEXISTS, propsPath);
}
final SimulationProperties props = new SimulationProperties(propsPath, scenarioDao, phenologicalModelDao);
try {
props.load();
} catch (final IOException e) {
throw new TechnicalException(i18n.format("error.config.simulation.load", Property.SIMULATION_PATH.getKey(),
propsPath, e.getLocalizedMessage()));
throw new AgroMetInfoException(ConfigurationErrorType.EVALUATION_LOAD, propsPath, e.getLocalizedMessage());
}
final Collection<ErrorMessage> errors = props.isValid();
if (!errors.isEmpty()) {
throw new TechnicalException(i18n.format("error.config.simulation.notvalid",
Property.SIMULATION_PATH.getKey(), propsPath, errors));
throw new AgroMetInfoException(ConfigurationErrorType.EVALUATION_INVALID, propsPath, errors.toString());
}
return props;
}
......@@ -315,7 +328,7 @@ public class MainConfiguration {
final SimulationProperties props;
try {
props = getSimulationProperties(suffix);
} catch (final TechnicalException e) {
} catch (final AgroMetInfoException e) {
return Optional.of(e.getMessage());
}
final String path;
......@@ -333,7 +346,7 @@ public class MainConfiguration {
try {
settings = (EvaluationSettings) XMLUtil.load(xmlFile, EvaluationSettings.CLASSES_FOR_JAXB);
settings.initializeKnowledge();
} catch (final TechnicalException ex) {
} catch (final IndicatorsException ex) {
return Optional.of(i18n.format("error.config.evaluation.load", path, ex.getLocalizedMessage()));
}
settings.setFilePath(path);
......@@ -445,7 +458,7 @@ public class MainConfiguration {
final SimulationProperties props;
try {
props = getSimulationProperties(suffix);
} catch (final TechnicalException e) {
} catch (final AgroMetInfoException e) {
return Optional.of(e.getMessage());
}
try {
......
......@@ -44,12 +44,16 @@ import lombok.RequiredArgsConstructor;
*/
@RequiredArgsConstructor
public final class DiHelper {
/**
* Path of .property resource.
*/
public static final String BUNDLE_NAME = "fr.agrometinfo.seasonhandler.messages";
/**
* Internationalization resource for the whole application.
*/
@Getter
private static final I18n I18N = new I18n("fr.agrometinfo.seasonhandler.messages", Locale.getDefault());
private static final I18n I18N = new I18n(BUNDLE_NAME, Locale.getDefault());
/**
* App configuration.
......@@ -67,6 +71,7 @@ public final class DiHelper {
receiver.setClimaticScenarioDao(provideClimaticScenarioDao(pm));
receiver.setVarietyParameterDao(provideVarietyParameterDao(pm));
final SimulationLauncher launcher = new SimulationLauncher(config.getDatabaseRoles(), pm);
launcher.setJmsPriority(config.getInt(MainConfiguration.Property.JMS_TREATMENT_PRIORITY));
launcher.setSoftwareOrigin("agrometinfo");
receiver.setLauncher(launcher);
}
......
package fr.agrometinfo.seasonhandler.error;
import fr.inrae.agroclim.indicators.exception.ErrorCategory;
import fr.inrae.agroclim.indicators.exception.ErrorType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* Category for error types in the handler.
*
* @author Olivier Maury
*/
@RequiredArgsConstructor
public enum AgroMetInfoErrorCategory implements ErrorCategory {
/**
* For problems in configuration defined in .property file.
*/
CONFIG("AMI10");
/**
* Category code: prefix for {@link ErrorType#getFullCode()}.
*/
@Getter
private final String code;
@Override
public String getName() {
return name();
}
}
package fr.agrometinfo.seasonhandler.error;
import fr.agrometinfo.seasonhandler.di.DiHelper;
import fr.inrae.agroclim.indicators.exception.ErrorMessage;
import fr.inrae.agroclim.indicators.exception.ErrorMessageException;
import fr.inrae.agroclim.indicators.exception.ErrorType;
import java.io.Serializable;
import java.util.List;
/**
* An exception with {@link ErrorMessage} to describe the error in the handler to the user.
*
* @author Olivier Maury
*/
public class AgroMetInfoException extends ErrorMessageException {
/**
* Path of .property resource.
*/
private static final String BUNDLE_NAME = DiHelper.BUNDLE_NAME;
/**
* UUID for Serializable.
*/
private static final long serialVersionUID = 6030595237342400006L;
/**
* Constructor.
*
* @param errorType Error type.
* @param arguments Arguments for the message.
*/
public AgroMetInfoException(final ErrorType errorType, final Serializable... arguments) {
super(new ErrorMessage(BUNDLE_NAME, errorType, List.of(arguments)));
}
/**
* Constructor.
*
* @param errorType Error type.
* @param arguments Arguments for the message.
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public AgroMetInfoException(final ErrorType errorType, final Throwable cause, final Serializable... arguments) {
super(new ErrorMessage(BUNDLE_NAME, errorType, List.of(arguments)), cause);
}
}
package fr.agrometinfo.seasonhandler.error;
import fr.inrae.agroclim.indicators.exception.ErrorCategory;
import fr.inrae.agroclim.indicators.exception.type.CommonErrorType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* Keys from messages.properties used to warn about errors.
*/
@RequiredArgsConstructor
public enum ConfigurationErrorType implements CommonErrorType {
/**
* The simulation file does not exist.
*
* parameter 0 : simulation path
*/
EVALUATION_NOTEXISTS(null, "001"),
/**
* The evaluation cannot be loaded.
*
* parameter 0 : evaluation path
* prameter 1 : exception message
*/
EVALUATION_LOAD(null, "002"),
/**
* The simulation has errors.
*
* parameter 0 : simulation path
* prameter 1 : errors
*/
EVALUATION_INVALID(null, "003");
/**
* Parent refers to the resource part.
*/
@Getter
private final ConfigurationErrorType parent;
/**
* Subcode for the error.
*/
@Getter
private final String subCode;
@Override
public ErrorCategory getCategory() {
return AgroMetInfoErrorCategory.CONFIG;
}
}
/**
* {@link ErrorType} implementations for error handling.
*/
package fr.agrometinfo.seasonhandler.error;
......@@ -31,6 +31,7 @@ import javax.jms.MessageListener;
import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
import fr.agrometinfo.seasonhandler.MainConfiguration;
import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.model.Evaluation;
import fr.inrae.agroclim.indicators.model.indicator.CompositeIndicator;
import fr.inrae.agroclim.season.core.SimulationLauncher;
......@@ -115,7 +116,7 @@ public final class SafranReceiver implements MessageListener, Runnable {
updateLastDateInTable();
sendEvaluations();
msg.acknowledge();
} catch (final JMSException ex) {
} catch (final IndicatorsException | JMSException ex) {
LOGGER.fatal(ex);
}
} else {
......@@ -132,7 +133,13 @@ public final class SafranReceiver implements MessageListener, Runnable {
consumer.setMessageListener(this);
}
private void sendEvaluation(final Evaluation evaluation, final SimulationProperties props) {
/**
* @param evaluation evaluation to send
* @param props simulation properties
* @throws IndicatorsException should not occur at this point: error while getting XML from evaluation
*/
private void sendEvaluation(final Evaluation evaluation, final SimulationProperties props)
throws IndicatorsException {
final int nbOfYears = varietyParameterDao.varietyParameters(props.getSpecies(), props.getVariety()) //
.getOrDefault("nban", 1.).intValue();
final int doyOffset = (nbOfYears - 1) * 365;
......@@ -183,7 +190,10 @@ public final class SafranReceiver implements MessageListener, Runnable {
LOGGER.info("Simulation is created: #{}", simulationId);
}
private void sendEvaluations() {
/**
* @throws IndicatorsException should not occur at this point: error while getting XML from evaluation
*/
private void sendEvaluations() throws IndicatorsException {
LOGGER.traceEntry("Loop on each evaluation");
final Optional<String> res = config.init();
if (!res.isEmpty()) {
......
......@@ -31,6 +31,7 @@ usage.exitCodeList.1 = 64:Usage error: user input for the command was incorrect.
# Error messages
# --------------
error.config.evaluation.invalid = Evaluation "{0}" has errors: "{1}".
error.config.evaluation.notexists = Evaluation defined in config "{0}" at "{1}" does not exist.
error.config.evaluation.load = Error while loading evaluation "{0}": {1}.
error.config.evaluation.missingaggregation = Missing aggregation in evaluation "{0}".
......
......@@ -31,6 +31,7 @@ usage.exitCodeList.1 = 64:Erreur d'utilisation : les valeurs donn\u00e9es par l'
# Error messages
# --------------
error.config.evaluation.invalid = L'\u00e9valuation \u00ab {0} \u00bb comporte des erreurs : {1}.
error.config.evaluation.notexists = L'\u00e9valuation d\u00e9finie dans la configuration \u00ab {0} \u00bb \u00e0 \u00ab {1} \u00bb n'existe pas.
error.config.evaluation.load = Erreur lors du chargement de l'\u00e9valuation \u00ab {0} \u00bb : {1}.
error.config.evaluation.missingaggregation = Agr\u00e9gation manquante dans l'\u00e9valuation \u00ab {0} \u00bb.
......
......@@ -53,6 +53,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.simulationDoneQueueLookup = simulation-done
queue.treatement.priority = 6
## Same as in running SEASON-cli.
......
package fr.agrometinfo.seasonhandler.error;
import fr.agrometinfo.seasonhandler.di.DiHelper;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import fr.inrae.agroclim.indicators.exception.ErrorType;
import fr.inrae.agroclim.indicators.util.ErrorTypeUtils;
/**
* Ensure all implementations of {@link ErrorType} are well defined.
*
* @author Olivier Maury
*/
class AgroMetInfoErrorTypeTest {
/**
* Where translations are.
*/
private static final String BUNDLE_NAME = DiHelper.BUNDLE_NAME;
/**
* @return classes to test.
*/
public static List<Class<? extends Enum<?>>> data() {
return List.of(ConfigurationErrorType.class);
}
/**
* @param clazz parametrized argument
*/
@ParameterizedTest
@MethodSource("data")
void i18n(final Class<? extends Enum<?>> clazz) {
final Map<Locale, Map<Class<?>, List<String>>> missing = ErrorTypeUtils.getMissingTranslations(clazz,
BUNDLE_NAME, List.of(Locale.ENGLISH, Locale.FRENCH));
assertTrue(missing.isEmpty(), "Missing translations in " + BUNDLE_NAME + ": " + missing.toString());
}
/**
* @param clazz parametrized argument
*/
@ParameterizedTest
@MethodSource("data")
void subCodeAreUnique(final Class<? extends Enum<?>> clazz) {
final Set<String> duplicates = ErrorTypeUtils.getDuplicatedCodes(clazz);
assertTrue(duplicates.isEmpty());
}
}
......@@ -13,6 +13,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.treatement.priority = 6
## Same as in running SEASON-cli.
season.results.table.owner = season
......
......@@ -14,6 +14,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.simulationDoneQueueLookup = simulation-done
queue.treatement.priority = 6
## Same as in running SEASON-cli.
......
......@@ -14,6 +14,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.simulationDoneQueueLookup = simulation-done
queue.treatement.priority = 6
## Same as in running SEASON-cli.
......
......@@ -14,6 +14,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.simulationDoneQueueLookup = simulation-done
queue.treatement.priority = 6
## Same as in running SEASON-cli.
season.results.table.owner = season
......
......@@ -14,6 +14,7 @@ java.naming.provider.url = tcp://localhost:61616?reconnectAttempts=-1
queue.newSafranDataQueueLookup = agrometinfo-new-safran-data
queue.treatmentQueueLookup = treatment
queue.simulationDoneQueueLookup = simulation-done
queue.treatement.priority = 6
## Same as in running SEASON-cli.
season.results.table.owner = season
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment