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.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.JdkFutureAdapters;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
19 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
20 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
21 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
22 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
27 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
28 import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
29 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
30 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
37 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
38 import org.opendaylight.controller.md.sal.dom.api.DOMService;
39 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
40 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
41 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
42 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
43 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
44 import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
45 import org.opendaylight.controller.sal.core.api.RpcImplementation;
46 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
47 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
48 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
49 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
50 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
51 import org.opendaylight.controller.sal.core.api.data.DataProviderService;
52 import org.opendaylight.controller.sal.core.api.data.DataValidator;
53 import org.opendaylight.controller.sal.core.api.model.SchemaService;
54 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
55 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
56 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
57 import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
58 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
59 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
60 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
61 import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
62 import org.opendaylight.yangtools.concepts.ListenerRegistration;
63 import org.opendaylight.yangtools.concepts.Registration;
64 import org.opendaylight.yangtools.yang.common.QName;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
69 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
70 import org.opendaylight.yangtools.yang.model.api.Module;
71 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
74 import javax.annotation.Nullable;
75 import java.util.List;
78 import java.util.concurrent.ExecutionException;
80 public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
82 private final DataProviderService dataReader;
83 private final DataReader<YangInstanceIdentifier,CompositeNode> readWrapper;
85 private final YangInstanceIdentifier mountPath;
86 private final NotificationPublishService notificationPublishService;
87 private final RpcProvisionRegistry rpcs;
89 private final ListenerRegistry<SchemaContextListener> schemaListenerRegistry = new ListenerRegistry<>();
91 private SchemaContext schemaContext;
93 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
94 this.mountPath = Preconditions.checkNotNull(path);
95 Preconditions.checkNotNull(mountPointBuilder);
97 dataReader = new DataBrokerImpl();
98 readWrapper = new ReadWrapper();
99 notificationPublishService = new DelgatingNotificationPublishService();
100 rpcs = new SchemaAwareRpcBroker(path.toString(), this);
102 mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
103 mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
104 mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
106 mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
108 mountPointBuilder.register();
111 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPoint mount) {
112 this.mountPath = Preconditions.checkNotNull(path);
113 Preconditions.checkNotNull(mount);
115 final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
117 this.schemaContext = mount.getSchemaContext();
119 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
121 // Set schema context to provide it for BackwardsCompatibleDataBroker
122 if(schemaContext != null) {
123 setSchemaContext(schemaContext);
126 readWrapper = new ReadWrapper();
128 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
129 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
132 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
133 final Optional<T> serviceOptional = mount.getService(type);
134 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
135 "Cannot construct backwards compatible mount wrapper without it", type, mount);
136 return serviceOptional.get();
140 public void addModule(final Module module) {
141 throw new UnsupportedOperationException();
145 public void removeModule(final Module module) {
146 throw new UnsupportedOperationException();
150 public SchemaContext getSessionContext() {
151 return getSchemaContext();
155 public SchemaContext getGlobalContext() {
156 return getSchemaContext();
160 public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
161 return schemaListenerRegistry.register(listener);
165 public void publish(final CompositeNode notification) {
166 notificationPublishService.publish(notification);
170 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
171 return notificationPublishService.addNotificationListener(notification, listener);
174 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
175 public DataReader<YangInstanceIdentifier, CompositeNode> getReadWrapper() {
180 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
181 return dataReader.readConfigurationData(path);
185 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
186 return dataReader.readOperationalData(path);
190 public Registration registerOperationalReader(
191 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
192 return dataReader.registerOperationalReader(path, reader);
196 public Registration registerConfigurationReader(
197 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
198 return dataReader.registerConfigurationReader(path, reader);
202 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
203 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
207 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
208 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
212 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
213 throws IllegalArgumentException {
214 return rpcs.addRpcImplementation(rpcType, implementation);
218 public Set<QName> getSupportedRpcs() {
219 return rpcs.getSupportedRpcs();
223 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
224 return rpcs.invokeRpc(rpc, input);
228 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
229 return rpcs.addRpcRegistrationListener(listener);
233 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
234 return rpcs.invokeRpc(type, input);
238 public DataModificationTransaction beginTransaction() {
239 return dataReader.beginTransaction();
243 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final YangInstanceIdentifier path,
244 final DataChangeListener listener) {
245 return dataReader.registerDataChangeListener(path, listener);
249 public Registration registerCommitHandler(
250 final YangInstanceIdentifier path, final DataCommitHandler<YangInstanceIdentifier, CompositeNode> commitHandler) {
251 return dataReader.registerCommitHandler(path, commitHandler);
255 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
260 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
265 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
269 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
274 public SchemaContext getSchemaContext() {
275 return schemaContext;
279 public void setSchemaContext(final SchemaContext schemaContext) {
280 this.schemaContext = schemaContext;
281 for (ListenerRegistration<SchemaContextListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
282 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
286 class ReadWrapper implements DataReader<YangInstanceIdentifier, CompositeNode> {
287 private YangInstanceIdentifier shortenPath(final YangInstanceIdentifier path) {
288 YangInstanceIdentifier ret = null;
289 if(mountPath.contains(path)) {
290 final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
291 ret = YangInstanceIdentifier.create(newArgs);
297 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
298 final YangInstanceIdentifier newPath = shortenPath(path);
299 if(newPath == null) {
302 return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
306 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
307 final YangInstanceIdentifier newPath = shortenPath(path);
308 if(newPath == null) {
311 return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
316 public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
317 final RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>> commitHandlerListener) {
318 return dataReader.registerCommitHandlerListener(commitHandlerListener);
322 public <L extends RouteChangeListener<RpcRoutingContext, YangInstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
324 return rpcs.registerRouteChangeListener(listener);
328 static final class BackwardsCompatibleDomStore implements DOMDataBroker {
329 private final DataProviderService dataReader;
330 private final SchemaContextProvider schemaContextProvider;
332 public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
333 this.dataReader = dataReader;
334 this.schemaContextProvider = schemaContextProvider;
338 public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
339 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
340 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
344 public DOMDataWriteTransaction newWriteOnlyTransaction() {
345 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
346 return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
350 public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final YangInstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
351 throw new UnsupportedOperationException("Register data listener not supported for mount point");
355 public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
356 throw new UnsupportedOperationException("Transaction chain not supported for mount point");
360 public DOMDataReadWriteTransaction newReadWriteTransaction() {
361 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
362 return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
366 static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
367 private final DataProviderService dataReader;
368 private final DataNormalizer normalizer;
370 public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
371 this.dataReader = dataReader;
372 this.normalizer = normalizer;
376 public Object getIdentifier() {
381 public void close() {
386 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
387 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
389 CompositeNode rawData = null;
392 case CONFIGURATION: {
393 rawData = dataReader.readConfigurationData(path);
397 rawData = dataReader.readOperationalData(path);
401 Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
403 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
404 final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
405 return Futures.immediateCheckedFuture(normalizedNodeOptional);
408 @Override public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
409 YangInstanceIdentifier path) {
412 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
413 } catch (InterruptedException | ExecutionException e) {
414 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
420 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
421 private DataModificationTransaction oldTx;
422 private final DataNormalizer dataNormalizer;
424 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
425 this.oldTx = dataReader.beginTransaction();
426 this.dataNormalizer = dataNormalizer;
430 public Object getIdentifier() {
435 public boolean cancel() {
441 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
442 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
444 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
447 case CONFIGURATION: {
448 oldTx.putConfigurationData(legacyPath, legacyData);
453 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
454 } catch (final DataNormalizationException e) {
455 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
460 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
461 // TODO not supported
462 throw new UnsupportedOperationException("Merge not supported for mount point");
466 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
468 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
471 case CONFIGURATION: {
472 oldTx.removeConfigurationData(legacyPath);
476 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
477 } catch (final DataNormalizationException e) {
478 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
483 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
484 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
486 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
491 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
493 public TransactionCommitFailedException apply(@Nullable final Exception input) {
494 return new TransactionCommitFailedException("Commit failed", input);
500 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
501 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
507 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
509 private final DataProviderService dataReader;
510 private final DataNormalizer dataNormalizer;
511 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
513 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
514 this.dataReader = dataReader;
515 this.dataNormalizer = dataNormalizer;
516 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
520 public Object getIdentifier() {
525 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
526 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
527 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
530 @Override public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
531 YangInstanceIdentifier path) {
534 return Futures.immediateCheckedFuture(read(store, path).get().isPresent());
535 } catch (InterruptedException | ExecutionException e) {
536 return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
541 public boolean cancel() {
542 return delegateWriteTx.cancel();
546 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
547 delegateWriteTx.put(store, path, data);
551 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
552 delegateWriteTx.merge(store, path, data);
556 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
557 delegateWriteTx.delete(store, path);
561 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
562 return delegateWriteTx.submit();
566 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
567 return delegateWriteTx.commit();
572 private class DelgatingNotificationPublishService implements NotificationPublishService {
573 private final NotificationRouter notificationRouter;
575 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
576 this.notificationRouter = notificationRouter;
579 private DelgatingNotificationPublishService() {
580 this(new NotificationRouterImpl());
584 public void publish(final CompositeNode notification) {
585 notificationRouter.publish(notification);
589 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
590 return notificationRouter.addNotificationListener(notification, listener);