/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/agpl.txt * * 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 se.streamsource.infrastructure.circuitbreaker; import org.qi4j.api.io.Output; import org.qi4j.api.io.Receiver; import org.qi4j.api.io.Sender; import org.qi4j.api.specification.Specification; /** * CircuitBreaker helper methods. */ public class CircuitBreakers { public static <Item, ReceiverThrowable extends Throwable> Output<Item, ReceiverThrowable> withBreaker(final CircuitBreaker breaker, final Output<Item, ReceiverThrowable> output) { return new Output<Item, ReceiverThrowable>() { public <SenderThrowableType extends Throwable> void receiveFrom(final Sender<? extends Item, SenderThrowableType> sender) throws ReceiverThrowable, SenderThrowableType { output.receiveFrom(new Sender<Item, SenderThrowableType>() { public <ReceiverThrowableType extends Throwable> void sendTo(final Receiver<? super Item, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType { // Check breaker first if (!breaker.isOn()) throw (ReceiverThrowableType) breaker.getLastThrowable(); sender.sendTo(new Receiver<Item, ReceiverThrowableType>() { public void receive(Item item) throws ReceiverThrowableType { try { receiver.receive(item); // Notify breaker that it went well breaker.success(); } catch (Throwable receiverThrowableType) { // Notify breaker of trouble breaker.throwable(receiverThrowableType); throw (ReceiverThrowableType) receiverThrowableType; } } }); } }); } }; } /** * Allow all throwables that are equal to or subclasses of given list of throwables. * * @param throwables * @return */ public static Specification<Throwable> in(final Class<? extends Throwable>... throwables) { return new Specification<Throwable>() { public boolean satisfiedBy(Throwable item) { Class<? extends Throwable> throwableClass = item.getClass(); for (Class<? extends Throwable> throwable : throwables) { if (throwable.isAssignableFrom(throwableClass)) return true; } return false; } }; } public static Specification<Throwable> rootCause(final Specification<Throwable> specification) { return new Specification<Throwable>() { public boolean satisfiedBy(Throwable item) { return specification.satisfiedBy(unwrap(item)); } private Throwable unwrap(Throwable item) { if (item.getCause() != null) return item.getCause(); else return item; } }; } }