package org.ovirt.engine.core.dal.job;
import java.util.EnumMap;
import java.util.Map;
import java.util.ResourceBundle;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.job.StepEnum;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.MessageResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Contains messages by the context of Job or Step, as read from <i>bundles/ExecutionMessages.properties</i>
*/
public class ExecutionMessageDirector {
public static final String EXECUTION_MESSAGES_FILE_PATH = "bundles/ExecutionMessages";
/**
* The prefix of the job message in the properties file
*/
protected static final String JOB_MESSAGE_PREFIX = "job.";
/**
* The prefix of the step message in the properties file
*/
protected static final String STEP_MESSAGE_PREFIX = "step.";
/**
* A single instance of the {@code ExecutionMessageDirector}
*/
private static ExecutionMessageDirector instance = new ExecutionMessageDirector();
/**
* Logger
*/
private static final Logger log = LoggerFactory.getLogger(ExecutionMessageDirector.class);
/**
* Stores the job messages
*/
private Map<VdcActionType, String> jobMessages = new EnumMap<>(VdcActionType.class);
/**
* Stores the step messages
*/
private Map<StepEnum, String> stepMessages = new EnumMap<>(StepEnum.class);
private ExecutionMessageDirector() {
}
/**
* Load resources files and initialize the messages cache.
*
* @param bundleBaseName
* The base name of the resource bundle
*/
public void initialize(String bundleBaseName) {
log.info("Start initializing {}", getClass().getSimpleName());
ResourceBundle bundle = ResourceBundle.getBundle(bundleBaseName);
final int jobMessagePrefixLength = JOB_MESSAGE_PREFIX.length();
final int stepMessagePrefixLength = STEP_MESSAGE_PREFIX.length();
for (String key : bundle.keySet()) {
if (key.startsWith(JOB_MESSAGE_PREFIX)) {
addMessage(key, bundle.getString(key), jobMessages, VdcActionType.class, jobMessagePrefixLength);
} else if (key.startsWith(STEP_MESSAGE_PREFIX)) {
addMessage(key, bundle.getString(key), stepMessages, StepEnum.class, stepMessagePrefixLength);
} else {
log.error("The message key '{}' cannot be categorized since not started with '{}' nor '{}'",
key,
JOB_MESSAGE_PREFIX,
STEP_MESSAGE_PREFIX);
}
}
log.info("Finished initializing {}", getClass().getSimpleName());
}
/**
* Adds a pair of {@code Enum} and message to the messages map. If the key is not valid, an error message is logged.
* The key should be resolvable as an {@code Enum}, once its prefix is trimmed and the searched for an {@code Enum}
* match by name. Possible entries of (key,value) from the resource bundle:
*
* <pre>
* job.ChangeVMCluster=Change VM ${VM} Cluster to ${Cluster}
* step.VALIDATING=Validating
* </pre>
*
* @param key
* The key of the pair to be added, by which the enum is searched.
* @param value
* The message of the pair to be added
* @param enumClass
* The enum class search for an instance which match the key
* @param messagesMap
* The map whic the message should be added to
* @param prefixLength
* The length of the key prefix
*/
private <T extends Enum<T>> void addMessage(String key,
String value,
Map<T, String> messagesMap,
Class<T> enumClass,
int prefixLength) {
T enumKey;
try {
enumKey = T.valueOf(enumClass, key.substring(prefixLength));
} catch (IllegalArgumentException e) {
log.error("Message key '{}' is not valid for enum '{}'", key, enumClass.getSimpleName());
return;
}
if (!messagesMap.containsKey(key)) {
messagesMap.put(enumKey, value);
} else {
log.warn("Code '{}' appears more than once in '{}' table.", key, enumClass.getSimpleName());
}
}
public static ExecutionMessageDirector getInstance() {
return instance;
}
/**
* Retrieves a message by the step name.
*
* @param stepName
* The name by which the message is retrieved
* @return A message describing the step, or the step name by {@code StepEnum.name()} if not found.
*/
public String getStepMessage(StepEnum stepName) {
return getMessage(stepMessages, stepName);
}
/**
* Retrieves a message by the action type.
*
* @param actionType
* The type by which the message is retrieved
* @return A message describing the action type, or the action type name by {@code VdcActionType.name()} if not
* found.
*/
public String getJobMessage(VdcActionType actionType) {
return getMessage(jobMessages, actionType);
}
private <T extends Enum<T>> String getMessage(Map<T, String> map, T type) {
String message = map.get(type);
if (message == null) {
log.warn("The message key '{}' is missing from '{}'", type.name(), EXECUTION_MESSAGES_FILE_PATH);
message = type.name();
}
return message;
}
public static String resolveJobMessage(VdcActionType actionType, Map<String, String> values) {
String jobMessage = getInstance().getJobMessage(actionType);
if (jobMessage != null) {
return MessageResolver.resolveMessage(jobMessage, values);
} else {
return actionType.name();
}
}
public static String resolveStepMessage(StepEnum stepName, Map<String, String> values) {
String stepMessage = getInstance().getStepMessage(stepName);
if (stepMessage != null) {
return MessageResolver.resolveMessage(stepMessage, values);
} else {
return stepName.name();
}
}
}