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