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.restconf.impl;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import javax.ws.rs.core.Response.Status;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
23 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
24 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
25 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
26 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
27 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
28 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
29 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
30 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
31 import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
32 import org.opendaylight.yangtools.concepts.ListenerRegistration;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.common.RpcResult;
35 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 public class BrokerFacade {
42 private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
44 private final static BrokerFacade INSTANCE = new BrokerFacade();
45 private volatile ConsumerSession context;
46 private DOMDataBroker domDataBroker;
48 private BrokerFacade() {
51 public void setContext(final ConsumerSession context) {
52 this.context = context;
55 public static BrokerFacade getInstance() {
56 return BrokerFacade.INSTANCE;
59 private void checkPreconditions() {
60 if (context == null || domDataBroker == null) {
61 throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
66 public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
68 return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path);
71 public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
72 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
73 if (domDataBrokerService.isPresent()) {
74 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path);
76 throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
80 public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
82 return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
85 public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
86 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
87 if (domDataBrokerService.isPresent()) {
88 return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path);
90 throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
94 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
95 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
97 return putDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path, payload);
100 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
101 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
102 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
103 if (domDataBrokerService.isPresent()) {
104 return putDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path,
107 throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
110 // POST configuration
111 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
112 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
113 checkPreconditions();
114 return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload);
117 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
118 final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
119 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
120 if (domDataBrokerService.isPresent()) {
121 return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
124 throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
127 // DELETE configuration
128 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
129 final YangInstanceIdentifier path) {
130 checkPreconditions();
131 return deleteDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path);
134 public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
135 final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
136 final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
137 if (domDataBrokerService.isPresent()) {
138 return deleteDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path);
140 throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
144 public Future<RpcResult<CompositeNode>> invokeRpc(final QName type, final CompositeNode payload) {
145 this.checkPreconditions();
147 return context.rpc(type, payload);
150 public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope,
151 final ListenerAdapter listener) {
152 this.checkPreconditions();
154 if (listener.isListening()) {
158 YangInstanceIdentifier path = listener.getPath();
159 final ListenerRegistration<DOMDataChangeListener> registration = domDataBroker.registerDataChangeListener(
160 datastore, path, listener, scope);
162 listener.setRegistration(registration);
165 private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
166 LogicalDatastoreType datastore, YangInstanceIdentifier path) {
167 LOG.trace("Read " + datastore.name() + " via Restconf: {}", path);
168 final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
169 if (listenableFuture != null) {
170 Optional<NormalizedNode<?, ?>> optional;
172 LOG.debug("Reading result data from transaction.");
173 optional = listenableFuture.get();
174 } catch (InterruptedException | ExecutionException e) {
175 throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause());
178 if (optional != null) {
179 if (optional.isPresent()) {
180 return optional.get();
187 private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
188 final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
189 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
190 ListenableFuture<Optional<NormalizedNode<?, ?>>> futureDatastoreData = rWTransaction.read(datastore, path);
192 final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.get();
193 if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) {
194 String errMsg = "Post Configuration via Restconf was not executed because data already exists";
195 LOG.trace(errMsg + ":{}", path);
196 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
197 ErrorTag.DATA_EXISTS);
199 } catch (InterruptedException | ExecutionException e) {
200 LOG.trace("It wasn't possible to get data loaded from datastore at path " + path);
202 rWTransaction.merge(datastore, path, payload);
203 LOG.trace("Post " + datastore.name() + " via Restconf: {}", path);
204 return rWTransaction.submit();
207 private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
208 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
209 final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
210 LOG.trace("Put " + datastore.name() + " via Restconf: {}", path);
211 writeTransaction.put(datastore, path, payload);
212 return writeTransaction.submit();
215 private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
216 final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
217 YangInstanceIdentifier path) {
218 LOG.info("Delete " + datastore.name() + " via Restconf: {}", path);
219 writeTransaction.delete(datastore, path);
220 return writeTransaction.submit();
223 public void setDomDataBroker(DOMDataBroker domDataBroker) {
224 this.domDataBroker = domDataBroker;