2 * Copyright (c) 2014 Cisco Systems, Inc. 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.controller.sal.dom.broker;
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Iterables;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.JdkFutureAdapters;
18 import com.google.common.util.concurrent.ListenableFuture;
21 import java.util.concurrent.ExecutionException;
22 import javax.annotation.Nullable;
23 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
24 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
25 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
26 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
27 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
33 import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
34 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
35 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
40 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
41 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
42 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
43 import org.opendaylight.controller.md.sal.dom.api.DOMService;
44 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
45 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
46 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
47 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
48 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
49 import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
50 import org.opendaylight.controller.sal.core.api.RpcImplementation;
51 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
52 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
53 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
54 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
55 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
56 import org.opendaylight.controller.sal.core.api.data.DataProviderService;
57 import org.opendaylight.controller.sal.core.api.data.DataValidator;
58 import org.opendaylight.controller.sal.core.api.model.SchemaService;
59 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
60 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
61 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
62 import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
63 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
64 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
65 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
66 import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
67 import org.opendaylight.yangtools.concepts.ListenerRegistration;
68 import org.opendaylight.yangtools.concepts.Registration;
69 import org.opendaylight.yangtools.yang.common.QName;
70 import org.opendaylight.yangtools.yang.common.RpcResult;
71 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
74 import org.opendaylight.yangtools.yang.model.api.Module;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
78 public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
80 private final DataProviderService dataReader;
81 private final DataReader<YangInstanceIdentifier,CompositeNode> readWrapper;
83 private final YangInstanceIdentifier mountPath;
84 private final NotificationPublishService notificationPublishService;
85 private final RpcProvisionRegistry rpcs;
87 private final ListenerRegistry<SchemaContextListener> schemaListenerRegistry = new ListenerRegistry<>();
89 private SchemaContext schemaContext;
91 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
92 this.mountPath = Preconditions.checkNotNull(path);
93 Preconditions.checkNotNull(mountPointBuilder);
95 dataReader = new DataBrokerImpl();
96 readWrapper = new ReadWrapper();
97 notificationPublishService = new DelgatingNotificationPublishService();
98 rpcs = new SchemaAwareRpcBroker(path.toString(), this);
100 mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
101 mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
102 mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
104 mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
106 mountPointBuilder.register();
109 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPoint mount) {
110 this.mountPath = Preconditions.checkNotNull(path);
111 Preconditions.checkNotNull(mount);
113 final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
115 this.schemaContext = mount.getSchemaContext();
117 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
119 // Set schema context to provide it for BackwardsCompatibleDataBroker
120 if(schemaContext != null) {
121 setSchemaContext(schemaContext);
124 readWrapper = new ReadWrapper();
126 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
127 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
130 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
131 final Optional<T> serviceOptional = mount.getService(type);
132 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
133 "Cannot construct backwards compatible mount wrapper without it", type, mount);
134 return serviceOptional.get();
138 public void addModule(final Module module) {
139 throw new UnsupportedOperationException();
143 public void removeModule(final Module module) {
144 throw new UnsupportedOperationException();
148 public SchemaContext getSessionContext() {
149 return getSchemaContext();
153 public SchemaContext getGlobalContext() {
154 return getSchemaContext();
158 public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
159 return schemaListenerRegistry.register(listener);
163 public void publish(final CompositeNode notification) {
164 notificationPublishService.publish(notification);
168 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
169 return notificationPublishService.addNotificationListener(notification, listener);
172 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
173 public DataReader<YangInstanceIdentifier, CompositeNode> getReadWrapper() {
178 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
179 return dataReader.readConfigurationData(path);
183 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
184 return dataReader.readOperationalData(path);
188 public Registration registerOperationalReader(
189 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
190 return dataReader.registerOperationalReader(path, reader);
194 public Registration registerConfigurationReader(
195 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
196 return dataReader.registerConfigurationReader(path, reader);
200 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
201 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
205 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
206 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
210 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
211 throws IllegalArgumentException {
212 return rpcs.addRpcImplementation(rpcType, implementation);
216 public Set<QName> getSupportedRpcs() {
217 return rpcs.getSupportedRpcs();
221 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
222 return rpcs.invokeRpc(rpc, input);
226 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
227 return rpcs.addRpcRegistrationListener(listener);
231 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
232 return rpcs.invokeRpc(type, input);
236 public DataModificationTransaction beginTransaction() {
237 return dataReader.beginTransaction();
241 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final YangInstanceIdentifier path,
242 final DataChangeListener listener) {
243 return dataReader.registerDataChangeListener(path, listener);
247 public Registration registerCommitHandler(
248 final YangInstanceIdentifier path, final DataCommitHandler<YangInstanceIdentifier, CompositeNode> commitHandler) {
249 return dataReader.registerCommitHandler(path, commitHandler);
253 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
258 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
263 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
267 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
272 public SchemaContext getSchemaContext() {
273 return schemaContext;
277 public void setSchemaContext(final SchemaContext schemaContext) {
278 this.schemaContext = schemaContext;
279 for (ListenerRegistration<SchemaContextListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
280 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
284 class ReadWrapper implements DataReader<YangInstanceIdentifier, CompositeNode> {
285 private YangInstanceIdentifier shortenPath(final YangInstanceIdentifier path) {
286 if (!mountPath.contains(path)) {
289 return YangInstanceIdentifier.create(Iterables.skip(path.getPathArguments(), Iterables.size(mountPath.getPathArguments())));
293 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
294 final YangInstanceIdentifier newPath = shortenPath(path);
295 if(newPath == null) {
298 return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
302 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
303 final YangInstanceIdentifier newPath = shortenPath(path);
304 if(newPath == null) {
307 return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
312 public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
313 final RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>> commitHandlerListener) {
314 return dataReader.registerCommitHandlerListener(commitHandlerListener);
318 public <L extends RouteChangeListener<RpcRoutingContext, YangInstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
320 return rpcs.registerRouteChangeListener(listener);
324 static final class BackwardsCompatibleDomStore implements DOMDataBroker {
325 private final DataProviderService dataReader;
326 private final SchemaContextProvider schemaContextProvider;
328 public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
329 this.dataReader = dataReader;
330 this.schemaContextProvider = schemaContextProvider;
334 public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
335 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
336 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
340 public DOMDataWriteTransaction newWriteOnlyTransaction() {
341 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
342 return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
346 public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final YangInstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
347 throw new UnsupportedOperationException("Register data listener not supported for mount point");
351 public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
352 throw new UnsupportedOperationException("Transaction chain not supported for mount point");
356 public DOMDataReadWriteTransaction newReadWriteTransaction() {
357 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
358 return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
362 static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
363 private final DataProviderService dataReader;
364 private final DataNormalizer normalizer;
366 public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
367 this.dataReader = dataReader;
368 this.normalizer = normalizer;
372 public Object getIdentifier() {
377 public void close() {
382 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
383 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
385 CompositeNode rawData = null;
388 case CONFIGURATION: {
389 rawData = dataReader.readConfigurationData(path);
393 rawData = dataReader.readOperationalData(path);
397 Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
399 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
400 final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
401 return Futures.immediateCheckedFuture(normalizedNodeOptional);
404 @Override public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
405 final YangInstanceIdentifier path) {
408 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
409 } catch (InterruptedException | ExecutionException e) {
410 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
416 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
417 private DataModificationTransaction oldTx;
418 private final DataNormalizer dataNormalizer;
420 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
421 this.oldTx = dataReader.beginTransaction();
422 this.dataNormalizer = dataNormalizer;
426 public Object getIdentifier() {
431 public boolean cancel() {
437 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
438 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
440 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
443 case CONFIGURATION: {
444 oldTx.putConfigurationData(legacyPath, legacyData);
449 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
450 } catch (final DataNormalizationException e) {
451 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
456 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
457 // TODO not supported
458 throw new UnsupportedOperationException("Merge not supported for mount point");
462 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
464 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
467 case CONFIGURATION: {
468 oldTx.removeConfigurationData(legacyPath);
472 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
473 } catch (final DataNormalizationException e) {
474 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
479 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
480 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
482 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
487 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
489 public TransactionCommitFailedException apply(@Nullable final Exception input) {
490 return new TransactionCommitFailedException("Commit failed", input);
496 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
497 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
503 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
505 private final DataProviderService dataReader;
506 private final DataNormalizer dataNormalizer;
507 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
509 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
510 this.dataReader = dataReader;
511 this.dataNormalizer = dataNormalizer;
512 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
516 public Object getIdentifier() {
521 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
522 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
523 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
526 @Override public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
527 final YangInstanceIdentifier path) {
530 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
531 } catch (InterruptedException | ExecutionException e) {
532 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
537 public boolean cancel() {
538 return delegateWriteTx.cancel();
542 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
543 delegateWriteTx.put(store, path, data);
547 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
548 delegateWriteTx.merge(store, path, data);
552 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
553 delegateWriteTx.delete(store, path);
557 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
558 return delegateWriteTx.submit();
562 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
563 return delegateWriteTx.commit();
568 private class DelgatingNotificationPublishService implements NotificationPublishService {
569 private final NotificationRouter notificationRouter;
571 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
572 this.notificationRouter = notificationRouter;
575 private DelgatingNotificationPublishService() {
576 this(new NotificationRouterImpl());
580 public void publish(final CompositeNode notification) {
581 notificationRouter.publish(notification);
585 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
586 return notificationRouter.addNotificationListener(notification, listener);