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.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.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<InstanceIdentifier,CompositeNode> readWrapper;
82 private final InstanceIdentifier 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 InstanceIdentifier 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 InstanceIdentifier 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();
115 dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
116 readWrapper = new ReadWrapper();
118 notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
119 rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
122 private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
123 final Optional<T> serviceOptional = mount.getService(type);
124 Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
125 "Cannot construct backwards compatible mount wrapper without it", type, mount);
126 return serviceOptional.get();
130 public void addModule(final Module module) {
131 throw new UnsupportedOperationException();
135 public void removeModule(final Module module) {
136 throw new UnsupportedOperationException();
140 public SchemaContext getSessionContext() {
141 return getSchemaContext();
145 public SchemaContext getGlobalContext() {
146 return getSchemaContext();
150 public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
151 return schemaListenerRegistry.register(listener);
155 public void publish(final CompositeNode notification) {
156 notificationPublishService.publish(notification);
160 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
161 return notificationPublishService.addNotificationListener(notification, listener);
164 // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
165 public DataReader<InstanceIdentifier, CompositeNode> getReadWrapper() {
170 public CompositeNode readConfigurationData(final InstanceIdentifier path) {
171 return dataReader.readConfigurationData(path);
175 public CompositeNode readOperationalData(final InstanceIdentifier path) {
176 return dataReader.readOperationalData(path);
180 public Registration registerOperationalReader(
181 final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
182 return dataReader.registerOperationalReader(path, reader);
186 public Registration registerConfigurationReader(
187 final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
188 return dataReader.registerConfigurationReader(path, reader);
192 public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
193 return rpcs.addRoutedRpcImplementation(rpcType, implementation);
197 public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
198 rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
202 public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
203 throws IllegalArgumentException {
204 return rpcs.addRpcImplementation(rpcType, implementation);
208 public Set<QName> getSupportedRpcs() {
209 return rpcs.getSupportedRpcs();
213 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
214 return rpcs.invokeRpc(rpc, input);
218 public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
219 return rpcs.addRpcRegistrationListener(listener);
223 public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
224 return rpcs.invokeRpc(type, input);
228 public DataModificationTransaction beginTransaction() {
229 return dataReader.beginTransaction();
233 public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
234 final DataChangeListener listener) {
235 return dataReader.registerDataChangeListener(path, listener);
239 public Registration registerCommitHandler(
240 final InstanceIdentifier path, final DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
241 return dataReader.registerCommitHandler(path, commitHandler);
245 public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
250 public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
255 public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
259 public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
264 public SchemaContext getSchemaContext() {
265 return schemaContext;
269 public void setSchemaContext(final SchemaContext schemaContext) {
270 this.schemaContext = schemaContext;
271 for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
272 schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
276 class ReadWrapper implements DataReader<InstanceIdentifier, CompositeNode> {
277 private InstanceIdentifier shortenPath(final InstanceIdentifier path) {
278 InstanceIdentifier ret = null;
279 if(mountPath.contains(path)) {
280 final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
281 ret = InstanceIdentifier.create(newArgs);
287 public CompositeNode readConfigurationData(final InstanceIdentifier path) {
288 final InstanceIdentifier newPath = shortenPath(path);
289 if(newPath == null) {
292 return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
296 public CompositeNode readOperationalData(final InstanceIdentifier path) {
297 final InstanceIdentifier newPath = shortenPath(path);
298 if(newPath == null) {
301 return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
306 public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
307 final RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
308 return dataReader.registerCommitHandlerListener(commitHandlerListener);
312 public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
314 return rpcs.registerRouteChangeListener(listener);
318 static final class BackwardsCompatibleDomStore implements DOMDataBroker {
319 private final DataProviderService dataReader;
320 private final SchemaContextProvider schemaContextProvider;
322 public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
323 this.dataReader = dataReader;
324 this.schemaContextProvider = schemaContextProvider;
328 public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
329 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
330 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
334 public DOMDataWriteTransaction newWriteOnlyTransaction() {
335 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
336 return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
340 public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
341 throw new UnsupportedOperationException("Register data listener not supported for mount point");
345 public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
346 throw new UnsupportedOperationException("Transaction chain not supported for mount point");
350 public DOMDataReadWriteTransaction newReadWriteTransaction() {
351 final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
352 return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
356 static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
357 private final DataProviderService dataReader;
358 private final DataNormalizer normalizer;
360 public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
361 this.dataReader = dataReader;
362 this.normalizer = normalizer;
366 public Object getIdentifier() {
371 public void close() {
376 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
378 CompositeNode rawData = null;
381 case CONFIGURATION: {
382 rawData = dataReader.readConfigurationData(path);
386 rawData = dataReader.readOperationalData(path);
390 Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
392 final Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
393 final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
394 return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
399 static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
400 private DataModificationTransaction oldTx;
401 private final DataNormalizer dataNormalizer;
403 public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
404 this.oldTx = dataReader.beginTransaction();
405 this.dataNormalizer = dataNormalizer;
409 public Object getIdentifier() {
414 public boolean cancel() {
420 public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
421 final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
423 final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
426 case CONFIGURATION: {
427 oldTx.putConfigurationData(legacyPath, legacyData);
432 throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
433 } catch (final DataNormalizationException e) {
434 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
439 public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
440 // TODO not supported
441 throw new UnsupportedOperationException("Merge not supported for mount point");
445 public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
447 final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
450 case CONFIGURATION: {
451 oldTx.removeConfigurationData(legacyPath);
455 throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
456 } catch (final DataNormalizationException e) {
457 throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
462 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
463 final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
465 public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
470 return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
472 public TransactionCommitFailedException apply(@Nullable final Exception input) {
473 return new TransactionCommitFailedException("Commit failed", input);
479 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
480 return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
486 static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
488 private final DataProviderService dataReader;
489 private final DataNormalizer dataNormalizer;
490 private final BackwardsCompatibleWriteTransaction delegateWriteTx;
492 public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
493 this.dataReader = dataReader;
494 this.dataNormalizer = dataNormalizer;
495 this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
499 public Object getIdentifier() {
504 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
505 return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
509 public boolean cancel() {
510 return delegateWriteTx.cancel();
514 public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
515 delegateWriteTx.put(store, path, data);
519 public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
520 delegateWriteTx.merge(store, path, data);
524 public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
525 delegateWriteTx.delete(store, path);
529 public CheckedFuture<Void, TransactionCommitFailedException> submit() {
530 return delegateWriteTx.submit();
534 public ListenableFuture<RpcResult<TransactionStatus>> commit() {
535 return delegateWriteTx.commit();
540 private class DelgatingNotificationPublishService implements NotificationPublishService {
541 private final NotificationRouter notificationRouter;
543 public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
544 this.notificationRouter = notificationRouter;
547 private DelgatingNotificationPublishService() {
548 this(new NotificationRouterImpl());
552 public void publish(final CompositeNode notification) {
553 notificationRouter.publish(notification);
557 public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
558 return notificationRouter.addNotificationListener(notification, listener);