
uk.num.numlib.internal.modl.ModlServices Maven / Gradle / Ivy
package uk.num.numlib.internal.modl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.modl.interpreter.Interpreter;
import uk.modl.modlObject.ModlObject;
import uk.modl.modlObject.ModlValue;
import uk.modl.parser.printers.JsonPrinter;
import uk.num.numlib.exc.NumBadRecordException;
import uk.num.numlib.internal.module.ModuleConfig;
import java.util.ArrayList;
/**
* A class to act as a facade for the MODL interpreter.
*
* @author tonywalmsley
*/
public class ModlServices {
private static final Logger LOG = LoggerFactory.getLogger(ModlServices.class);
/**
* A Jackson object mapper to create the ModuleConfig object from JSON.
*/
private ObjectMapper objectMapper;
/**
* Default constructor
*/
public ModlServices() {
objectMapper = new ObjectMapper();
}
/**
* Interpret a module configuration MODL object.
*
* @param configTxt The MODL string
* @return A ModuleConfig object.
* @throws NumBadRecordException on error
*/
public ModuleConfig interpretModuleConfig(final String configTxt) throws NumBadRecordException {
assert configTxt != null && configTxt.trim()
.length() > 0;
LOG.trace("Interpreting Module Config: {}", configTxt);
try {
final ModlObject modlObject = Interpreter.interpret(configTxt, new ArrayList<>());
final String configJson = JsonPrinter.printModl(modlObject);
LOG.trace("Interpreted result: {}", configJson);
return objectMapper.readValue(configJson, ModuleConfig.class);
} catch (final Exception e) {
LOG.error("Exception during interpretModuleConfig().", e);
throw new NumBadRecordException("Error interpreting module config file.", e);
}
}
/**
* Interpret a NUM record MODL string to a JSON String.
*
* @param numRecord The NUM record string.
* @return The interpreted result as a JSON string.
* @throws NumBadRecordException on error
* @throws NumQueryRedirect on error
* @throws NumLookupRedirect on error
*/
public String interpretNumRecord(final String numRecord) throws NumBadRecordException, NumQueryRedirect,
NumLookupRedirect {
assert numRecord != null && numRecord.trim()
.length() > 0;
LOG.trace("Interpreting NUM record: {}", numRecord);
try {
final ModlObject modlObject = Interpreter.interpret(numRecord, new ArrayList<>());
checkForRedirection(modlObject);
return JsonPrinter.printModl(modlObject);
} catch (Exception e) {
LOG.error("Exception during interpretNumRecord().", e);
throw new NumBadRecordException("Error interpreting NUM record.", e);
}
}
/**
* Look for a redirect instruction in the interpreted NUM record.
*
* @param modlObject the interpreted NUM record
* @throws NumQueryRedirect on error
* @throws NumLookupRedirect on error
*/
private void checkForRedirection(final ModlObject modlObject) throws NumQueryRedirect, NumLookupRedirect {
if (modlObject.getStructures() != null) {
for (final ModlObject.Structure structure : modlObject.getStructures()) {
findRedirect(structure);
}
}
}
/**
* Look for a redirect instruction in the interpreted NUM record, recursively.
*
* @param structure the ModlValue to check.
* @throws NumQueryRedirect on error
* @throws NumLookupRedirect on error
*/
private void findRedirect(final ModlValue structure) throws NumQueryRedirect, NumLookupRedirect {
// If its a Pair then check whether the key indicates a redirect.
if (structure instanceof ModlObject.Pair) {
final ModlObject.Pair pair = (ModlObject.Pair) structure;
// Check for q_
if ("q_".equals(pair.getKey().string)) {
final Object value = pair.getValue();
if (value instanceof ModlObject.String) {
final ModlObject.String str = (ModlObject.String) value;
throw new NumQueryRedirect(str.string);
}
}
// Check for l_
if ("l_".equals(pair.getKey().string)) {
final Object value = pair.getValue();
if (value instanceof ModlObject.String) {
final ModlObject.String str = (ModlObject.String) value;
throw new NumLookupRedirect(str.string);
}
}
findRedirect(pair.getModlValue());
}
// Check the pairs in a Map
if (structure instanceof ModlObject.Map) {
final ModlObject.Map map = (ModlObject.Map) structure;
for (ModlObject.Pair pair : map.getPairs()) {
findRedirect(pair);
}
}
// Check the pairs in an Array
if (structure instanceof ModlObject.Array) {
final ModlObject.Array array = (ModlObject.Array) structure;
for (ModlValue modlValue : array.getModlValues()) {
findRedirect(modlValue);
}
}
}
/**
* Interpret a NUM record response from the populator.
*
* @param numRecord The NUM record string.
* @return The interpreted result as a PopulatorResponse object.
* @throws NumBadRecordException on error
*/
public PopulatorResponse interpretPopulatorResponse(final String numRecord) throws NumBadRecordException {
assert numRecord != null && numRecord.trim()
.length() > 0;
LOG.trace("Interpreting populator response record: {}", numRecord);
try {
final ModlObject modlObject = Interpreter.interpret(numRecord, new ArrayList<>());
final String json = JsonPrinter.printModl(modlObject);
LOG.trace("Interpreted populator response: {}", json);
final PopulatorResponse response = objectMapper.readValue(json, PopulatorResponse.class);
if (!response.isValid() && response.getStatus_() == null) {
// We have a valid MODL record because we didn't get any errors from the interpreter, so it must be a
// TXT record. Set the status to indicate this and return the MODL record in the response object.
final PopulatorResponseRecord status_ = new PopulatorResponseRecord();
status_.setCode(PopulatorResponse.VALID_TXT_RECORD_CODE);
status_.setDescription("TXT Record");
response.setStatus_(status_);
response.setNUMRecord(numRecord);
}
return response;
} catch (Exception e) {
LOG.error("Exception during interpretPopulatorResponse().", e);
throw new NumBadRecordException("Error interpreting populator response record.", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy