/*
* 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.api;
import static java.util.Objects.requireNonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContext;
import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
import org.opendaylight.yangtools.yang.model.api.stmt.ActionEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
/**
* An {@link ApiPath} resolved against a {@link DatabindContext}. This can be either
*
* - a {@link Data} pointing to a datastore resource, or
* - an {@link Rpc} pointing to a YANG {@code rpc} statement, or
* - an {@link Action} pointing to an instantiation of a YANG {@code action} statement
*
*/
@NonNullByDefault
public sealed interface DatabindPath extends DatabindAware {
/**
* Returns the {@link EffectiveStatementInference} made by this path.
*
* @return the {@link EffectiveStatementInference} made by this path
*/
Inference inference();
/**
* A {@link DatabindPath} denoting an invocation of a YANG {@code action}.
*
* @param databind the {@link DatabindContext} to which this path is bound
* @param inference the {@link EffectiveStatementInference} made by this path
* @param instance the {@link YangInstanceIdentifier} of the instance being referenced, guaranteed to be
* non-empty
* @param action the {@code action}
*/
record Action(
DatabindContext databind,
Inference inference,
YangInstanceIdentifier instance,
ActionEffectiveStatement action) implements OperationPath, InstanceReference {
public Action {
requireNonNull(inference);
requireNonNull(action);
if (instance.isEmpty()) {
throw new IllegalArgumentException("action must be instantiated on a data resource");
}
}
@Override
public InputEffectiveStatement inputStatement() {
return action.input();
}
@Override
public OutputEffectiveStatement outputStatement() {
return action.output();
}
}
/**
* A {@link DatabindPath} denoting a datastore instance.
*
* @param databind the {@link DatabindContext} to which this path is bound
* @param inference the {@link EffectiveStatementInference} made by this path
* @param instance the {@link YangInstanceIdentifier} of the instance being referenced,
* {@link YangInstanceIdentifier#empty()} denotes the datastore
* @param schema the {@link DataSchemaContext} of the datastore instance
*/
// FIXME: split into 'Datastore' and 'Data' with non-empty instance, so we can bind to correct
// instance-identifier semantics, which does not allow YangInstanceIdentifier.empty()
record Data(
DatabindContext databind,
Inference inference,
YangInstanceIdentifier instance,
DataSchemaContext schema) implements InstanceReference {
public Data {
requireNonNull(inference);
requireNonNull(instance);
requireNonNull(schema);
}
// FIXME: this is the 'Datastore' constructor
public Data(final DatabindContext databind) {
this(databind, Inference.ofDataTreePath(databind.modelContext()), YangInstanceIdentifier.of(),
databind.schemaTree().getRoot());
}
}
/**
* A {@link DatabindPath} denoting an invocation of a YANG {@code rpc}.
*
* @param databind the {@link DatabindContext} to which this path is bound
* @param inference the {@link EffectiveStatementInference} made by this path
* @param rpc the {@code rpc}
*/
record Rpc(DatabindContext databind, Inference inference, RpcEffectiveStatement rpc) implements OperationPath {
public Rpc {
requireNonNull(inference);
requireNonNull(rpc);
}
@Override
public InputEffectiveStatement inputStatement() {
return rpc.input();
}
@Override
public OutputEffectiveStatement outputStatement() {
return rpc.output();
}
}
/**
* An intermediate trait of {@link DatabindPath}s which are referencing a YANG data resource. This can be either
* a {@link Data}, or an {@link Action}}.
*/
sealed interface InstanceReference extends DatabindPath {
/**
* Returns the {@link YangInstanceIdentifier} of the instance being referenced.
*
* @return the {@link YangInstanceIdentifier} of the instance being referenced,
* {@link YangInstanceIdentifier#empty()} denotes the data root
*/
YangInstanceIdentifier instance();
/**
* Returns this reference as a {@link ServerErrorPath}.
*
* @return this reference as a {@link ServerErrorPath}
*/
default ServerErrorPath toErrorPath() {
return new ServerErrorPath(databind(), instance());
}
}
/**
* An intermediate trait of {@link DatabindPath}s which are referencing a YANG operation. This can be either
* an {@link Action}, as defined in
* RFC8040 Invoke Operation Mode or
* an {@link Rpc}, as defined in
* RFC8040 Operation Resource.
*/
sealed interface OperationPath extends DatabindPath {
/**
* Returns the {@code input} statement of this operation.
*
* @return the {@code input} statement of this operation
*/
InputEffectiveStatement inputStatement();
/**
* Returns the {@code output} statement of this operation.
*
* @return the {@code output} statement of this operation
*/
OutputEffectiveStatement outputStatement();
}
}