Activation status handling mechanism for ForwardingConstruct provisioning
[unimgr.git] / impl / src / main / java / org / opendaylight / unimgr / impl / ForwardingConstructActivatorService.java
1 /*
2  * Copyright (c) 2016 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.unimgr.impl;
10
11 import java.util.List;
12 import java.util.Optional;
13 import java.util.concurrent.locks.ReentrantReadWriteLock;
14
15 import javax.annotation.Nonnull;
16
17 import org.opendaylight.unimgr.mef.nrp.api.ActivationDriver;
18 import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverAmbiguousException;
19 import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverBuilder;
20 import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverNotFoundException;
21 import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverRepoService;
22 import org.opendaylight.unimgr.mef.nrp.impl.ActivationTransaction;
23 import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstruct;
24 import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import static org.opendaylight.unimgr.mef.nrp.impl.ActivationTransaction.Result;
29
30 /**
31  * @author bartosz.michalik@amartus.com
32  * @author krzysztof.bijakowski@amartus.com [modifications]
33  */
34 public class ForwardingConstructActivatorService {
35     private static final Logger LOG = LoggerFactory.getLogger(ForwardingConstructActivatorService.class);
36     private ActivationDriverRepoService activationRepoService;
37     private final ReentrantReadWriteLock lock;
38
39     public ForwardingConstructActivatorService(ActivationDriverRepoService activationRepoService) {
40         this.activationRepoService = activationRepoService;
41         lock = new ReentrantReadWriteLock();
42     }
43
44     /**
45      * Activate a MEF ForwardingConstruct.
46      * @param forwardingConstruct the new route to activate
47      */
48     public void activate(@Nonnull ForwardingConstruct forwardingConstruct, @Nonnull ForwardingConstructActivationStateTracker stateTracker) {
49         if(stateTracker.isActivatable()) {
50             Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
51             if (tx.isPresent()) {
52                 Result result = tx.get().activate();
53
54                 if(result.isSuccessful()) {
55                     stateTracker.activated(forwardingConstruct);
56                     LOG.info("Forwarding construct activated successfully, request = {} ", forwardingConstruct);
57                 } else {
58                     stateTracker.activationFailed(forwardingConstruct);
59                     LOG.warn("Forwarding construct activation failed, reason = {}, request = {}", result.getMessage(), forwardingConstruct);
60                 }
61             } else {
62                 LOG.warn("No transaction for this activation request {}", forwardingConstruct);
63             }
64         }
65     }
66
67     /**
68      * Deactivate a MEF ForwardingConstruct.
69      * @param forwardingConstruct the existing route to deactivate
70      */
71     public void deactivate(@Nonnull ForwardingConstruct forwardingConstruct, @Nonnull ForwardingConstructActivationStateTracker stateTracker) {
72         if(stateTracker.isDeactivatable()) {
73             Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
74             if (tx.isPresent()) {
75                 Result result = tx.get().deactivate();
76
77                 if(result.isSuccessful()) {
78                     stateTracker.deactivated();
79                     LOG.info("Forwarding construct deactivated successfully, request = {}", forwardingConstruct);
80                 } else {
81                     stateTracker.deactivationFailed();
82                     LOG.warn("Forwarding construct deactivation failed, reason = {}, request = {}", result.getMessage(), forwardingConstruct);
83                 }
84             } else {
85                 LOG.warn("No transaction for this deactivation request {}", forwardingConstruct);
86             }
87         }
88     }
89
90     private Optional<ActivationTransaction> prepareTransaction(ForwardingConstruct fwdC) {
91         final List<FcPort> list = fwdC.getFcPort();
92         //TODO validate pre-condition
93         final FcPort a = list.get(0);
94         final FcPort z = list.get(1);
95
96         return isTheSameNode(fwdC)
97                 ? getTxForNode(a,z, fwdC) : getTxForMultiNode(a,z, fwdC);
98     }
99
100     private boolean isTheSameNode(ForwardingConstruct forwardingConstruct) {
101         final FcPort p1 = forwardingConstruct.getFcPort().get(0);
102         final FcPort p2 = forwardingConstruct.getFcPort().get(1);
103         return p1.getNode().equals(p2.getNode());
104     }
105
106     private Optional<ActivationTransaction> getTxForNode(FcPort portA, FcPort portZ, ForwardingConstruct fwdC) {
107         lock.readLock().lock();
108         try {
109             final ActivationDriverBuilder.BuilderContext ctx = new ActivationDriverBuilder.BuilderContext();
110             ActivationDriver activator = activationRepoService.getDriver(portA, portZ, ctx);
111
112             activator.initialize(portA, portZ, fwdC);
113             ActivationTransaction tx = new ActivationTransaction();
114             tx.addDriver(activator);
115             return Optional.of(tx);
116         } catch (ActivationDriverNotFoundException e) {
117             LOG.warn("No unique activation driver found for {} <-> {}", portA, portZ);
118             return Optional.empty();
119         } catch (ActivationDriverAmbiguousException e) {
120             LOG.warn("Multiple activation driver found for {} <-> {}", portZ, portA);
121             return Optional.empty();
122         } catch (Exception e) {
123             LOG.error("driver initialization exception", e);
124             return Optional.empty();
125         } finally {
126             lock.readLock().unlock();
127         }
128     }
129
130     private Optional<ActivationTransaction> getTxForMultiNode(FcPort portA, FcPort portZ, ForwardingConstruct fwdC) {
131         //1. find and initialize drivers
132         lock.readLock().lock();
133         try {
134
135             final ActivationDriverBuilder.BuilderContext ctx = new ActivationDriverBuilder.BuilderContext();
136             ctx.put(ForwardingConstruct.class.getName(), fwdC);
137
138             Optional<ActivationDriver> aendActivator = findDriver(portA, ctx);
139             Optional<ActivationDriver> zendActivator = findDriver(portZ, ctx);
140
141             if (aendActivator.isPresent() && zendActivator.isPresent()) {
142                 aendActivator.get().initialize(portA, portZ, fwdC);
143                 zendActivator.get().initialize(portZ, portA, fwdC);
144
145                 final ActivationTransaction tx = new ActivationTransaction();
146                 tx.addDriver(aendActivator.get());
147                 tx.addDriver(zendActivator.get());
148
149                 return Optional.of(tx);
150             } else {
151                 // ??? TODO improve comment for better traceability
152                 LOG.error("drivers for both ends needed");
153                 return Optional.empty();
154             }
155
156         } catch (Exception e) {
157             LOG.error("driver initialization exception",e);
158             return Optional.empty();
159         } finally {
160             lock.readLock().unlock();
161         }
162     }
163
164     protected Optional<ActivationDriver> findDriver(FcPort port, ActivationDriverBuilder.BuilderContext fwdC) {
165         if (activationRepoService == null)  {
166             LOG.warn("Activation Driver repo is not initialized");
167             return Optional.empty();
168         }
169         try {
170             return Optional.ofNullable(activationRepoService.getDriver(port, fwdC));
171         } catch (ActivationDriverNotFoundException e) {
172             LOG.warn("No activation driver found for {}", port);
173             return Optional.empty();
174         } catch (ActivationDriverAmbiguousException e) {
175             LOG.warn("Multiple activation driver found for {}", port);
176             return Optional.empty();
177         }
178
179
180     }
181
182     /**
183      * Set the activation driver repository service.
184      * @param activationRepoService service to use
185      */
186     public void setActivationRepoService(ActivationDriverRepoService activationRepoService) {
187         lock.writeLock().lock();
188         this.activationRepoService = activationRepoService;
189         lock.writeLock().unlock();
190     }
191
192     /**
193      * Unset the activation driver repository service.
194      */
195     public void unsetActivationRepoService() {
196         lock.writeLock().lock();
197         this.activationRepoService = null;
198         lock.writeLock().unlock();
199     }
200
201     static final class Context {
202         final FcPort portA;
203         final FcPort portZ;
204         final ForwardingConstruct fwC;
205
206         public Context(FcPort portA, FcPort portZ, ForwardingConstruct fwC) {
207             this.portA = portA;
208             this.portZ = portZ;
209             this.fwC = fwC;
210         }
211     }
212 }