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.spi.NotificationRouter;
65 import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
66 import org.opendaylight.yangtools.concepts.ListenerRegistration;
67 import org.opendaylight.yangtools.concepts.Registration;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.common.RpcResult;
70 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
73 import org.opendaylight.yangtools.yang.model.api.Module;
74 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
79 public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
81 private final DataProviderService dataReader;
82 private final DataReader<YangInstanceIdentifier,CompositeNode> readWrapper;
84 private final YangInstanceIdentifier mountPath;
85 private final NotificationPublishService notificationPublishService;
86 private final RpcProvisionRegistry rpcs;
88 private final ListenerRegistry<SchemaContextListener> schemaListenerRegistry = new ListenerRegistry<>();
90 private SchemaContext schemaContext;
92 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
93 this.mountPath = Preconditions.checkNotNull(path);
94 Preconditions.checkNotNull(mountPointBuilder);
96 dataReader = new DataBrokerImpl();
97 readWrapper = new ReadWrapper();
98 notificationPublishService = new DelgatingNotificationPublishService();
99 rpcs = new SchemaAwareRpcBroker(path.toString(), this);
101 mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
102 mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
103 mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
105 mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
107 mountPointBuilder.register();
110 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPoint mount) {
111 this.mountPath = Preconditions.checkNotNull(path);
112 Preconditions.checkNotNull(mount);
114 final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
116 this.schemaContext = mount.getSchemaContext();
118 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
120 // Set schema context to provide it for BackwardsCompatibleDataBroker
121 if(schemaContext != null) {
122 setSchemaContext(schemaContext);
125 readWrapper = new ReadWrapper();
127 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
128 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
131 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
132 final Optional<T> serviceOptional = mount.getService(type);
133 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
134 "Cannot construct backwards compatible mount wrapper without it", type, mount);
135 return serviceOptional.get();
139 public void addModule(final Module module) {
140 throw new UnsupportedOperationException();
144 public void removeModule(final Module module) {
145 throw new UnsupportedOperationException();
149 public SchemaContext getSessionContext() {
150 return getSchemaContext();
154 public SchemaContext getGlobalContext() {
155 return getSchemaContext();
159 public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
160 return schemaListenerRegistry.register(listener);
164 public void publish(final CompositeNode notification) {
165 notificationPublishService.publish(notification);
169 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
170 return notificationPublishService.addNotificationListener(notification, listener);
173 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
174 public DataReader<YangInstanceIdentifier, CompositeNode> getReadWrapper() {
179 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
180 return dataReader.readConfigurationData(path);
184 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
185 return dataReader.readOperationalData(path);
189 public Registration registerOperationalReader(
190 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
191 return dataReader.registerOperationalReader(path, reader);
195 public Registration registerConfigurationReader(
196 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
197 return dataReader.registerConfigurationReader(path, reader);
201 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
202 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
206 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
207 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
211 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
212 throws IllegalArgumentException {
213 return rpcs.addRpcImplementation(rpcType, implementation);
217 public Set<QName> getSupportedRpcs() {
218 return rpcs.getSupportedRpcs();
222 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
223 return rpcs.invokeRpc(rpc, input);
227 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
228 return rpcs.addRpcRegistrationListener(listener);
232 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
233 return rpcs.invokeRpc(type, input);
237 public DataModificationTransaction beginTransaction() {
238 return dataReader.beginTransaction();
242 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final YangInstanceIdentifier path,
243 final DataChangeListener listener) {
244 return dataReader.registerDataChangeListener(path, listener);
248 public Registration registerCommitHandler(
249 final YangInstanceIdentifier path, final DataCommitHandler<YangInstanceIdentifier, CompositeNode> commitHandler) {
250 return dataReader.registerCommitHandler(path, commitHandler);
254 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
259 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
264 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
268 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
273 public SchemaContext getSchemaContext() {
274 return schemaContext;
278 public void setSchemaContext(final SchemaContext schemaContext) {
279 this.schemaContext = schemaContext;
280 for (ListenerRegistration<SchemaContextListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
281 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
285 class ReadWrapper implements DataReader<YangInstanceIdentifier, CompositeNode> {
286 private YangInstanceIdentifier shortenPath(final YangInstanceIdentifier path) {
287 if (!mountPath.contains(path)) {
290 return YangInstanceIdentifier.create(Iterables.skip(path.getPathArguments(), Iterables.size(mountPath.getPathArguments())));
294 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
295 final YangInstanceIdentifier newPath = shortenPath(path);
296 if(newPath == null) {
299 return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
303 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
304 final YangInstanceIdentifier newPath = shortenPath(path);
305 if(newPath == null) {
308 return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
313 public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
314 final RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>> commitHandlerListener) {
315 return dataReader.registerCommitHandlerListener(commitHandlerListener);
319 public <L extends RouteChangeListener<RpcRoutingContext, YangInstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
321 return rpcs.registerRouteChangeListener(listener);
325 static final class BackwardsCompatibleDomStore implements DOMDataBroker {
326 private final DataProviderService dataReader;
327 private final SchemaContextProvider schemaContextProvider;
329 public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
330 this.dataReader = dataReader;
331 this.schemaContextProvider = schemaContextProvider;
335 public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
336 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
337 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
341 public DOMDataWriteTransaction newWriteOnlyTransaction() {
342 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
343 return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
347 public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final YangInstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
348 throw new UnsupportedOperationException("Register data listener not supported for mount point");
352 public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
353 throw new UnsupportedOperationException("Transaction chain not supported for mount point");
357 public DOMDataReadWriteTransaction newReadWriteTransaction() {
358 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
359 return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
363 static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
364 private final DataProviderService dataReader;
365 private final DataNormalizer normalizer;
367 public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
368 this.dataReader = dataReader;
369 this.normalizer = normalizer;
373 public Object getIdentifier() {
378 public void close() {
383 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
384 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
386 CompositeNode rawData = null;
389 case CONFIGURATION: {
390 rawData = dataReader.readConfigurationData(path);
394 rawData = dataReader.readOperationalData(path);
398 Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
400 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
401 final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
402 return Futures.immediateCheckedFuture(normalizedNodeOptional);
405 @Override public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
406 final YangInstanceIdentifier path) {
409 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
410 } catch (InterruptedException | ExecutionException e) {
411 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
417 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
418 private DataModificationTransaction oldTx;
419 private final DataNormalizer dataNormalizer;
421 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
422 this.oldTx = dataReader.beginTransaction();
423 this.dataNormalizer = dataNormalizer;
427 public Object getIdentifier() {
432 public boolean cancel() {
438 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
439 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
441 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
444 case CONFIGURATION: {
445 oldTx.putConfigurationData(legacyPath, legacyData);
450 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
451 } catch (final DataNormalizationException e) {
452 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
457 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
458 // TODO not supported
459 throw new UnsupportedOperationException("Merge not supported for mount point");
463 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
465 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
468 case CONFIGURATION: {
469 oldTx.removeConfigurationData(legacyPath);
473 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
474 } catch (final DataNormalizationException e) {
475 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
480 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
481 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
483 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
488 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
490 public TransactionCommitFailedException apply(@Nullable final Exception input) {
491 return new TransactionCommitFailedException("Commit failed", input);
497 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
498 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
504 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
506 private final DataProviderService dataReader;
507 private final DataNormalizer dataNormalizer;
508 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
510 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
511 this.dataReader = dataReader;
512 this.dataNormalizer = dataNormalizer;
513 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
517 public Object getIdentifier() {
522 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
523 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
524 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
527 @Override public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
528 final YangInstanceIdentifier path) {
531 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
532 } catch (InterruptedException | ExecutionException e) {
533 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
538 public boolean cancel() {
539 return delegateWriteTx.cancel();
543 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
544 delegateWriteTx.put(store, path, data);
548 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
549 delegateWriteTx.merge(store, path, data);
553 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
554 delegateWriteTx.delete(store, path);
558 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
559 return delegateWriteTx.submit();
563 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
564 return delegateWriteTx.commit();
569 private class DelgatingNotificationPublishService implements NotificationPublishService {
570 private final NotificationRouter notificationRouter;
572 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
573 this.notificationRouter = notificationRouter;
576 private DelgatingNotificationPublishService() {
577 this(new NotificationRouterImpl());
581 public void publish(final CompositeNode notification) {
582 notificationRouter.publish(notification);
586 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
587 return notificationRouter.addNotificationListener(notification, listener);