Merge "BUG-692 Replace strings with ModifyAction enum"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / BrokerFacade.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.restconf.impl;
9
10 import com.google.common.util.concurrent.Futures;
11
12 import java.util.concurrent.Future;
13
14 import javax.ws.rs.core.Response.Status;
15
16 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
17 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
18 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
19 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
20 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
21 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
22 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
23 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
24 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
25 import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
26 import org.opendaylight.yangtools.concepts.ListenerRegistration;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.common.RpcResult;
29 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
30 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
36     private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
37
38     private final static BrokerFacade INSTANCE = new BrokerFacade();
39
40     private volatile DataBrokerService dataService;
41     private volatile ConsumerSession context;
42
43     private BrokerFacade() {
44     }
45
46     public void setContext(final ConsumerSession context) {
47         this.context = context;
48     }
49
50     public void setDataService(final DataBrokerService dataService) {
51         this.dataService = dataService;
52     }
53
54     public static BrokerFacade getInstance() {
55         return BrokerFacade.INSTANCE;
56     }
57
58     private void checkPreconditions() {
59         if (context == null || dataService == null) {
60             throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
61         }
62     }
63
64     @Override
65     public CompositeNode readConfigurationData(final InstanceIdentifier path) {
66         this.checkPreconditions();
67
68         LOG.trace("Read Configuration via Restconf: {}", path);
69
70         return dataService.readConfigurationData(path);
71     }
72
73     public CompositeNode readConfigurationDataBehindMountPoint(final MountInstance mountPoint,
74             final InstanceIdentifier path) {
75         this.checkPreconditions();
76
77         LOG.trace("Read Configuration via Restconf: {}", path);
78
79         return mountPoint.readConfigurationData(path);
80     }
81
82     @Override
83     public CompositeNode readOperationalData(final InstanceIdentifier path) {
84         this.checkPreconditions();
85
86         BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path);
87
88         return dataService.readOperationalData(path);
89     }
90
91     public CompositeNode readOperationalDataBehindMountPoint(final MountInstance mountPoint,
92             final InstanceIdentifier path) {
93         this.checkPreconditions();
94
95         BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path);
96
97         return mountPoint.readOperationalData(path);
98     }
99
100     public Future<RpcResult<CompositeNode>> invokeRpc(final QName type, final CompositeNode payload) {
101         this.checkPreconditions();
102
103         return context.rpc(type, payload);
104     }
105
106     public Future<RpcResult<TransactionStatus>> commitConfigurationDataPut(final InstanceIdentifier path,
107             final CompositeNode payload) {
108         this.checkPreconditions();
109
110         final DataModificationTransaction transaction = dataService.beginTransaction();
111         BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path);
112         transaction.putConfigurationData(path, payload);
113         return transaction.commit();
114     }
115
116     public Future<RpcResult<TransactionStatus>> commitConfigurationDataPutBehindMountPoint(
117             final MountInstance mountPoint, final InstanceIdentifier path, final CompositeNode payload) {
118         this.checkPreconditions();
119
120         final DataModificationTransaction transaction = mountPoint.beginTransaction();
121         BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path);
122         transaction.putConfigurationData(path, payload);
123         return transaction.commit();
124     }
125
126     public Future<RpcResult<TransactionStatus>> commitConfigurationDataPost(final InstanceIdentifier path,
127             final CompositeNode payload) {
128         this.checkPreconditions();
129
130         final DataModificationTransaction transaction = dataService.beginTransaction();
131         /* check for available Node in Configuration DataStore by path */
132         CompositeNode availableNode = transaction.readConfigurationData(path);
133         if (availableNode != null) {
134             String errMsg = "Post Configuration via Restconf was not executed because data already exists";
135             BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString());
136
137             throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
138                     ErrorTag.DATA_EXISTS);
139         }
140         BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path);
141         transaction.putConfigurationData(path, payload);
142         return transaction.commit();
143     }
144
145     public Future<RpcResult<TransactionStatus>> commitConfigurationDataPostBehindMountPoint(
146             final MountInstance mountPoint, final InstanceIdentifier path, final CompositeNode payload) {
147         this.checkPreconditions();
148
149         final DataModificationTransaction transaction = mountPoint.beginTransaction();
150         /* check for available Node in Configuration DataStore by path */
151         CompositeNode availableNode = transaction.readConfigurationData(path);
152         if (availableNode != null) {
153             String errMsg = "Post Configuration via Restconf was not executed because data already exists";
154             BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString());
155
156             throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
157                     ErrorTag.DATA_EXISTS);
158         }
159         BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path);
160         transaction.putConfigurationData(path, payload);
161         return transaction.commit();
162     }
163
164     public Future<RpcResult<TransactionStatus>> commitConfigurationDataDelete(final InstanceIdentifier path) {
165         this.checkPreconditions();
166         return deleteDataAtTarget(path, dataService.beginTransaction());
167     }
168
169     public Future<RpcResult<TransactionStatus>> commitConfigurationDataDeleteBehindMountPoint(
170             final MountInstance mountPoint, final InstanceIdentifier path) {
171         this.checkPreconditions();
172         return deleteDataAtTarget(path, mountPoint.beginTransaction());
173     }
174
175     private Future<RpcResult<TransactionStatus>> deleteDataAtTarget(final InstanceIdentifier path,
176             final DataModificationTransaction transaction) {
177         LOG.info("Delete Configuration via Restconf: {}", path);
178         CompositeNode redDataAtPath = transaction.readConfigurationData(path);
179         if (redDataAtPath == null) {
180             return Futures.immediateFuture(RpcResultBuilder.<TransactionStatus>
181                                                     success(TransactionStatus.COMMITED).build());
182         }
183         transaction.removeConfigurationData(path);
184         return transaction.commit();
185     }
186
187     public void registerToListenDataChanges(final ListenerAdapter listener) {
188         this.checkPreconditions();
189
190         if (listener.isListening()) {
191             return;
192         }
193
194         InstanceIdentifier path = listener.getPath();
195         final ListenerRegistration<DataChangeListener> registration = dataService.registerDataChangeListener(path,
196                 listener);
197
198         listener.setRegistration(registration);
199     }
200 }