import static java.util.Objects.requireNonNull;
-import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangNetconfError;
import org.opendaylight.yangtools.yang.data.api.YangNetconfErrorAware;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
/**
* Unchecked exception to communicate error information, as defined in the ietf restcong draft, to be sent to the
* @author Thomas Pantelis
*/
public class RestconfDocumentedException extends WebApplicationException {
- @Serial
+ @java.io.Serial
private static final long serialVersionUID = 2L;
private final List<RestconfError> errors;
private final Status status;
+ // FIXME: this field should be non-null
+ private final transient @Nullable EffectiveModelContext modelContext;
+
/**
* Constructs an instance with an error message. The error type defaults to APPLICATION and the error tag defaults
* to OPERATION_FAILED.
}
status = null;
+ modelContext = null;
}
/**
*/
public RestconfDocumentedException(final Status status) {
errors = List.of();
+ modelContext = null;
this.status = requireNonNull(status, "Status can't be null");
}
super(cause, ErrorTags.statusOf(error.getErrorTag()));
errors = List.of(error);
status = null;
+ modelContext = null;
}
public RestconfDocumentedException(final Throwable cause, final List<RestconfError> errors) {
super(cause, ErrorTags.statusOf(errors.get(0).getErrorTag()));
this.errors = List.copyOf(errors);
status = null;
+ modelContext = null;
+ }
+
+ public RestconfDocumentedException(final Throwable cause, final RestconfError error,
+ final EffectiveModelContext modelContext) {
+ super(cause, ErrorTags.statusOf(error.getErrorTag()));
+ errors = List.of(error);
+ status = null;
+ this.modelContext = requireNonNull(modelContext);
}
public static RestconfDocumentedException decodeAndThrow(final String message,
return errorList;
}
+ /**
+ * Reference to {@link EffectiveModelContext} in which this exception was generated. This method will return
+ * {@code null} if this exception was serialized or if the context is not available.
+ *
+ * @return Reference model context
+ */
+ public @Nullable EffectiveModelContext modelContext() {
+ return modelContext;
+ }
+
public List<RestconfError> getErrors() {
return errors;
}
@Override
public void onFailure(final Throwable cause) {
- future.setFailure(TransactionUtil.decodeException(cause, "DELETE", path));
+ future.setFailure(TransactionUtil.decodeException(cause, "DELETE", path, modelContext()));
}
}, MoreExecutors.directExecutor());
}
@Override
public void onFailure(final Throwable cause) {
- future.setFailure(TransactionUtil.decodeException(cause, "MERGE", path));
+ future.setFailure(TransactionUtil.decodeException(cause, "MERGE", path, modelContext));
}
}, MoreExecutors.directExecutor());
}
@Override
public void onFailure(final Throwable cause) {
- ret.setFailure(TransactionUtil.decodeException(cause, "PUT", path));
+ ret.setFailure(TransactionUtil.decodeException(cause, "PUT", path, modelContext));
}
}, MoreExecutors.directExecutor());
@Override
public void onFailure(final Throwable cause) {
- ret.setFailure(TransactionUtil.decodeException(cause, "POST", path));
+ ret.setFailure(TransactionUtil.decodeException(cause, "POST", path, modelContext));
}
}, MoreExecutors.directExecutor());
public void onFailure(final Throwable cause) {
// if errors occurred during transaction commit then patch failed and global errors are reported
ret.set(new PatchStatusContext(modelContext, patch.patchId(), List.copyOf(editCollection), false,
- TransactionUtil.decodeException(cause, "PATCH", null).getErrors()));
+ TransactionUtil.decodeException(cause, "PATCH", null, modelContext).getErrors()));
}
}, MoreExecutors.directExecutor());
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
static @NonNull RestconfDocumentedException decodeException(final Throwable ex, final String txType,
- final YangInstanceIdentifier path) {
+ final YangInstanceIdentifier path, final EffectiveModelContext context) {
if (ex instanceof TransactionCommitFailedException) {
// If device send some error message we want this message to get to client and not just to throw it away
// or override it with new generic message. We search for NetconfDocumentedException that was send from
if (errorTag.equals(ErrorTag.DATA_EXISTS)) {
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
return new RestconfDocumentedException(ex, new RestconfError(ErrorType.PROTOCOL,
- ErrorTag.DATA_EXISTS, "Data already exists", path));
+ ErrorTag.DATA_EXISTS, "Data already exists", path), context);
} else if (errorTag.equals(ErrorTag.DATA_MISSING)) {
LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
return new RestconfDocumentedException(ex, new RestconfError(ErrorType.PROTOCOL,
- ErrorTag.DATA_MISSING, "Data does not exist", path));
+ ErrorTag.DATA_MISSING, "Data does not exist", path), context);
}
} else if (error instanceof NetconfDocumentedException netconfError) {
return new RestconfDocumentedException(netconfError.getMessage(), netconfError.getErrorType(),