Feature uses features-parent as parent
[groupbasedpolicy.git] / renderers / opflex / src / main / java / org / opendaylight / groupbasedpolicy / renderer / opflex / EprContext.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
9 package org.opendaylight.groupbasedpolicy.renderer.opflex;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ScheduledExecutorService;
14 import java.util.concurrent.atomic.AtomicReference;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.groupbasedpolicy.renderer.opflex.jsonrpc.JsonRpcEndpoint;
21 import org.opendaylight.groupbasedpolicy.renderer.opflex.jsonrpc.RpcMessage;
22
23 import com.google.common.util.concurrent.CheckedFuture;
24
25 /**
26  * A context for managing a related set of operations to the Endpoint Registry's
27  * lists of Endpoints. It also keeps state from messaging that initiated the
28  * Endpoint Registry interaction, so that notifications from the registry can be
29  * used to send responses
30  *
31  * @author tbachman
32  */
33 public class EprContext implements Runnable, EprOperation.EprOpCallback {
34
35     private EprCtxCallback cb;
36     private final DataBroker dataProvider;
37     private final ScheduledExecutorService executor;
38     private final JsonRpcEndpoint peer;
39     private final RpcMessage request;
40     private final List<EprOperation> operations = new ArrayList<>();
41     private AtomicReference<Integer> completedOperations;
42     private CheckedFuture<Void, TransactionCommitFailedException> f;
43
44     public EprContext(JsonRpcEndpoint peer, RpcMessage request, DataBroker dataProvider,
45             ScheduledExecutorService executor) {
46         this.dataProvider = dataProvider;
47         this.executor = executor;
48         this.peer = peer;
49         this.request = request;
50     }
51
52     /**
53      * Add an operation to this context. This is not thread-safe.
54      *
55      * @param operation
56      */
57     public void addOperation(EprOperation operation) {
58         if (operation != null) {
59             operations.add(operation);
60         }
61     }
62
63     public List<EprOperation> getOperations() {
64         return this.operations;
65     }
66
67     public JsonRpcEndpoint getPeer() {
68         return this.peer;
69     }
70
71     /**
72      * Provides a callback that is invoked in response to a transaction with the
73      * EPR.
74      *
75      * @author tbachman
76      */
77     public static interface EprCtxCallback {
78
79         public void callback(EprContext ctx);
80     }
81
82     public void setCallback(EprCtxCallback callback) {
83         this.cb = callback;
84     }
85
86     public RpcMessage getRequest() {
87         return this.request;
88     }
89
90     /**
91      * Create an Endpoint in the Endopint Registry. This can only be called in
92      * response to an {@link org.opendaylight.groupbasedpolicy.renderer.opflex.lib.messages.EndpointDeclareRequest} message
93      */
94     public void createEp() {
95
96         WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
97
98         /*
99          * Add each of the create/update operations to a single transaction
100          */
101         for (EprOperation eo : operations) {
102             eo.put(wt);
103         }
104         f = wt.submit();
105         f.addListener(this, executor);
106
107     }
108
109     /**
110      * Delete an Endpoint in the Endpoint Registry. This can only be called in
111      * response to an {@link org.opendaylight.groupbasedpolicy.renderer.opflex.lib.messages.EndpointUndeclareRequest} message
112      */
113     public void deleteEp() {
114
115         WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
116
117         /*
118          * Add each of the delete operations to a single transaction
119          */
120         for (EprOperation eo : operations) {
121             eo.delete(wt);
122         }
123         f = wt.submit();
124         f.addListener(this, executor);
125     }
126
127     /**
128      * Look up an endpoint in the Endpoint Registry. This can only be called in
129      * response to an {@link org.opendaylight.groupbasedpolicy.renderer.opflex.lib.messages.EndpointResolveRequest} message. It initiates all
130      * of the reads, one by one, and invokes the callback when all of them have
131      * completed.
132      */
133     public void lookupEndpoint() {
134
135         /*
136          * Each read operation requires it's own transaction. We add a callback
137          * for each operation, so we can determine when all of the read
138          * operations have completed.
139          */
140         this.completedOperations = new AtomicReference<Integer>(Integer.valueOf(0));
141         for (EprOperation eo : operations) {
142             ReadOnlyTransaction rot = dataProvider.newReadOnlyTransaction();
143
144             eo.setCallback(this);
145             eo.read(rot, executor);
146         }
147     }
148
149     /**
150      * This implements the callback for the create and delete operations, from
151      * the CheckedFuture.
152      */
153     @Override
154     public void run() {
155         try {
156             f.get();
157         } catch (Exception e) {
158             // TODO: Don't use Exception
159         }
160         cb.callback(this);
161     }
162
163     /**
164      * This implements the callback for the lookup operation.
165      */
166     @Override
167     public void callback(EprOperation op) {
168         /*
169          * Add this to the list of operations that have completed, and if
170          * finished, invoke our callback
171          */
172         completedOperations.set(completedOperations.get().intValue() + 1);
173         if (completedOperations.get() >= operations.size()) {
174             cb.callback(this);
175             // TODO: way to ensure it doesn't get invoked multiple times
176         }
177     }
178 }