1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3.concurrent;
18
19 import java.beans.PropertyChangeListener;
20 import java.beans.PropertyChangeSupport;
21 import java.util.concurrent.atomic.AtomicReference;
22
23 /**
24 * Base class for circuit breakers.
25 *
26 * @param <T> the type of the value monitored by this circuit breaker
27 * @since 3.5
28 */
29 public abstract class AbstractCircuitBreaker<T> implements CircuitBreaker<T> {
30
31 /**
32 * An internal enumeration representing the different states of a circuit
33 * breaker. This class also contains some logic for performing state
34 * transitions. This is done to avoid complex if-conditions in the code of
35 * {@link CircuitBreaker}.
36 */
37 protected enum State {
38
39 /** The closed state. */
40 CLOSED {
41
42 /**
43 * {@inheritDoc}
44 */
45 @Override
46 public State oppositeState() {
47 return OPEN;
48 }
49 },
50
51 /** The open state. */
52 OPEN {
53
54 /**
55 * {@inheritDoc}
56 */
57 @Override
58 public State oppositeState() {
59 return CLOSED;
60 }
61 };
62
63 /**
64 * Returns the opposite state to the represented state. This is useful
65 * for flipping the current state.
66 *
67 * @return the opposite state
68 */
69 public abstract State oppositeState();
70 }
71
72 /**
73 * The name of the <em>open</em> property as it is passed to registered
74 * change listeners.
75 */
76 public static final String PROPERTY_NAME = "open";
77
78 /**
79 * Converts the given state value to a boolean <em>open</em> property.
80 *
81 * @param state the state to be converted
82 * @return the boolean open flag
83 */
84 protected static boolean isOpen(final State state) {
85 return state == State.OPEN;
86 }
87
88 /** The current state of this circuit breaker. */
89 protected final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
90
91 /** An object for managing change listeners registered at this instance. */
92 private final PropertyChangeSupport changeSupport;
93
94 /**
95 * Creates an {@link AbstractCircuitBreaker}. It also creates an internal {@link PropertyChangeSupport}.
96 */
97 public AbstractCircuitBreaker() {
98 changeSupport = new PropertyChangeSupport(this);
99 }
100
101 /**
102 * Adds a change listener to this circuit breaker. This listener is notified whenever
103 * the state of this circuit breaker changes. If the listener is
104 * <strong>null</strong>, it is silently ignored.
105 *
106 * @param listener the listener to be added
107 */
108 public void addChangeListener(final PropertyChangeListener listener) {
109 changeSupport.addPropertyChangeListener(listener);
110 }
111
112 /**
113 * Changes the internal state of this circuit breaker. If there is actually a change
114 * of the state value, all registered change listeners are notified.
115 *
116 * @param newState the new state to be set
117 */
118 protected void changeState(final State newState) {
119 if (state.compareAndSet(newState.oppositeState(), newState)) {
120 changeSupport.firePropertyChange(PROPERTY_NAME, !isOpen(newState), isOpen(newState));
121 }
122 }
123
124 /**
125 * {@inheritDoc}
126 */
127 @Override
128 public abstract boolean checkState();
129
130 /**
131 * {@inheritDoc}
132 */
133 @Override
134 public void close() {
135 changeState(State.CLOSED);
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override
142 public abstract boolean incrementAndCheckState(T increment);
143
144 /**
145 * {@inheritDoc}
146 */
147 @Override
148 public boolean isClosed() {
149 return !isOpen();
150 }
151
152 /**
153 * {@inheritDoc}
154 */
155 @Override
156 public boolean isOpen() {
157 return isOpen(state.get());
158 }
159
160 /**
161 * {@inheritDoc}
162 */
163 @Override
164 public void open() {
165 changeState(State.OPEN);
166 }
167
168 /**
169 * Removes the specified change listener from this circuit breaker.
170 *
171 * @param listener the listener to be removed
172 */
173 public void removeChangeListener(final PropertyChangeListener listener) {
174 changeSupport.removePropertyChangeListener(listener);
175 }
176
177 }