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;
19 import java.util.List;
23 import javax.annotation.Nullable;
25 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
26 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
27 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
28 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
29 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
34 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
35 import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
36 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
37 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
40 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
41 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
42 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
43 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
44 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
45 import org.opendaylight.controller.md.sal.dom.api.DOMService;
46 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
47 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
48 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
49 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
50 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
51 import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
52 import org.opendaylight.controller.sal.core.api.RpcImplementation;
53 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
54 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
55 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
56 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
57 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
58 import org.opendaylight.controller.sal.core.api.data.DataProviderService;
59 import org.opendaylight.controller.sal.core.api.data.DataValidator;
60 import org.opendaylight.controller.sal.core.api.model.SchemaService;
61 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
62 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
63 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
64 import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
65 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
66 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
67 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
68 import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
69 import org.opendaylight.yangtools.concepts.ListenerRegistration;
70 import org.opendaylight.yangtools.concepts.Registration;
71 import org.opendaylight.yangtools.yang.common.QName;
72 import org.opendaylight.yangtools.yang.common.RpcResult;
73 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
76 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
77 import org.opendaylight.yangtools.yang.model.api.Module;
78 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
79 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
81 public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
83 private final DataProviderService dataReader;
84 private final DataReader<YangInstanceIdentifier,CompositeNode> readWrapper;
86 private final YangInstanceIdentifier mountPath;
87 private final NotificationPublishService notificationPublishService;
88 private final RpcProvisionRegistry rpcs;
90 private final ListenerRegistry<SchemaContextListener> schemaListenerRegistry = new ListenerRegistry<>();
92 private SchemaContext schemaContext;
94 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
95 this.mountPath = Preconditions.checkNotNull(path);
96 Preconditions.checkNotNull(mountPointBuilder);
98 dataReader = new DataBrokerImpl();
99 readWrapper = new ReadWrapper();
100 notificationPublishService = new DelgatingNotificationPublishService();
101 rpcs = new SchemaAwareRpcBroker(path.toString(), this);
103 mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
104 mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
105 mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
107 mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
109 mountPointBuilder.register();
112 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPoint mount) {
113 this.mountPath = Preconditions.checkNotNull(path);
114 Preconditions.checkNotNull(mount);
116 final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
118 this.schemaContext = mount.getSchemaContext();
120 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
122 // Set schema context to provide it for BackwardsCompatibleDataBroker
123 if(schemaContext != null) {
124 setSchemaContext(schemaContext);
127 readWrapper = new ReadWrapper();
129 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
130 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
133 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
134 final Optional<T> serviceOptional = mount.getService(type);
135 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
136 "Cannot construct backwards compatible mount wrapper without it", type, mount);
137 return serviceOptional.get();
141 public void addModule(final Module module) {
142 throw new UnsupportedOperationException();
146 public void removeModule(final Module module) {
147 throw new UnsupportedOperationException();
151 public SchemaContext getSessionContext() {
152 return getSchemaContext();
156 public SchemaContext getGlobalContext() {
157 return getSchemaContext();
161 public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
162 return schemaListenerRegistry.register(listener);
166 public void publish(final CompositeNode notification) {
167 notificationPublishService.publish(notification);
171 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
172 return notificationPublishService.addNotificationListener(notification, listener);
175 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
176 public DataReader<YangInstanceIdentifier, CompositeNode> getReadWrapper() {
181 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
182 return dataReader.readConfigurationData(path);
186 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
187 return dataReader.readOperationalData(path);
191 public Registration registerOperationalReader(
192 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
193 return dataReader.registerOperationalReader(path, reader);
197 public Registration registerConfigurationReader(
198 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
199 return dataReader.registerConfigurationReader(path, reader);
203 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
204 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
208 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
209 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
213 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
214 throws IllegalArgumentException {
215 return rpcs.addRpcImplementation(rpcType, implementation);
219 public Set<QName> getSupportedRpcs() {
220 return rpcs.getSupportedRpcs();
224 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
225 return rpcs.invokeRpc(rpc, input);
229 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
230 return rpcs.addRpcRegistrationListener(listener);
234 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
235 return rpcs.invokeRpc(type, input);
239 public DataModificationTransaction beginTransaction() {
240 return dataReader.beginTransaction();
244 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final YangInstanceIdentifier path,
245 final DataChangeListener listener) {
246 return dataReader.registerDataChangeListener(path, listener);
250 public Registration registerCommitHandler(
251 final YangInstanceIdentifier path, final DataCommitHandler<YangInstanceIdentifier, CompositeNode> commitHandler) {
252 return dataReader.registerCommitHandler(path, commitHandler);
256 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
261 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
266 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
270 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
275 public SchemaContext getSchemaContext() {
276 return schemaContext;
280 public void setSchemaContext(final SchemaContext schemaContext) {
281 this.schemaContext = schemaContext;
282 for (ListenerRegistration<SchemaContextListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
283 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
287 class ReadWrapper implements DataReader<YangInstanceIdentifier, CompositeNode> {
288 private YangInstanceIdentifier shortenPath(final YangInstanceIdentifier path) {
289 YangInstanceIdentifier ret = null;
290 if(mountPath.contains(path)) {
291 final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
292 ret = YangInstanceIdentifier.create(newArgs);
298 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
299 final YangInstanceIdentifier newPath = shortenPath(path);
300 if(newPath == null) {
303 return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
307 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
308 final YangInstanceIdentifier newPath = shortenPath(path);
309 if(newPath == null) {
312 return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
317 public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
318 final RegistrationListener<DataCommitHandlerRegistration<YangInstanceIdentifier, CompositeNode>> commitHandlerListener) {
319 return dataReader.registerCommitHandlerListener(commitHandlerListener);
323 public <L extends RouteChangeListener<RpcRoutingContext, YangInstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
325 return rpcs.registerRouteChangeListener(listener);
329 static final class BackwardsCompatibleDomStore implements DOMDataBroker {
330 private final DataProviderService dataReader;
331 private final SchemaContextProvider schemaContextProvider;
333 public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
334 this.dataReader = dataReader;
335 this.schemaContextProvider = schemaContextProvider;
339 public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
340 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
341 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
345 public DOMDataWriteTransaction newWriteOnlyTransaction() {
346 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
347 return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
351 public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final YangInstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
352 throw new UnsupportedOperationException("Register data listener not supported for mount point");
356 public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
357 throw new UnsupportedOperationException("Transaction chain not supported for mount point");
361 public DOMDataReadWriteTransaction newReadWriteTransaction() {
362 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
363 return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
367 static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
368 private final DataProviderService dataReader;
369 private final DataNormalizer normalizer;
371 public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
372 this.dataReader = dataReader;
373 this.normalizer = normalizer;
377 public Object getIdentifier() {
382 public void close() {
387 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
388 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
390 CompositeNode rawData = null;
393 case CONFIGURATION: {
394 rawData = dataReader.readConfigurationData(path);
398 rawData = dataReader.readOperationalData(path);
402 Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
404 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
405 final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
406 return Futures.immediateCheckedFuture(normalizedNodeOptional);
411 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
412 private DataModificationTransaction oldTx;
413 private final DataNormalizer dataNormalizer;
415 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
416 this.oldTx = dataReader.beginTransaction();
417 this.dataNormalizer = dataNormalizer;
421 public Object getIdentifier() {
426 public boolean cancel() {
432 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
433 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
435 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
438 case CONFIGURATION: {
439 oldTx.putConfigurationData(legacyPath, legacyData);
444 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
445 } catch (final DataNormalizationException e) {
446 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
451 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
452 // TODO not supported
453 throw new UnsupportedOperationException("Merge not supported for mount point");
457 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
459 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
462 case CONFIGURATION: {
463 oldTx.removeConfigurationData(legacyPath);
467 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
468 } catch (final DataNormalizationException e) {
469 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
474 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
475 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
477 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
482 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
484 public TransactionCommitFailedException apply(@Nullable final Exception input) {
485 return new TransactionCommitFailedException("Commit failed", input);
491 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
492 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
498 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
500 private final DataProviderService dataReader;
501 private final DataNormalizer dataNormalizer;
502 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
504 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
505 this.dataReader = dataReader;
506 this.dataNormalizer = dataNormalizer;
507 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
511 public Object getIdentifier() {
516 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
517 final LogicalDatastoreType store, final YangInstanceIdentifier path) {
518 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
522 public boolean cancel() {
523 return delegateWriteTx.cancel();
527 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
528 delegateWriteTx.put(store, path, data);
532 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
533 delegateWriteTx.merge(store, path, data);
537 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
538 delegateWriteTx.delete(store, path);
542 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
543 return delegateWriteTx.submit();
547 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
548 return delegateWriteTx.commit();
553 private class DelgatingNotificationPublishService implements NotificationPublishService {
554 private final NotificationRouter notificationRouter;
556 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
557 this.notificationRouter = notificationRouter;
560 private DelgatingNotificationPublishService() {
561 this(new NotificationRouterImpl());
565 public void publish(final CompositeNode notification) {
566 notificationRouter.publish(notification);
570 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
571 return notificationRouter.addNotificationListener(notification, listener);