81d396a37ad229dbd9f81feaa8f91910afe26088
[netconf.git] / netconf / tools / netconf-testtool / src / main / java / org / opendaylight / netconf / test / tool / MdsalOperationProvider.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.test.tool;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.MoreExecutors;
13 import java.util.EnumMap;
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.ExecutorService;
19 import java.util.function.Consumer;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
22 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
23 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
24 import org.opendaylight.mdsal.dom.api.DOMSchemaService.YangTextSourceExtension;
25 import org.opendaylight.mdsal.dom.broker.SerializedDOMDataBroker;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
27 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStoreFactory;
28 import org.opendaylight.netconf.server.api.SessionIdProvider;
29 import org.opendaylight.netconf.server.api.monitoring.Capability;
30 import org.opendaylight.netconf.server.api.monitoring.CapabilityListener;
31 import org.opendaylight.netconf.server.api.operations.NetconfOperation;
32 import org.opendaylight.netconf.server.api.operations.NetconfOperationService;
33 import org.opendaylight.netconf.server.api.operations.NetconfOperationServiceFactory;
34 import org.opendaylight.netconf.server.mdsal.CurrentSchemaContext;
35 import org.opendaylight.netconf.server.mdsal.TransactionProvider;
36 import org.opendaylight.netconf.server.mdsal.operations.Commit;
37 import org.opendaylight.netconf.server.mdsal.operations.DiscardChanges;
38 import org.opendaylight.netconf.server.mdsal.operations.EditConfig;
39 import org.opendaylight.netconf.server.mdsal.operations.Get;
40 import org.opendaylight.netconf.server.mdsal.operations.GetConfig;
41 import org.opendaylight.netconf.server.mdsal.operations.Lock;
42 import org.opendaylight.netconf.server.mdsal.operations.Unlock;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
48 import org.opendaylight.yangtools.concepts.Registration;
49 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
50 import org.opendaylight.yangtools.yang.common.QName;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
55 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
60 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
61 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
62 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 class MdsalOperationProvider implements NetconfOperationServiceFactory {
67     private static final Logger LOG = LoggerFactory.getLogger(MdsalOperationProvider.class);
68
69     private final Set<Capability> caps;
70     private final EffectiveModelContext schemaContext;
71     private final YangTextSourceExtension sourceProvider;
72
73     MdsalOperationProvider(final SessionIdProvider idProvider,
74                            final Set<Capability> caps,
75                            final EffectiveModelContext schemaContext,
76                            final YangTextSourceExtension sourceProvider) {
77         this.caps = caps;
78         this.schemaContext = schemaContext;
79         this.sourceProvider = sourceProvider;
80     }
81
82     @Override
83     public Set<Capability> getCapabilities() {
84         return caps;
85     }
86
87     @Override
88     public Registration registerCapabilityListener(final CapabilityListener listener) {
89         listener.onCapabilitiesChanged(caps, Set.of());
90         return () -> { };
91     }
92
93     @Override
94     public NetconfOperationService createService(final SessionIdType sessionId) {
95         return new MdsalOperationService(sessionId, schemaContext, caps, sourceProvider);
96     }
97
98     static class MdsalOperationService implements NetconfOperationService {
99         private final SessionIdType currentSessionId;
100         private final EffectiveModelContext schemaContext;
101         private final Set<Capability> caps;
102         private final DOMSchemaService schemaService;
103         private final DOMDataBroker dataBroker;
104         private final YangTextSourceExtension sourceProvider;
105
106         MdsalOperationService(final SessionIdType currentSessionId, final EffectiveModelContext schemaContext,
107                               final Set<Capability> caps, final YangTextSourceExtension sourceProvider) {
108             this.currentSessionId = requireNonNull(currentSessionId);
109             this.schemaContext = schemaContext;
110             this.caps = caps;
111             this.sourceProvider = sourceProvider;
112             schemaService = createSchemaService();
113
114             dataBroker = createDataStore(schemaService, currentSessionId);
115         }
116
117         @Override
118         public Set<NetconfOperation> getNetconfOperations() {
119             ContainerNode netconf = createNetconfState();
120
121             final DOMDataTreeWriteTransaction tx = dataBroker.newWriteOnlyTransaction();
122             tx.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.of(NetconfState.QNAME), netconf);
123
124             try {
125                 tx.commit().get();
126                 LOG.debug("Netconf state updated successfully");
127             } catch (InterruptedException | ExecutionException e) {
128                 LOG.warn("Unable to update netconf state", e);
129             }
130
131             TransactionProvider transactionProvider = new TransactionProvider(dataBroker, currentSessionId);
132             CurrentSchemaContext currentSchemaContext = CurrentSchemaContext.create(schemaService, sourceProvider);
133
134             final Get get = new Get(currentSessionId, currentSchemaContext, transactionProvider);
135             final EditConfig editConfig = new EditConfig(currentSessionId, currentSchemaContext, transactionProvider);
136             final GetConfig getConfig = new GetConfig(currentSessionId, currentSchemaContext, transactionProvider);
137             final Commit commit = new Commit(currentSessionId, transactionProvider);
138             final Lock lock = new Lock(currentSessionId);
139             final Unlock unLock = new Unlock(currentSessionId);
140             final DiscardChanges discardChanges = new DiscardChanges(currentSessionId, transactionProvider);
141
142             return Set.of(get, getConfig, editConfig, commit, lock, unLock, discardChanges);
143         }
144
145         @Override
146         public void close() {
147             // No-op
148         }
149
150         private ContainerNode createNetconfState() {
151             final DummyMonitoringService monitor = new DummyMonitoringService(caps);
152             final QName identifier = QName.create(Schema.QNAME, "identifier");
153             final QName version = QName.create(Schema.QNAME, "version");
154             final QName format = QName.create(Schema.QNAME, "format");
155             final QName location = QName.create(Schema.QNAME, "location");
156             final QName namespace = QName.create(Schema.QNAME, "namespace");
157
158             CollectionNodeBuilder<MapEntryNode, SystemMapNode> schemaMapEntryNodeMapNodeCollectionNodeBuilder =
159                 Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(Schema.QNAME));
160             LeafSetNode<String> locationLeafSet = Builders.<String>leafSetBuilder()
161                 .withNodeIdentifier(new NodeIdentifier(location))
162                 .withChild(Builders.<String>leafSetEntryBuilder()
163                     .withNodeIdentifier(new NodeWithValue<>(location, "NETCONF"))
164                     .withValue("NETCONF")
165                     .build())
166                 .build();
167
168             Map<QName, Object> keyValues = new HashMap<>();
169             for (final Schema schema : monitor.getSchemas().nonnullSchema().values()) {
170                 keyValues.put(identifier, schema.getIdentifier());
171                 keyValues.put(version, schema.getVersion());
172                 keyValues.put(format, Yang.QNAME);
173
174                 schemaMapEntryNodeMapNodeCollectionNodeBuilder.withChild(Builders.mapEntryBuilder()
175                     .withNodeIdentifier(NodeIdentifierWithPredicates.of(Schema.QNAME, keyValues))
176                     .withChild(ImmutableNodes.leafNode(identifier, schema.getIdentifier()))
177                     .withChild(ImmutableNodes.leafNode(version, schema.getVersion()))
178                     .withChild(ImmutableNodes.leafNode(format, Yang.QNAME))
179                     .withChild(ImmutableNodes.leafNode(namespace, schema.getNamespace().getValue()))
180                     .withChild(locationLeafSet)
181                     .build());
182             }
183
184             return Builders.containerBuilder()
185                 .withNodeIdentifier(new NodeIdentifier(NetconfState.QNAME))
186                 .withChild(Builders.containerBuilder()
187                     .withNodeIdentifier(new NodeIdentifier(Schemas.QNAME))
188                     .withChild(schemaMapEntryNodeMapNodeCollectionNodeBuilder.build())
189                     .build())
190                 .build();
191         }
192
193         private static DOMDataBroker createDataStore(final DOMSchemaService schemaService,
194                 final SessionIdType sessionId) {
195             LOG.debug("Session {}: Creating data stores for simulated device", sessionId.getValue());
196             final DOMStore operStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", schemaService);
197             final DOMStore configStore = InMemoryDOMDataStoreFactory.create("DOM-CFG", schemaService);
198
199             ExecutorService listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(16, 16,
200                 "CommitFutures", MdsalOperationProvider.class);
201
202             final var datastores = new EnumMap<LogicalDatastoreType, DOMStore>(LogicalDatastoreType.class);
203             datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
204             datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);
205
206             return new SerializedDOMDataBroker(datastores, MoreExecutors.listeningDecorator(listenableFutureExecutor));
207         }
208
209         private DOMSchemaService createSchemaService() {
210             return new DOMSchemaService() {
211                 @Override
212                 public EffectiveModelContext getGlobalContext() {
213                     return schemaContext;
214                 }
215
216                 @Override
217                 public Registration registerSchemaContextListener(final Consumer<EffectiveModelContext> listener) {
218                     listener.accept(getGlobalContext());
219                     return () -> {
220                         // No-op
221                     };
222                 }
223             };
224         }
225     }
226 }