[DO NOT MERGE]
[controller.git] / opendaylight / ping / service / src / main / java / org / opendaylight / controller / ping / service / impl / PingServiceImpl.java
1 package org.opendaylight.controller.ping.service.impl;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.concurrent.ExecutionException;
6 import java.util.concurrent.Future;
7
8 import org.opendaylight.controller.ping.service.api.PingServiceAPI;
9 import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
10 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
11 import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911.PingService;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911.SendEchoInputBuilder;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.ping.rev130911.SendEchoOutput;
16 import org.opendaylight.yangtools.yang.common.RpcResult;
17 import org.osgi.framework.BundleActivator;
18 import org.osgi.framework.BundleContext;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 public class PingServiceImpl extends AbstractBindingAwareConsumer implements
23         BundleActivator, BindingAwareConsumer, PingServiceAPI {
24     private static Logger log = LoggerFactory.getLogger(PingServiceImpl.class);
25
26     private PingService pingService;
27     private ConsumerContext session;
28     private Map<Ipv4Address, Future<RpcResult<SendEchoOutput>>> asyncPingEntryMap;
29
30     @Override
31     public void onSessionInitialized(ConsumerContext session) {
32         this.session = session;
33         this.pingService = this.session.getRpcService(PingService.class);
34     }
35
36     @Override
37     protected void startImpl(BundleContext context) {
38         asyncPingEntryMap = new HashMap<>();
39         context.registerService(PingServiceAPI.class, this, null);
40     }
41
42     @Override
43     protected void stopImpl(BundleContext context) {
44         asyncPingEntryMap.clear();
45     }
46
47     @Override
48     public PingResult pingDestinationSync(String address) {
49         return _pingDestinationSync(address);
50     }
51
52     @Override
53     public PingResult pingDestinationAsync(String address) {
54         return _pingDestinationAsync(address);
55     }
56
57     @Override
58     public void pingAsyncClear(String address) {
59         _pingAsyncClear(address);
60     }
61
62     private PingResult _pingDestinationSync(String address) {
63         if (pingService == null) { return PingResult.Error; } // No pingService service found.
64
65         try {
66             Ipv4Address destination = new Ipv4Address(address);
67             SendEchoInputBuilder ib = new SendEchoInputBuilder();
68             ib.setDestination(destination);
69             return mapResult(pingService.sendEcho(ib.build()).get().getResult().getEchoResult());
70         } catch (InterruptedException ie) {
71             log.warn("InterruptedException received by pingDestinationSync: {} from: {}",
72                     address, ie.getMessage());
73         } catch (ExecutionException ee) {
74             log.warn("ExecutionException received by pingDestinationSync: {} from: {}",
75                     address, ee.getMessage());
76         }
77         return PingResult.Error;
78     }
79
80     private synchronized PingResult _pingDestinationAsync(String address) {
81         if (pingService == null) { return PingResult.Error; } // No pingService service found.
82
83         /** Look for destination in asyncPingEntryMap. If none is found, create a new entry
84          * and return "in progress". This will happen on the very first time async is requested.
85          *
86          * NOTE: In a real scenario, you would want to consider a cache which automatically drops
87          * entries, so implementation does not need to rely on users calling async clear to remove
88          * the entries from the map. An example for doing such would be Google's caches or a
89          * weakhash map; which we deliberately chose not to use here for sake of simplicity.
90          */
91         final Ipv4Address destination = new Ipv4Address(address);
92         final Future<RpcResult<SendEchoOutput>> rpcResultFuture = asyncPingEntryMap.get(destination);
93         if (rpcResultFuture == null) {
94             SendEchoInputBuilder ib = new SendEchoInputBuilder();
95             ib.setDestination(destination);
96             asyncPingEntryMap.put(destination, pingService.sendEcho(ib.build()));
97             log.info("Starting pingDestinationAsync: {}", address);
98             return PingResult.InProgress;
99         }
100
101         /** Pending result may not be ready to be consumed. In such case, use "in progress".
102          */
103         if (!rpcResultFuture.isDone()) {
104             log.info("pingDestinationAsync: {} get result is not ready (ie. inProgress)", address);
105             return PingResult.InProgress;
106         }
107
108         /** If we made it this far, we know that rpcResultFuture is ready for consumption.
109          */
110         try {
111             PingResult pingResult = mapResult(rpcResultFuture.get().getResult().getEchoResult());
112             log.info("pingDestinationAsync: {} get result is {}", address, pingResult);
113             return pingResult;
114         } catch (InterruptedException ie) {
115             log.warn("InterruptedException received by pingDestinationAsync: {} from: {}",
116                     address, ie.getMessage());
117         } catch (ExecutionException ee) {
118             log.warn("ExecutionException received by pingDestinationAsync: {} from: {}",
119                     address, ee.getMessage());
120         }
121         return PingResult.Error;
122     }
123
124     private synchronized void _pingAsyncClear(String address) {
125         asyncPingEntryMap.remove(new Ipv4Address(address));
126         log.info("Removing pingDestinationAsync: {}", address);
127     }
128
129     private static PingResult mapResult(SendEchoOutput.EchoResult echoResult) {
130         // Translate echoResult to pingResult
131         switch (echoResult) {
132             case Reachable:
133                 return PingResult.GotResponse;
134             case Unreachable:
135                 return PingResult.NoResponse;
136             case Error:
137             default:
138                 break;
139         }
140         return PingResult.Error;
141     }
142 }