All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.restconf.server.OperationsRequestProcessor Maven / Gradle / Ivy

/*
 * Copyright (c) 2024 PANTHEON.tech s.r.o. and others. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.restconf.server;

import static org.opendaylight.restconf.server.Method.GET;
import static org.opendaylight.restconf.server.Method.HEAD;
import static org.opendaylight.restconf.server.Method.OPTIONS;
import static org.opendaylight.restconf.server.Method.POST;
import static org.opendaylight.restconf.server.RequestUtils.extractApiPath;
import static org.opendaylight.restconf.server.RequestUtils.requestBody;
import static org.opendaylight.restconf.server.ResponseUtils.allowHeaderValue;
import static org.opendaylight.restconf.server.ResponseUtils.optionsResponse;
import static org.opendaylight.restconf.server.ResponseUtils.responseBuilder;
import static org.opendaylight.restconf.server.ResponseUtils.simpleResponse;
import static org.opendaylight.restconf.server.ResponseUtils.unmappedRequestErrorResponse;
import static org.opendaylight.restconf.server.ResponseUtils.unsupportedMediaTypeErrorResponse;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.FutureCallback;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.restconf.api.FormattableBody;
import org.opendaylight.restconf.server.api.InvokeResult;
import org.opendaylight.restconf.server.api.JsonOperationInputBody;
import org.opendaylight.restconf.server.api.RestconfServer;
import org.opendaylight.restconf.server.api.XmlOperationInputBody;

/**
 * Static request processor serving operation resource requests.
 *
 * @see RFC 8040.
 * Section 3.3.2. {+restconf}/operations
 */
final class OperationsRequestProcessor {
    @VisibleForTesting
    static final String ALLOW_METHODS = allowHeaderValue(OPTIONS, HEAD, GET, POST);

    private OperationsRequestProcessor() {
        // hidden on purpose
    }

    static void processOperationsRequest(final RequestParameters params, final RestconfServer service,
            final FutureCallback callback) {
        final var apiPath = extractApiPath(params);
        switch (params.method()) {
            case OPTIONS -> callback.onSuccess(optionsResponse(params, ALLOW_METHODS));
            case HEAD, GET -> getOperations(params, service, callback, apiPath);
            case POST -> {
                if (NettyMediaTypes.RESTCONF_TYPES.contains(params.contentType())) {
                    // invoke rpc -> https://datatracker.ietf.org/doc/html/rfc8040#section-4.4.2
                    postOperations(params, service, callback, apiPath);
                } else {
                    callback.onSuccess(unsupportedMediaTypeErrorResponse(params));
                }
            }
            default -> callback.onSuccess(unmappedRequestErrorResponse(params));
        }
    }

    private static void getOperations(final RequestParameters params, final RestconfServer service,
            final FutureCallback callback, final ApiPath apiPath) {
        final var request = new NettyServerRequest(params, callback,
            result -> responseBuilder(params, HttpResponseStatus.OK).setBody(result).build());
        if (apiPath.isEmpty()) {
            service.operationsGET(request);
        } else {
            service.operationsGET(request, apiPath);
        }
    }

    private static void postOperations(final RequestParameters params, final RestconfServer service,
            final FutureCallback callback, final ApiPath apiPath) {
        final var request = new NettyServerRequest(params, callback,
            result -> {
                final var output = result.output();
                return output == null ? simpleResponse(params, HttpResponseStatus.NO_CONTENT)
                    : responseBuilder(params, HttpResponseStatus.OK).setBody(output).build();
            });
        final var operationInputBody = requestBody(params, JsonOperationInputBody::new, XmlOperationInputBody::new);
        service.operationsPOST(request, params.baseUri(), apiPath, operationInputBody);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy