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