View Javadoc
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 }