Refactoring of cisco-xr-driver and impl modules.
[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                 stateTracker.activationFailed(forwardingConstruct);
64             }
65         }
66     }
67
68     /**
69      * Deactivate a MEF ForwardingConstruct.
70      * @param forwardingConstruct the existing route to deactivate
71      */
72     public void deactivate(@Nonnull ForwardingConstruct forwardingConstruct, @Nonnull ForwardingConstructActivationStateTracker stateTracker) {
73         if(stateTracker.isDeactivatable()) {
74             Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
75             if (tx.isPresent()) {
76                 Result result = tx.get().deactivate();
77
78                 if(result.isSuccessful()) {
79                     stateTracker.deactivated();
80                     LOG.info("Forwarding construct deactivated successfully, request = {}", forwardingConstruct);
81                 } else {
82                     stateTracker.deactivationFailed();
83                     LOG.warn("Forwarding construct deactivation failed, reason = {}, request = {}", result.getMessage(), forwardingConstruct);
84                 }
85             } else {
86                 LOG.warn("No transaction for this deactivation request {}", forwardingConstruct);
87                 stateTracker.deactivationFailed();
88             }
89         }
90     }
91
92     private Optional<ActivationTransaction> prepareTransaction(ForwardingConstruct fwdC) {
93         final List<FcPort> list = fwdC.getFcPort();
94         //TODO validate pre-condition
95         final FcPort a = list.get(0);
96         final FcPort z = list.get(1);
97
98         return isTheSameNode(fwdC)
99                 ? getTxForNode(a,z, fwdC) : getTxForMultiNode(a,z, fwdC);
100     }
101
102     private boolean isTheSameNode(ForwardingConstruct forwardingConstruct) {
103         final FcPort p1 = forwardingConstruct.getFcPort().get(0);
104         final FcPort p2 = forwardingConstruct.getFcPort().get(1);
105         return p1.getNode().equals(p2.getNode());
106     }
107
108     private Optional<ActivationTransaction> getTxForNode(FcPort portA, FcPort portZ, ForwardingConstruct fwdC) {
109         lock.readLock().lock();
110         try {
111             final ActivationDriverBuilder.BuilderContext ctx = new ActivationDriverBuilder.BuilderContext();
112             ActivationDriver activator = activationRepoService.getDriver(portA, portZ, ctx);
113
114             activator.initialize(portA, portZ, fwdC);
115             ActivationTransaction tx = new ActivationTransaction();
116             tx.addDriver(activator);
117             return Optional.of(tx);
118         } catch (ActivationDriverNotFoundException e) {
119             LOG.warn("No unique activation driver found for {} <-> {}", portA, portZ);
120             return Optional.empty();
121         } catch (ActivationDriverAmbiguousException e) {
122             LOG.warn("Multiple activation driver found for {} <-> {}", portZ, portA);
123             return Optional.empty();
124         } catch (Exception e) {
125             LOG.error("driver initialization exception", e);
126             return Optional.empty();
127         } finally {
128             lock.readLock().unlock();
129         }
130     }
131
132     private Optional<ActivationTransaction> getTxForMultiNode(FcPort portA, FcPort portZ, ForwardingConstruct fwdC) {
133         //1. find and initialize drivers
134         lock.readLock().lock();
135         try {
136
137             final ActivationDriverBuilder.BuilderContext ctx = new ActivationDriverBuilder.BuilderContext();
138             ctx.put(ForwardingConstruct.class.getName(), fwdC);
139
140             Optional<ActivationDriver> aendActivator = findDriver(portA, ctx);
141             Optional<ActivationDriver> zendActivator = findDriver(portZ, ctx);
142
143             if (aendActivator.isPresent() && zendActivator.isPresent()) {
144                 aendActivator.get().initialize(portA, portZ, fwdC);
145                 zendActivator.get().initialize(portZ, portA, fwdC);
146
147                 final ActivationTransaction tx = new ActivationTransaction();
148                 tx.addDriver(aendActivator.get());
149                 tx.addDriver(zendActivator.get());
150
151                 return Optional.of(tx);
152             } else {
153                 // ??? TODO improve comment for better traceability
154                 LOG.error("drivers for both ends needed");
155                 return Optional.empty();
156             }
157
158         } catch (Exception e) {
159             LOG.error("driver initialization exception",e);
160             return Optional.empty();
161         } finally {
162             lock.readLock().unlock();
163         }
164     }
165
166     protected Optional<ActivationDriver> findDriver(FcPort port, ActivationDriverBuilder.BuilderContext fwdC) {
167         if (activationRepoService == null)  {
168             LOG.warn("Activation Driver repo is not initialized");
169             return Optional.empty();
170         }
171         try {
172             return Optional.ofNullable(activationRepoService.getDriver(port, fwdC));
173         } catch (ActivationDriverNotFoundException e) {
174             LOG.warn("No activation driver found for {}", port);
175             return Optional.empty();
176         } catch (ActivationDriverAmbiguousException e) {
177             LOG.warn("Multiple activation driver found for {}", port);
178             return Optional.empty();
179         }
180
181
182     }
183
184     /**
185      * Set the activation driver repository service.
186      * @param activationRepoService service to use
187      */
188     public void setActivationRepoService(ActivationDriverRepoService activationRepoService) {
189         lock.writeLock().lock();
190         this.activationRepoService = activationRepoService;
191         lock.writeLock().unlock();
192     }
193
194     /**
195      * Unset the activation driver repository service.
196      */
197     public void unsetActivationRepoService() {
198         lock.writeLock().lock();
199         this.activationRepoService = null;
200         lock.writeLock().unlock();
201     }
202
203     static final class Context {
204         final FcPort portA;
205         final FcPort portZ;
206         final ForwardingConstruct fwC;
207
208         public Context(FcPort portA, FcPort portZ, ForwardingConstruct fwC) {
209             this.portA = portA;
210             this.portZ = portZ;
211             this.fwC = fwC;
212         }
213     }
214 }