Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@
* @return the amount of time in milliseconds.
*/
long resetMillis() default -1;

/**
* Clock type: fully qualified class name of Clock implementation class (implementing interface Clock)
* @return the fully qualified class name of Clock
*/
String clockType() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
*/
package org.fishwife.jrugged.aspects;

import java.util.concurrent.Callable;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclarePrecedence;
import org.fishwife.jrugged.CircuitBreakerConfig;
import org.fishwife.jrugged.CircuitBreakerFactory;
import org.fishwife.jrugged.Clock;
import org.fishwife.jrugged.DefaultFailureInterpreter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;

/**
* Surrounds methods decorated with the CircuitBreaker annotation with a named
* {@link org.fishwife.jrugged.CircuitBreaker}.
Expand Down Expand Up @@ -91,8 +91,10 @@ public Object monitor(final ProceedingJoinPoint pjp,
circuitBreakerAnnotation.limit(),
circuitBreakerAnnotation.windowMillis());

String clockType = circuitBreakerAnnotation.clockType();
Clock clock = createClockByType(clockType);
CircuitBreakerConfig config = new CircuitBreakerConfig(
circuitBreakerAnnotation.resetMillis(), dfi);
circuitBreakerAnnotation.resetMillis(), dfi, clock);

circuitBreaker =
circuitBreakerFactory.createCircuitBreaker(name, config);
Expand Down Expand Up @@ -124,4 +126,16 @@ public Object call() throws Exception {
}
});
}

protected Clock createClockByType(String clockType) throws InstantiationException, IllegalAccessException,
java.lang.reflect.InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
Clock clock = null;
if (clockType != null) {
clockType = clockType.trim();
if (!clockType.isEmpty()) {
clock = (Clock) (Class.forName(clockType).getConstructor().newInstance());
}
}
return clock;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@
import org.aspectj.lang.Signature;
import org.fishwife.jrugged.CircuitBreakerException;
import org.fishwife.jrugged.CircuitBreakerFactory;
import org.fishwife.jrugged.Clock;
import org.fishwife.jrugged.SystemClock;
import org.junit.Before;
import org.junit.Test;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertNull;

public class TestCircuitBreakerAspect {

Expand All @@ -39,6 +43,8 @@ public class TestCircuitBreakerAspect {

private static final String TEST_CIRCUIT_BREAKER = "TestCircuitBreaker";

private static final String SYSTEM_CLOCK_TYPE = "org.fishwife.jrugged.SystemClock";

@Before
public void setUp() {
aspect = new CircuitBreakerAspect();
Expand All @@ -51,6 +57,7 @@ public void setUp() {
expect(mockAnnotation.limit()).andReturn(5).anyTimes();
expect(mockAnnotation.resetMillis()).andReturn(30000L).anyTimes();
expect(mockAnnotation.windowMillis()).andReturn(10000L).anyTimes();
expect(mockAnnotation.clockType()).andReturn(null);
@SuppressWarnings("unchecked")
Class<Throwable>[] ignores = new Class[0];
expect(mockAnnotation.ignore()).andReturn(ignores);
Expand Down Expand Up @@ -81,6 +88,7 @@ public void testMonitor() throws Throwable {
expect(otherMockAnnotation.limit()).andReturn(5).anyTimes();
expect(otherMockAnnotation.resetMillis()).andReturn(30000L).anyTimes();
expect(otherMockAnnotation.windowMillis()).andReturn(10000L).anyTimes();
expect(otherMockAnnotation.clockType()).andReturn(SYSTEM_CLOCK_TYPE);
@SuppressWarnings("unchecked")
Class<Throwable>[] ignores = new Class[0];
expect(otherMockAnnotation.ignore()).andReturn(ignores);
Expand Down Expand Up @@ -205,6 +213,28 @@ public void testTripBreaker() throws Throwable {
verify(mockSignature);
}

@Test
public void testCreateClockByTypeWithNullClockTypePassedIn() throws Exception {
assertNull(aspect.createClockByType(null));
}

@Test
public void testCreateClockByTypeWithBlankClockTypePassedIn() throws Exception {
assertNull(aspect.createClockByType(" "));
}

@Test(expected = ClassNotFoundException.class)
public void testCreateClockByTypeWithNonExistingClockTypePassedIn() throws Exception {
aspect.createClockByType("NonExistingClass");
}

@Test
public void testCreateClockByTypeWithClockTypePassedIn() throws Exception {
Clock clock = aspect.createClockByType(SYSTEM_CLOCK_TYPE);
assertNotNull(clock);
assertTrue(clock instanceof SystemClock);
}

private static ProceedingJoinPoint createPjpMock(Signature mockSignature, int times) {
ProceedingJoinPoint mockPjp = createMock(ProceedingJoinPoint.class);
// XXX: the following two interactions are for logging, so they may happen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ public class CircuitBreakerConfig {

private FailureInterpreter failureInterpreter;
private long resetMillis;
private Clock clock;

public CircuitBreakerConfig(long resetMillis,
FailureInterpreter failureInterpreter,
Clock clock) {
this(resetMillis, failureInterpreter);
this.clock = clock;
}

public CircuitBreakerConfig(long resetMillis,
FailureInterpreter failureInterpreter) {
Expand All @@ -36,4 +44,8 @@ public long getResetMillis() {
public FailureInterpreter getFailureInterpreter() {
return failureInterpreter;
}

public Clock getClock() {
return clock;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ protected void configureCircuitBreaker(String name,
resetMillis
});
}

Clock clock = config.getClock();
if (clock != null) {
circuit.setClock(clock);
}
}

private void configureDefaultFailureInterpreter(String name, long resetMillis, CircuitBreaker circuit) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.fishwife.jrugged;

import org.junit.Before;
import org.junit.Test;

import static org.easymock.EasyMock.createMock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;

public class TestCircuitBreakerConfig {
private FailureInterpreter mockFailureInterpreter;
private long resetMillis;
private Clock mockClock;

@Before
public void setUp() {
resetMillis = 1000L;
mockFailureInterpreter = createMock(FailureInterpreter.class);
mockClock = createMock(Clock.class);
}

@Test
public void testConstructConfigWithOptionalClock() {
CircuitBreakerConfig underTest = new CircuitBreakerConfig(resetMillis, mockFailureInterpreter, mockClock);

assertEquals(resetMillis, underTest.getResetMillis());
assertSame(mockFailureInterpreter, underTest.getFailureInterpreter());
assertSame(mockClock, underTest.getClock());
}

@Test
public void testConstructConfigWithoutOptionalClock() {
CircuitBreakerConfig underTest = new CircuitBreakerConfig(resetMillis, mockFailureInterpreter);

assertEquals(resetMillis, underTest.getResetMillis());
assertSame(mockFailureInterpreter, underTest.getFailureInterpreter());
assertNull(underTest.getClock());
}
}