/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2022 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,
import org.opendaylight.mdsal.dom.api.DOMActionResult;
import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
-import org.opendaylight.mdsal.dom.api.DOMNotification;
-import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
-public interface MessageTransformer {
-
- DOMNotification toNotification(NetconfMessage message);
-
- NetconfMessage toRpcRequest(QName rpc, NormalizedNode node);
-
- DOMRpcResult toRpcResult(NetconfMessage message, QName rpc);
-
+/**
+ * Interface for transforming NETCONF device action request/response messages.
+ */
+public interface ActionTransformer {
/**
* Parse action into message for request.
*
* @param payload - input of action
* @return message
*/
- default NetconfMessage toActionRequest(final Absolute action, final DOMDataTreeIdentifier domDataTreeIdentifier,
- final NormalizedNode payload) {
- throw new UnsupportedOperationException();
- }
+ NetconfMessage toActionRequest(Absolute action, DOMDataTreeIdentifier domDataTreeIdentifier,
+ NormalizedNode payload);
/**
* Parse result of invoking action into DOM result.
* @param message - message to parsing
* @return {@link DOMActionResult}
*/
- default DOMActionResult toActionResult(final Absolute action, final NetconfMessage message) {
- throw new UnsupportedOperationException();
- }
+ DOMActionResult toActionResult(Absolute action, NetconfMessage message);
}
* @param listener - allows specific service to send and receive messages to/from device
* @return {@link Actions} of specific device
*/
- @NonNull Actions createDeviceAction(MessageTransformer messageTransformer, RemoteDeviceCommunicator listener);
+ @NonNull Actions createDeviceAction(ActionTransformer messageTransformer, RemoteDeviceCommunicator listener);
}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.netconf.sal.connect.api;
+
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.netconf.api.NetconfMessage;
+
+/**
+ * Interface for transforming NETCONF device {@link NetconfMessage}s to {@link DOMNotification}.
+ */
+public interface NotificationTransformer {
+
+ DOMNotification toNotification(NetconfMessage message);
+}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.netconf.sal.connect.api;
+
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface for transforming NETCONF device RPC request/response messages.
+ */
+public interface RpcTransformer {
+
+ NetconfMessage toRpcRequest(QName rpc, NormalizedNode node);
+
+ DOMRpcResult toRpcResult(NetconfMessage message, QName rpc);
+}
import com.google.common.util.concurrent.MoreExecutors;
import javax.inject.Singleton;
import org.opendaylight.mdsal.dom.api.DOMActionService;
+import org.opendaylight.netconf.sal.connect.api.ActionTransformer;
import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices.Actions;
import org.osgi.service.component.annotations.Component;
/**
* Implementation of the factory for creation of {@link DOMActionService} instances that are provided by device.
- * {@link DOMActionService} is implemented using {@link MessageTransformer} that builds NETCONF RPCs and
+ * {@link DOMActionService} is implemented using {@link ActionTransformer} that builds NETCONF RPCs and
* transforms replied NETCONF message to action result, and using {@link RemoteDeviceCommunicator} that is responsible
* for sending of built RPCs to NETCONF client.
*/
private static final Logger LOG = LoggerFactory.getLogger(DeviceActionFactoryImpl.class);
@Override
- public Actions.Normalized createDeviceAction(final MessageTransformer messageTransformer,
+ public Actions.Normalized createDeviceAction(final ActionTransformer messageTransformer,
final RemoteDeviceCommunicator listener) {
return (schemaPath, dataTreeIdentifier, input) -> {
requireNonNull(schemaPath);
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
private boolean connected = false;
// Message transformer is constructed once the schemas are available
- private MessageTransformer messageTransformer;
+ private NetconfMessageTransformer messageTransformer;
public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final BaseNetconfSchemas baseSchemas,
final RemoteDeviceId id, final RemoteDeviceHandler salFacade,
updateTransformer(null);
}
- private synchronized void updateTransformer(final MessageTransformer transformer) {
+ private synchronized void updateTransformer(final NetconfMessageTransformer transformer) {
messageTransformer = transformer;
}
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlUtil;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.NotificationTransformer;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.slf4j.Logger;
private boolean passNotifications = false;
private NotificationFilter filter;
- private MessageTransformer messageTransformer;
+ private NotificationTransformer messageTransformer;
NotificationHandler(final RemoteDeviceHandler salFacade, final RemoteDeviceId id) {
this.salFacade = requireNonNull(salFacade);
* Forward all cached notifications and pass all notifications from this point directly to sal facade.
* @param transformer Message transformer
*/
- synchronized void onRemoteSchemaUp(final MessageTransformer transformer) {
+ synchronized void onRemoteSchemaUp(final NotificationTransformer transformer) {
messageTransformer = requireNonNull(transformer);
passNotifications = true;
import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices.Rpcs;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.NoOpListenerRegistration;
import org.opendaylight.yangtools.yang.common.QName;
*/
public final class NetconfDeviceRpc implements Rpcs.Normalized {
private final RemoteDeviceCommunicator communicator;
- private final MessageTransformer transformer;
+ private final RpcTransformer transformer;
private final EffectiveModelContext modelContext;
public NetconfDeviceRpc(final EffectiveModelContext modelContext, final RemoteDeviceCommunicator communicator,
- final MessageTransformer transformer) {
+ final RpcTransformer transformer) {
this.modelContext = requireNonNull(modelContext);
this.communicator = communicator;
this.transformer = transformer;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices.Rpcs;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseRpcSchemalessTransformer;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.SchemalessMessageTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
@Override
public ListenableFuture<? extends DOMRpcResult> invokeRpc(final QName type, final NormalizedNode input) {
- final MessageTransformer transformer;
+ final RpcTransformer transformer;
if (input instanceof DOMSourceAnyxmlNode) {
transformer = schemalessTransformer;
} else if (isBaseRpc(type)) {
}
private @NonNull ListenableFuture<DOMRpcResult> handleRpc(final @NonNull QName type,
- final @NonNull NormalizedNode input, final MessageTransformer transformer) {
+ final @NonNull NormalizedNode input, final RpcTransformer transformer) {
final var delegateFuture = listener.sendRequest(transformer.toRpcRequest(type, input), type);
final var ret = SettableFuture.<DOMRpcResult>create();
Futures.addCallback(delegateFuture, new FutureCallback<>() {
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
-import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlElement;
import org.opendaylight.netconf.api.xml.XmlUtil;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.MessageCounter;
import org.opendaylight.yangtools.yang.common.QName;
/**
* Transforms base netconf RPCs.
*/
-public class BaseRpcSchemalessTransformer implements MessageTransformer {
+public class BaseRpcSchemalessTransformer implements RpcTransformer {
private final ImmutableMap<QName, ? extends RpcDefinition> mappedRpcs;
private final EffectiveModelContext modelContext;
private final MessageCounter counter;
this.counter = counter;
}
- @Override
- public DOMNotification toNotification(final NetconfMessage message) {
- throw new UnsupportedOperationException("Notifications not supported.");
- }
-
@Override
public NetconfMessage toRpcRequest(final QName rpc, final NormalizedNode payload) {
// In case no input for rpc is defined, we can simply construct the payload here
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.MissingNameSpaceException;
import org.opendaylight.netconf.api.xml.XmlElement;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.ActionTransformer;
+import org.opendaylight.netconf.sal.connect.api.NotificationTransformer;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.MessageCounter;
import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
-public class NetconfMessageTransformer implements MessageTransformer {
+public class NetconfMessageTransformer implements ActionTransformer, NotificationTransformer, RpcTransformer {
private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageTransformer.class);
private static final ImmutableSet<XMLNamespace> BASE_OR_NOTIFICATION_NS = ImmutableSet.of(
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.MissingNameSpaceException;
import org.opendaylight.netconf.api.xml.XmlElement;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.NotificationTransformer;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.MessageCounter;
import org.opendaylight.yangtools.yang.common.QName;
/**
* Transforms anyxml rpcs for schemaless netconf devices.
*/
-public class SchemalessMessageTransformer implements MessageTransformer {
+public class SchemalessMessageTransformer implements NotificationTransformer, RpcTransformer {
// TODO maybe we should move this somewhere else as this
// might be used in applications using schemaless mountpoints
public static final NodeIdentifier SCHEMALESS_NOTIFICATION_PAYLOAD =
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.api.xml.XmlUtil;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
}
- public MessageTransformer getMessageTransformer() throws Exception {
- final MessageTransformer messageTransformer = mockClass(MessageTransformer.class);
- doReturn(NOTIFICATION).when(messageTransformer).toRpcRequest(any(QName.class), any(NormalizedNode.class));
- doReturn(RPC_RESULT).when(messageTransformer).toRpcResult(any(NetconfMessage.class), any(QName.class));
- doReturn(COMPOSITE_NODE).when(messageTransformer).toNotification(any(NetconfMessage.class));
- return messageTransformer;
- }
-
public NetconfSessionPreferences getSessionCaps(final boolean addMonitor,
final Collection<String> additionalCapabilities) {
final ArrayList<String> capabilities = Lists.newArrayList(
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlUtil;
-import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
import org.opendaylight.netconf.sal.connect.netconf.AbstractBaseSchemasTest;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
@Test
public void testDeadlock() throws Exception {
// when rpc is successful, but transformer fails for some reason
- final MessageTransformer failingTransformer = mock(MessageTransformer.class);
+ final RpcTransformer failingTransformer = mock(RpcTransformer.class);
final RemoteDeviceCommunicator communicatorMock = mock(RemoteDeviceCommunicator.class);
final NetconfMessage msg = null;
final RpcResult<NetconfMessage> result = RpcResultBuilder.success(msg).build();
transformer = new BaseRpcSchemalessTransformer(BASE_SCHEMAS, new MessageCounter());
}
- @Test(expected = UnsupportedOperationException.class)
- public void toNotification() throws Exception {
- transformer.toNotification(new NetconfMessage(
- XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/notification-payload.xml"))));
- }
-
@Test
public void toRpcRequest() throws Exception {
final Document doc =