2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.nb.rfc8040.databind;
10 import static java.util.Objects.requireNonNull;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.lang.invoke.MethodHandles;
15 import java.lang.invoke.VarHandle;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
19 import org.opendaylight.restconf.common.errors.RestconfError;
20 import org.opendaylight.yangtools.yang.data.api.YangNetconfError;
21 import org.opendaylight.yangtools.yang.data.api.YangNetconfErrorAware;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
26 * An abstract request body backed by an {@link InputStream}.
28 public abstract sealed class AbstractBody implements AutoCloseable
29 permits ChildBody, DataPostBody, OperationInputBody, PatchBody, ResourceBody {
30 private static final Logger LOG = LoggerFactory.getLogger(AbstractBody.class);
32 private static final VarHandle INPUT_STREAM;
36 INPUT_STREAM = MethodHandles.lookup().findVarHandle(AbstractBody.class, "inputStream", InputStream.class);
37 } catch (NoSuchFieldException | IllegalAccessException e) {
38 throw new ExceptionInInitializerError(e);
42 @SuppressWarnings("unused")
43 private volatile InputStream inputStream;
45 AbstractBody(final InputStream inputStream) {
46 this.inputStream = requireNonNull(inputStream);
50 public final void close() {
51 final var is = getStream();
55 } catch (IOException e) {
56 LOG.info("Failed to close input", e);
61 final @NonNull InputStream acquireStream() {
62 final var is = getStream();
64 throw new IllegalStateException("Input stream has already been consumed");
71 * Throw a {@link RestconfDocumentedException} if the specified exception has a {@link YangNetconfError} attachment.
73 * @param cause Proposed cause of a RestconfDocumentedException
75 static void throwIfYangError(final Exception cause) {
76 if (cause instanceof YangNetconfErrorAware infoAware) {
77 throw new RestconfDocumentedException(cause, infoAware.getNetconfErrors().stream()
78 .map(error -> new RestconfError(error.type(), error.tag(), error.message(), error.appTag(),
79 // FIXME: pass down error info
85 private @Nullable InputStream getStream() {
86 return (InputStream) INPUT_STREAM.getAndSet(this, null);