Bump odlparent to 5.0.0
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / lifecycle / GuardedContextImpl.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.openflowplugin.impl.lifecycle;
9
10 import static com.google.common.util.concurrent.Service.State.FAILED;
11 import static com.google.common.util.concurrent.Service.State.NEW;
12 import static com.google.common.util.concurrent.Service.State.RUNNING;
13 import static com.google.common.util.concurrent.Service.State.STARTING;
14 import static com.google.common.util.concurrent.Service.State.STOPPING;
15 import static com.google.common.util.concurrent.Service.State.TERMINATED;
16
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import com.google.common.util.concurrent.Monitor;
21 import com.google.common.util.concurrent.Monitor.Guard;
22 import com.google.common.util.concurrent.MoreExecutors;
23 import com.google.common.util.concurrent.Service;
24 import java.util.function.Function;
25 import javax.annotation.Nonnull;
26 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
27 import org.opendaylight.openflowplugin.api.openflow.OFPContext;
28 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
29 import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainMastershipWatcher;
30 import org.opendaylight.openflowplugin.api.openflow.lifecycle.GuardedContext;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 public class GuardedContextImpl implements GuardedContext {
35     private static final Logger LOG = LoggerFactory.getLogger(GuardedContextImpl.class);
36
37     private final Monitor monitor = new Monitor();
38     private final OFPContext delegate;
39     private Service.State state = NEW;
40
41     private final Guard isStartable = new Guard(monitor) {
42         @Override
43         public boolean isSatisfied() {
44             return state == NEW || state == TERMINATED;
45         }
46     };
47
48     private final Guard isStoppable = new Guard(monitor) {
49         @Override
50         public boolean isSatisfied() {
51             return state.compareTo(RUNNING) <= 0;
52         }
53     };
54
55     private final Guard isCloseable = new Guard(monitor) {
56         @Override
57         public boolean isSatisfied() {
58             return state != FAILED;
59         }
60     };
61
62     GuardedContextImpl(final OFPContext delegate) {
63         this.delegate = delegate;
64     }
65
66     @Override
67     public Service.State state() {
68         monitor.enter();
69         final Service.State stateSnapshot = state;
70         monitor.leave();
71         return stateSnapshot;
72     }
73
74     @Override
75     public <T> T map(final Function<OFPContext, T> transformer) {
76         return transformer.apply(delegate);
77     }
78
79     @Override
80     public void instantiateServiceInstance() {
81         if (monitor.enterIf(isStartable)) {
82             try {
83                 LOG.info("Starting {} service for node {}", this, getDeviceInfo());
84                 state = STARTING;
85                 delegate.instantiateServiceInstance();
86                 state = RUNNING;
87             } finally {
88                 monitor.leave();
89             }
90         } else {
91             throw new IllegalStateException("Service " + this + " has already been started");
92         }
93     }
94
95     @Override
96     @SuppressWarnings("checkstyle:IllegalCatch")
97     public ListenableFuture<?> closeServiceInstance() {
98         ListenableFuture<?> result = Futures.immediateFuture(null);
99
100         if (monitor.enterIf(isStoppable)) {
101             try {
102                 LOG.info("Stopping {} service for node {}", this, getDeviceInfo());
103                 state = STOPPING;
104                 final ListenableFuture<?> resultFuture = delegate.closeServiceInstance();
105
106                 Futures.addCallback(resultFuture, new FutureCallback<Object>() {
107                     @Override
108                     public void onSuccess(final Object result) {
109                         state = TERMINATED;
110                     }
111
112                     @Override
113                     public void onFailure(final Throwable throwable) {
114                         state = TERMINATED;
115                     }
116                 }, MoreExecutors.directExecutor());
117
118                 result = resultFuture;
119             } catch (final Exception e) {
120                 result = Futures.immediateFailedFuture(e);
121             } finally {
122                 monitor.leave();
123             }
124         }
125
126         state = TERMINATED;
127         return result;
128     }
129
130     @Nonnull
131     @Override
132     public ServiceGroupIdentifier getIdentifier() {
133         return delegate.getIdentifier();
134     }
135
136     @Override
137     public String toString() {
138         return delegate.getClass().getSimpleName() + "[" + state + "]";
139     }
140
141     @Override
142     public DeviceInfo getDeviceInfo() {
143         return delegate.getDeviceInfo();
144     }
145
146     @Override
147     public void registerMastershipWatcher(@Nonnull final ContextChainMastershipWatcher contextChainMastershipWatcher) {
148         delegate.registerMastershipWatcher(contextChainMastershipWatcher);
149     }
150
151     @Override
152     public void close() {
153         if (monitor.enterIf(isCloseable)) {
154             try {
155                 LOG.info("Terminating {} service for node {}", this, getDeviceInfo());
156                 state = FAILED;
157                 delegate.close();
158             } finally {
159                 monitor.leave();
160             }
161         }
162     }
163 }