/*
* Strongback
* Copyright 2015, Strongback and individual contributors by the @authors tag.
* See the COPYRIGHT.txt in the distribution for a full listing of individual
* contributors.
*
* Licensed under the MIT License; you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.strongback.components;
import java.util.concurrent.TimeUnit;
import org.strongback.Strongback;
import org.strongback.annotation.ThreadSafe;
/**
* A switch that is initially not triggered but that can be (manually or automatically) reset.
*/
@ThreadSafe
public interface Fuse extends Switch {
/**
* Trigger the fuse. Once this method is called, the {@link #isTriggered()} switches but then will never change until it is
* {@link #reset()}.
*
* @return this object to allow for chaining methods together; never null
*/
public Fuse trigger();
/**
* Reset the fuse so it is no longer triggered.
*
* @return this object to allow for chaining methods together; never null
*/
public Fuse reset();
/**
* Create a simple fuse that is manually {@link #trigger() triggered} and manually {@link #reset()}.
*
* @return the fuse; never null
*/
public static Fuse create() {
return new Fuse() {
private boolean triggered = false;
@Override
public boolean isTriggered() {
return triggered;
}
@Override
public Fuse trigger() {
triggered = true;
return this;
}
@Override
public Fuse reset() {
triggered = false;
return this;
}
@Override
public String toString() {
return triggered ? "triggered" : "notTriggered";
}
};
}
/**
* Create a simple fuse that is manually {@link #trigger() triggered} and manually {@link #reset()}.
*
* @param whenTriggered the function that is to be called when the fuse is triggered; may be null
* @return the fuse; never null
*/
public static Fuse instantaneous( Runnable whenTriggered ) {
return new Fuse() {
@Override
public boolean isTriggered() {
return false;
}
@Override
public Fuse trigger() {
if (whenTriggered != null) {
try {
whenTriggered.run();
} catch (Throwable t) {
Strongback.logger(Fuse.class).error(t, "Error when calling fuse trigger function");
}
}
return this;
}
@Override
public Fuse reset() {
return this;
}
@Override
public String toString() {
return "notTriggered";
}
};
}
/**
* Create a fuse that can be manually {@link #reset()} but that will automatically reset after the given delay.
*
* @param delay the time after the fuse is triggered that it should automatically reset; must be positive
* @param unit the time units for the delay; may not be null
* @param clock the clock that the fuse should use; if null, the system clock will be used
* @return the auto-resetting fuse; never null
*/
public static Fuse autoResetting(long delay, TimeUnit unit, Clock clock) {
return autoResetting(delay, unit, clock, null);
}
/**
* Create a fuse that can be manually {@link #reset()} but that will automatically reset after the given delay.
*
* @param delay the time after the fuse is triggered that it should automatically reset; must be positive
* @param unit the time units for the delay; may not be null
* @param clock the clock that the fuse should use; if null, the system clock will be used
* @param whenTriggered the function that is to be called when the fuse is triggered; may be null
* @return the auto-resetting fuse; never null
*/
public static Fuse autoResetting(long delay, TimeUnit unit, Clock clock, Runnable whenTriggered) {
Clock theClock = clock != null ? clock : Clock.system();
if (unit == null) throw new IllegalArgumentException("The time unit may not be null");
long delayTimeInMillis = unit.toMillis(delay);
return new Fuse() {
private boolean triggered = false;
private volatile long resetTime = 0L;
@Override
public synchronized boolean isTriggered() {
if (triggered && theClock.currentTimeInMillis() > resetTime) triggered = false;
return triggered;
}
@Override
public synchronized Fuse trigger() {
triggered = true;
resetTime = theClock.currentTimeInMillis() + delayTimeInMillis;
if (whenTriggered != null) {
try {
whenTriggered.run();
} catch (Throwable t) {
Strongback.logger(Fuse.class).error(t, "Error when calling fuse trigger function");
}
}
return this;
}
@Override
public synchronized Fuse reset() {
triggered = false;
return this;
}
@Override
public String toString() {
return triggered ? "triggered" : "notTriggered";
}
};
}
}