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 java.util.List;
21 import javax.annotation.Nullable;
22 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
23 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
24 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
25 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
26 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
31 import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
32 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
33 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
39 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
40 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
41 import org.opendaylight.controller.md.sal.dom.api.DOMService;
42 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
43 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
44 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
45 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
46 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
47 import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
48 import org.opendaylight.controller.sal.core.api.RpcImplementation;
49 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
50 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
51 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
52 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
53 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
54 import org.opendaylight.controller.sal.core.api.data.DataProviderService;
55 import org.opendaylight.controller.sal.core.api.data.DataValidator;
56 import org.opendaylight.controller.sal.core.api.model.SchemaService;
57 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
58 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
59 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
60 import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
61 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
62 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
63 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
64 import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
65 import org.opendaylight.yangtools.concepts.ListenerRegistration;
66 import org.opendaylight.yangtools.concepts.Registration;
67 import org.opendaylight.yangtools.yang.common.QName;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
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.SchemaServiceListener;
77 public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
79 private final DataProviderService dataReader;
80 private final DataReader<YangInstanceIdentifier,CompositeNode> readWrapper;
82 private final YangInstanceIdentifier mountPath;
83 private final NotificationPublishService notificationPublishService;
84 private final RpcProvisionRegistry rpcs;
86 private final ListenerRegistry<SchemaServiceListener> schemaListenerRegistry = new ListenerRegistry<>();
88 private SchemaContext schemaContext;
90 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
91 this.mountPath = Preconditions.checkNotNull(path);
92 Preconditions.checkNotNull(mountPointBuilder);
94 dataReader = new DataBrokerImpl();
95 readWrapper = new ReadWrapper();
96 notificationPublishService = new DelgatingNotificationPublishService();
97 rpcs = new SchemaAwareRpcBroker(path.toString(), this);
99 mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
100 mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
101 mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
103 mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
105 mountPointBuilder.register();
108 public BackwardsCompatibleMountPoint(final YangInstanceIdentifier path, final DOMMountPoint mount) {
109 this.mountPath = Preconditions.checkNotNull(path);
110 Preconditions.checkNotNull(mount);
112 final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
114 this.schemaContext = mount.getSchemaContext();
116 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
118 // Set schema context to provide it for BackwardsCompatibleDataBroker
119 if(schemaContext != null) {
120 setSchemaContext(schemaContext);
123 readWrapper = new ReadWrapper();
125 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
126 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
129 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
130 final Optional<T> serviceOptional = mount.getService(type);
131 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
132 "Cannot construct backwards compatible mount wrapper without it", type, mount);
133 return serviceOptional.get();
137 public void addModule(final Module module) {
138 throw new UnsupportedOperationException();
142 public void removeModule(final Module module) {
143 throw new UnsupportedOperationException();
147 public SchemaContext getSessionContext() {
148 return getSchemaContext();
152 public SchemaContext getGlobalContext() {
153 return getSchemaContext();
157 public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
158 return schemaListenerRegistry.register(listener);
162 public void publish(final CompositeNode notification) {
163 notificationPublishService.publish(notification);
167 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
168 return notificationPublishService.addNotificationListener(notification, listener);
171 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
172 public DataReader<YangInstanceIdentifier, CompositeNode> getReadWrapper() {
177 public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
178 return dataReader.readConfigurationData(path);
182 public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
183 return dataReader.readOperationalData(path);
187 public Registration registerOperationalReader(
188 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
189 return dataReader.registerOperationalReader(path, reader);
193 public Registration registerConfigurationReader(
194 final YangInstanceIdentifier path, final DataReader<YangInstanceIdentifier, CompositeNode> reader) {
195 return dataReader.registerConfigurationReader(path, reader);
199 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
200 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
204 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
205 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
209 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
210 throws IllegalArgumentException {
211 return rpcs.addRpcImplementation(rpcType, implementation);
215 public Set<QName> getSupportedRpcs() {
216 return rpcs.getSupportedRpcs();
220 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
221 return rpcs.invokeRpc(rpc, input);
225 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
226 return rpcs.addRpcRegistrationListener(listener);
230 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
231 return rpcs.invokeRpc(type, input);
235 public DataModificationTransaction beginTransaction() {
236 return dataReader.beginTransaction();
240 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final YangInstanceIdentifier path,
241 final DataChangeListener listener) {
242 return dataReader.registerDataChangeListener(path, listener);
246 public Registration registerCommitHandler(
247 final YangInstanceIdentifier path, final DataCommitHandler<YangInstanceIdentifier, CompositeNode> commitHandler) {
248 return dataReader.registerCommitHandler(path, commitHandler);
252 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
257 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
262 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
266 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
271 public SchemaContext getSchemaContext() {
272 return schemaContext;
276 public void setSchemaContext(final SchemaContext schemaContext) {
277 this.schemaContext = schemaContext;
278 for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
279 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
283 class ReadWrapper implements DataReader<YangInstanceIdentifier, CompositeNode> {
284 private YangInstanceIdentifier shortenPath(final YangInstanceIdentifier path) {
285 YangInstanceIdentifier ret = null;
286 if(mountPath.contains(path)) {
287 final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
288 ret = YangInstanceIdentifier.create(newArgs);
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 ListenableFuture<Optional<NormalizedNode<?, ?>>> read(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 com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
406 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
407 private DataModificationTransaction oldTx;
408 private final DataNormalizer dataNormalizer;
410 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
411 this.oldTx = dataReader.beginTransaction();
412 this.dataNormalizer = dataNormalizer;
416 public Object getIdentifier() {
421 public boolean cancel() {
427 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
428 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
430 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
433 case CONFIGURATION: {
434 oldTx.putConfigurationData(legacyPath, legacyData);
439 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
440 } catch (final DataNormalizationException e) {
441 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
446 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
447 // TODO not supported
448 throw new UnsupportedOperationException("Merge not supported for mount point");
452 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
454 final YangInstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
457 case CONFIGURATION: {
458 oldTx.removeConfigurationData(legacyPath);
462 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
463 } catch (final DataNormalizationException e) {
464 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
469 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
470 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
472 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
477 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
479 public TransactionCommitFailedException apply(@Nullable final Exception input) {
480 return new TransactionCommitFailedException("Commit failed", input);
486 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
487 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
493 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
495 private final DataProviderService dataReader;
496 private final DataNormalizer dataNormalizer;
497 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
499 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
500 this.dataReader = dataReader;
501 this.dataNormalizer = dataNormalizer;
502 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
506 public Object getIdentifier() {
511 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
512 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
516 public boolean cancel() {
517 return delegateWriteTx.cancel();
521 public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
522 delegateWriteTx.put(store, path, data);
526 public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
527 delegateWriteTx.merge(store, path, data);
531 public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
532 delegateWriteTx.delete(store, path);
536 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
537 return delegateWriteTx.submit();
541 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
542 return delegateWriteTx.commit();
547 private class DelgatingNotificationPublishService implements NotificationPublishService {
548 private final NotificationRouter notificationRouter;
550 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
551 this.notificationRouter = notificationRouter;
554 private DelgatingNotificationPublishService() {
555 this(new NotificationRouterImpl());
559 public void publish(final CompositeNode notification) {
560 notificationRouter.publish(notification);
564 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
565 return notificationRouter.addNotificationListener(notification, listener);