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 * http://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 * {@inheritDoc}
43 */
44 @Override
45 public State oppositeState() {
46 return OPEN;
47 }
48 },
49
50 /** The open state. */
51 OPEN {
52 /**
53 * {@inheritDoc}
54 */
55 @Override
56 public State oppositeState() {
57 return CLOSED;
58 }
59 };
60
61 /**
62 * Returns the opposite state to the represented state. This is useful
63 * for flipping the current state.
64 *
65 * @return the opposite state
66 */
67 public abstract State oppositeState();
68 }
69
70 /**
71 * The name of the <em>open</em> property as it is passed to registered
72 * change listeners.
73 */
74 public static final String PROPERTY_NAME = "open";
75
76 /**
77 * Converts the given state value to a boolean <em>open</em> property.
78 *
79 * @param state the state to be converted
80 * @return the boolean open flag
81 */
82 protected static boolean isOpen(final State state) {
83 return state == State.OPEN;
84 }
85
86 /** The current state of this circuit breaker. */
87 protected final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
88
89 /** An object for managing change listeners registered at this instance. */
90 private final PropertyChangeSupport changeSupport;
91
92 /**
93 * Creates an {@link AbstractCircuitBreaker}. It also creates an internal {@link PropertyChangeSupport}.
94 */
95 public AbstractCircuitBreaker() {
96 changeSupport = new PropertyChangeSupport(this);
97 }
98
99 /**
100 * Adds a change listener to this circuit breaker. This listener is notified whenever
101 * the state of this circuit breaker changes. If the listener is
102 * <strong>null</strong>, it is silently ignored.
103 *
104 * @param listener the listener to be added
105 */
106 public void addChangeListener(final PropertyChangeListener listener) {
107 changeSupport.addPropertyChangeListener(listener);
108 }
109
110 /**
111 * Changes the internal state of this circuit breaker. If there is actually a change
112 * of the state value, all registered change listeners are notified.
113 *
114 * @param newState the new state to be set
115 */
116 protected void changeState(final State newState) {
117 if (state.compareAndSet(newState.oppositeState(), newState)) {
118 changeSupport.firePropertyChange(PROPERTY_NAME, !isOpen(newState), isOpen(newState));
119 }
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 @Override
126 public abstract boolean checkState();
127
128 /**
129 * {@inheritDoc}
130 */
131 @Override
132 public void close() {
133 changeState(State.CLOSED);
134 }
135
136 /**
137 * {@inheritDoc}
138 */
139 @Override
140 public abstract boolean incrementAndCheckState(T increment);
141
142 /**
143 * {@inheritDoc}
144 */
145 @Override
146 public boolean isClosed() {
147 return !isOpen();
148 }
149
150 /**
151 * {@inheritDoc}
152 */
153 @Override
154 public boolean isOpen() {
155 return isOpen(state.get());
156 }
157
158 /**
159 * {@inheritDoc}
160 */
161 @Override
162 public void open() {
163 changeState(State.OPEN);
164 }
165
166 /**
167 * Removes the specified change listener from this circuit breaker.
168 *
169 * @param listener the listener to be removed
170 */
171 public void removeChangeListener(final PropertyChangeListener listener) {
172 changeSupport.removePropertyChangeListener(listener);
173 }
174
175 }