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    *      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 }