com.example.provider1.OperationHandler Maven / Gradle / Ivy
Show all versions of glue-examples Show documentation
package com.example.provider1;
import com.example.Constants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jspecify.annotations.NonNull;
import org.somda.sdc.biceps.common.MdibStateModifications;
import org.somda.sdc.biceps.common.storage.PreprocessingException;
import org.somda.sdc.biceps.model.message.Activate;
import org.somda.sdc.biceps.model.message.InvocationError;
import org.somda.sdc.biceps.model.message.InvocationState;
import org.somda.sdc.biceps.model.message.SetString;
import org.somda.sdc.biceps.model.message.SetValue;
import org.somda.sdc.biceps.model.participant.AbstractMetricDescriptor;
import org.somda.sdc.biceps.model.participant.EnumStringMetricDescriptor;
import org.somda.sdc.biceps.model.participant.LocalizedText;
import org.somda.sdc.biceps.model.participant.NumericMetricDescriptor;
import org.somda.sdc.biceps.model.participant.NumericMetricState;
import org.somda.sdc.biceps.model.participant.NumericMetricValue;
import org.somda.sdc.biceps.model.participant.SetStringOperationDescriptor;
import org.somda.sdc.biceps.model.participant.SetValueOperationDescriptor;
import org.somda.sdc.biceps.model.participant.StringMetricState;
import org.somda.sdc.biceps.model.participant.StringMetricValue;
import org.somda.sdc.biceps.provider.access.LocalMdibAccess;
import org.somda.sdc.glue.provider.sco.Context;
import org.somda.sdc.glue.provider.sco.InvocationResponse;
import org.somda.sdc.glue.provider.sco.OperationInvocationReceiver;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
/**
* This class provides a handler for incoming operations on the sdc provider.
*
* It implements generic handlers for some operations, which enables handling operations easily, although
* a real application should be a little more specialized in its handling.
*/
public class OperationHandler implements OperationInvocationReceiver {
private static final Logger LOG = LogManager.getLogger(OperationHandler.class);
private final LocalMdibAccess mdibAccess;
public OperationHandler(LocalMdibAccess mdibAccess) {
this.mdibAccess = mdibAccess;
}
LocalizedText createLocalizedText(String text) {
return createLocalizedText(text, "en");
}
LocalizedText createLocalizedText(String text, String lang) {
var localizedText = new LocalizedText();
localizedText.setValue(text);
localizedText.setLang(lang);
return localizedText;
}
@NonNull
@Override
public InvocationResponse handleSetValue(@NonNull Context context, @NonNull String operationHandle,
@NonNull SetValue setValue) throws Exception {
if (!operationHandle.equals(Constants.HANDLE_SET_VALUE)) {
throw new Exception(String.format("No handler for %s", operationHandle));
}
// TODO: Check if state is modifiable
context.sendSuccessfulReport(InvocationState.START);
var data = setValue.getRequestedNumericValue();
LOG.debug("Received SetValue request for {}: {}", operationHandle, data);
// find operation target
var setNumeric =
mdibAccess.getDescriptor(operationHandle, SetValueOperationDescriptor.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target cannot be found");
context.sendUnsuccessfulReport(
InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation descriptor %s missing", operationHandle)
);
}
);
String operationTargetHandle = setNumeric.getOperationTarget();
var targetDesc =
mdibAccess.getDescriptor(operationTargetHandle, NumericMetricDescriptor.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target cannot be found");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation target descriptor %s missing", operationTargetHandle)
);
});
// find allowed range for descriptor and verify it's within
targetDesc.getTechnicalRange().forEach(range -> {
if (range.getLower() != null && range.getLower().compareTo(data) > 0) {
// value too small
var errorMessage = createLocalizedText("Value too small");
context.sendUnsuccessfulReport(
InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
throw new RuntimeException(
String.format("Operation set value below lower limit of %s, was %s",
range.getLower(), data)
);
}
if (range.getUpper() != null && range.getUpper().compareTo(data) < 0) {
// value too big
var errorMessage = createLocalizedText("Value too big");
context.sendUnsuccessfulReport(
InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
throw new RuntimeException(
String.format("Operation set value below lower limit of %s, was %s",
range.getLower(), data)
);
}
}
);
var targetState = mdibAccess.getState(operationTargetHandle, NumericMetricState.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target state cannot be found");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation target descriptor %s missing", operationTargetHandle)
);
});
if (targetState.getMetricValue() == null) {
targetState.setMetricValue(new NumericMetricValue());
}
targetState.getMetricValue().setValue(data);
targetState.getMetricValue().setDeterminationTime(Instant.now());
ProviderUtil.addMetricQualityDemo(targetState.getMetricValue());
final var mod = new MdibStateModifications.Metric(List.of(targetState));
try {
mdibAccess.writeStates(mod);
context.sendSuccessfulReport(InvocationState.FIN);
return context.createSuccessfulResponse(InvocationState.FIN);
} catch (PreprocessingException e) {
LOG.error("Error while writing states", e);
var errorMessage = createLocalizedText("Error while writing states");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.UNSPEC, List.of(errorMessage));
return context.createUnsuccessfulResponse(
InvocationState.FAIL, InvocationError.UNSPEC, List.of(errorMessage));
}
}
@NonNull
@Override
public InvocationResponse handleSetString(@NonNull Context context, @NonNull String operationHandle,
@NonNull SetString setString) throws Exception {
if (!(operationHandle.equals(Constants.HANDLE_SET_STRING) || operationHandle.equals(Constants.HANDLE_SET_STRING_ENUM))) {
throw new Exception(String.format("No handler for %s", operationHandle));
}
// TODO: Check if state is modifiable
context.sendSuccessfulReport(InvocationState.START);
var data = setString.getRequestedStringValue();
LOG.debug("Received SetString for {}: {}", operationHandle, data);
// find operation target
var setStringOperation =
mdibAccess.getDescriptor(operationHandle, SetStringOperationDescriptor.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target cannot be found");
context.sendUnsuccessfulReport(
InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation descriptor %s missing", operationHandle)
);
}
);
String operationTargetHandle = setStringOperation.getOperationTarget();
var targetDescriptor = mdibAccess.getDescriptor(operationTargetHandle, AbstractMetricDescriptor.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target descriptor cannot be found");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation target descriptor %s missing", operationTargetHandle)
);
});
var isEnumString = (targetDescriptor instanceof EnumStringMetricDescriptor);
// verify if new data is allowed for enum strings
if (isEnumString) {
var targetDesc = mdibAccess.getDescriptor(
operationTargetHandle, EnumStringMetricDescriptor.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target descriptor cannot be found");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation target descriptor %s missing", operationTargetHandle)
);
});
// validate data is allowed
Optional first =
targetDesc.getAllowedValue().stream().filter(x -> x.getValue().equals(data)).findFirst();
if (first.isEmpty()) {
// not allowed value, bye bye
var errormessage = createLocalizedText("Value is not allowed here");
return context.createUnsuccessfulResponse(mdibAccess.getMdibVersion(),
InvocationState.FAIL, InvocationError.UNSPEC, List.of(errormessage));
}
}
var targetState = mdibAccess.getState(operationTargetHandle, StringMetricState.class).orElseThrow(() -> {
var errorMessage = createLocalizedText("Operation target state cannot be found");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.OTH, List.of(errorMessage));
return new RuntimeException(
String.format("Operation target descriptor %s missing", operationTargetHandle)
);
});
if (targetState.getMetricValue() == null) {
targetState.setMetricValue(new StringMetricValue());
}
targetState.getMetricValue().setValue(data);
targetState.getMetricValue().setDeterminationTime(Instant.now());
ProviderUtil.addMetricQualityDemo(targetState.getMetricValue());
final var mod = new MdibStateModifications.Metric(List.of(targetState));
try {
mdibAccess.writeStates(mod);
context.sendSuccessfulReport(InvocationState.FIN);
return context.createSuccessfulResponse(InvocationState.FIN);
} catch (PreprocessingException e) {
LOG.error("Error while writing states", e);
var errorMessage = createLocalizedText("Error while writing states");
context.sendUnsuccessfulReport(InvocationState.FAIL, InvocationError.UNSPEC, List.of(errorMessage));
return context.createUnsuccessfulResponse(InvocationState.FAIL,
InvocationError.UNSPEC, List.of(errorMessage));
}
}
@NonNull
@Override
public InvocationResponse handleActivate(@NonNull Context context, @NonNull String operationHandle,
@NonNull Activate activate) throws Exception {
if (!(operationHandle.equals(Constants.HANDLE_ACTIVATE) || operationHandle.equals("actop.mds0_sco_0"))) {
throw new Exception(String.format("No handler for %s", operationHandle));
}
context.sendSuccessfulReport(InvocationState.START);
LOG.info("Received Activate for {}", operationHandle);
context.sendSuccessfulReport(InvocationState.FIN);
return context.createSuccessfulResponse(mdibAccess.getMdibVersion(), InvocationState.FIN);
}
}