Skip to content

Commit

Permalink
Merge branch 'axon-4.2.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
smcvb committed Sep 30, 2019
2 parents cf1eb4d + 49e4df8 commit 5c966d6
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public abstract class AbstractRetryScheduler implements RetryScheduler {
*/
protected AbstractRetryScheduler(Builder builder) {
builder.validate();

this.retryExecutor = builder.retryExecutor;
this.maxRetryCount = builder.maxRetryCount;
}
Expand Down Expand Up @@ -142,25 +141,16 @@ public boolean scheduleRetry(CommandMessage commandMessage,
}

/**
* A builder class for {@link RetryScheduler}s. Values for the {@link Builder#retryExecutor} and
* {@link Builder#maxRetryCount} fields are both required, with the latter having a default value of
* {@link #DEFAULT_MAX_RETRIES}.
* A builder class for the {@link RetryScheduler} implementations.
* <p>
* The default for {@code maxRetryCount} is set to a single retry.
* The {@link ScheduledExecutorService} is a <b>hard requirement</b> and as such should be provided.
*/
public abstract static class Builder<B extends Builder> {

private ScheduledExecutorService retryExecutor;
private int maxRetryCount = DEFAULT_MAX_RETRIES;

/**
* Validate the fields. This method is called in the {@link AbstractRetryScheduler}'s constructor.
*
* @throws AxonConfigurationException if validation fails.
*/
protected void validate() throws AxonConfigurationException {
assertNonNull(retryExecutor, "The ScheduledExecutorService is a hard requirement and should be provided");
assertStrictPositive(maxRetryCount, "The maxRetryCount is a hard requirement and must be at least 1");
}

/**
* Sets the {@link ScheduledExecutorService} used to schedule a command retry.
*
Expand All @@ -175,7 +165,7 @@ public B retryExecutor(ScheduledExecutorService retryExecutor) {
}

/**
* Sets the maximum number of retries allowed for a single command, defaulted to 1.
* Sets the maximum number of retries allowed for a single command. Defaults to 1.
*
* @param maxRetryCount an {@code int} specifying the maximum number of retries allowed for a single command
* @return the current Builder instance, for fluent interfacing
Expand All @@ -186,5 +176,14 @@ public B maxRetryCount(int maxRetryCount) {
// noinspection unchecked
return (B) this;
}

/**
* Validate the fields. This method is called in the {@link AbstractRetryScheduler}'s constructor.
*
* @throws AxonConfigurationException if validation fails.
*/
protected void validate() throws AxonConfigurationException {
assertNonNull(retryExecutor, "The ScheduledExecutorService is a hard requirement and should be provided");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.axonframework.commandhandling.CommandMessage;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;

import static org.axonframework.common.BuilderUtils.assertStrictPositive;

Expand Down Expand Up @@ -51,7 +52,8 @@ protected ExponentialBackOffIntervalRetryScheduler(Builder builder) {
/**
* Instantiate a Builder to be able to create a {@link ExponentialBackOffIntervalRetryScheduler}.
* <p>
* The default for {@link Builder#backoffFactor} is set to 100ms, and must be at least 1.
* The default for {@code maxRetryCount} is set to a single retry and the {@code backoffFactor} defaults to 100ms.
* The {@link ScheduledExecutorService} is a <b>hard requirement</b> and as such should be provided.
*
* @return a Builder to be able to create a {@link ExponentialBackOffIntervalRetryScheduler}
*/
Expand All @@ -68,21 +70,24 @@ protected long computeRetryInterval(CommandMessage commandMessage,
}

/**
* A builder class for an exponential backoff retry scheduler.
* Builder class to instantiate an {@link ExponentialBackOffIntervalRetryScheduler}.
* <p>
* The default for {@link Builder#backoffFactor} is set to 100ms, and must be at least 1.
* The default for the {@code backoffFactor} is set to 100ms, and must be at least 1.
* The {@link ScheduledExecutorService} is a <b>hard requirement</b> and as such should be provided.
*/
public static class Builder extends AbstractRetryScheduler.Builder<Builder> {

private long backoffFactor = DEFAULT_BACKOFF_FACTOR;

/**
* Sets the backoff factor in milliseconds at which to schedule a retry, defaulted to 100ms.
* Sets the backoff factor in milliseconds at which to schedule a retry. This field defaults to 100ms and is
* required to be a positive number.
*
* @param backoffFactor an {@code int} specifying the interval in milliseconds at which to schedule a retry.
* @return the current Builder instance, for fluent interfacing.
* @param backoffFactor an {@code int} specifying the interval in milliseconds at which to schedule a retry
* @return the current Builder instance, for fluent interfacing
*/
public Builder backoffFactor(long backoffFactor) {
assertStrictPositive(backoffFactor, "The backoffFactor must be a positive number");
this.backoffFactor = backoffFactor;
return this;
}
Expand All @@ -95,12 +100,5 @@ public Builder backoffFactor(long backoffFactor) {
public ExponentialBackOffIntervalRetryScheduler build() {
return new ExponentialBackOffIntervalRetryScheduler(this);
}

/**
* Validate the input, in this case asserting that the backoff factor is strictly positive (>= 1).
*/
protected void validate() {
assertStrictPositive(backoffFactor, "The backoff factor is a hard requirement and must be at least 1.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

import org.axonframework.commandhandling.CommandMessage;
import org.axonframework.common.AxonConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
Expand All @@ -35,8 +33,6 @@
*/
public class IntervalRetryScheduler extends AbstractRetryScheduler {

private static final Logger logger = LoggerFactory.getLogger(IntervalRetryScheduler.class);

private static final long DEFAULT_RETRY_INTERVAL = 100L;

private final long retryInterval;
Expand Down Expand Up @@ -67,8 +63,7 @@ protected long computeRetryInterval(CommandMessage commandMessage,
* Instantiate a Builder to be able to create a {@link IntervalRetryScheduler}.
* <p>
* The default for {@code retryInterval} is set to 100ms, while {@code maxRetryCount} gets a single retry.
* The {@code retryInterval}, {@code maxRetryCount} and {@link ScheduledExecutorService} are
* <b>hard requirements</b> and as such should be provided.
* The {@link ScheduledExecutorService} is a <b>hard requirement</b> and as such should be provided.
*
* @return a Builder to be able to create a {@link IntervalRetryScheduler}
*/
Expand All @@ -80,15 +75,15 @@ public static Builder builder() {
* Builder class to instantiate a {@link IntervalRetryScheduler}.
* <p>
* The default for {@code retryInterval} is set to 100ms, while {@code maxRetryCount} gets a single retry.
* The {@code retryInterval}, {@code maxRetryCount} and {@link ScheduledExecutorService} are
* <b>hard requirements</b> and as such should be provided.
* The {@link ScheduledExecutorService} is a <b>hard requirement</b> and as such should be provided.
*/
public static class Builder extends AbstractRetryScheduler.Builder<Builder> {

private long retryInterval = DEFAULT_RETRY_INTERVAL;

/**
* Sets the retry interval in milliseconds at which to schedule a retry, defaulted to 100ms.
* Sets the retry interval in milliseconds at which to schedule a retry. This field defaults to 100ms and is
* required to be a positive number.
*
* @param retryInterval an {@code int} specifying the retry interval in milliseconds at which to schedule a
* retry
Expand All @@ -108,15 +103,5 @@ public Builder retryInterval(int retryInterval) {
public IntervalRetryScheduler build() {
return new IntervalRetryScheduler(this);
}

/**
* Validates whether the fields contained in this Builder are set accordingly.
*
* @throws AxonConfigurationException if one field is asserted to be incorrect according to the Builder's
* specifications
*/
protected void validate() throws AxonConfigurationException {
assertPositive(retryInterval, "The retryInterval is a hard requirement and should be provided");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,13 @@ default String schedule(Duration triggerDuration, String deadlineName, Object me
* deadline being used. In the former case, the given {@code messageOrPayload} will be wrapped as the payload of a
* {@link DeadlineMessage}.
* </p>
* <p>
* Scheduling a deadline with the same {@code deadlineName} and {@code scheduleId} will replace the previous
* schedule with the new one.
* </p>
*
* @param triggerDuration A {@link Duration} describing the waiting period before handling the deadline
* @param deadlineName A {@link String} representing the name of the deadline to schedule
* @param messageOrPayload A {@link org.axonframework.messaging.Message} or payload for a message as an
* {@link Object}
* @param deadlineScope A {@link ScopeDescriptor} describing the scope within which the deadline was scheduled
* @return A schedule id to use when cancelling the schedule
* @return the {@code scheduleId} as a {@link String} to use when cancelling the schedule
*/
default String schedule(Duration triggerDuration,
String deadlineName,
Expand All @@ -162,16 +158,16 @@ default String schedule(Duration triggerDuration,
* Cancels the deadline corresponding to the given {@code deadlineName} / {@code scheduleId} combination.
* This method has no impact on deadlines which have already been triggered.
*
* @param deadlineName A {@link String} representing the name of the deadline to cancel
* @param scheduleId The {@link String} denoting the scheduled deadline to cancel
* @param deadlineName a {@link String} representing the name of the deadline to cancel
* @param scheduleId the {@link String} denoting the scheduled deadline to cancel
*/
void cancelSchedule(String deadlineName, String scheduleId);

/**
* Cancels all the deadlines corresponding to the given {@code deadlineName}.
* This method has no impact on deadlines which have already been triggered.
*
* @param deadlineName A {@link String} representing the name of the deadlines to cancel
* @param deadlineName a {@link String} representing the name of the deadlines to cancel
*/
void cancelAll(String deadlineName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,13 @@ public boolean covers(TrackingToken other) {

//as soon as one delegated token doesn't cover return false
for (Map.Entry<String, TrackingToken> trackingTokenEntry : trackingTokens.entrySet()) {
if (!trackingTokenEntry.getValue().covers(otherMultiToken.trackingTokens
.get(trackingTokenEntry.getKey()))) {
TrackingToken constituent = trackingTokenEntry.getValue();
TrackingToken otherConstituent = otherMultiToken.trackingTokens.get(trackingTokenEntry.getKey());
if (constituent == null) {
if (otherConstituent != null) {
return false;
}
} else if (otherConstituent != null && !constituent.covers(otherConstituent)) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public enum ReplayStatus {

/**
* Indicats the message is delivered as part of a replay (and may have been delivered before)
* Indicates the message is delivered as part of a replay (and may have been delivered before)
*/
REPLAY(true),
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.axonframework.commandhandling.gateway;

import org.axonframework.common.AxonConfigurationException;
import org.junit.*;

import java.util.concurrent.ScheduledThreadPoolExecutor;
Expand Down Expand Up @@ -36,4 +37,9 @@ public void scheduleRetry() {
assertEquals("Scheduling a retry when past maxRetryCount should have failed.",
0, doScheduleRetry(retryScheduler, MAX_RETRIES + 1));
}

@Test(expected = AxonConfigurationException.class)
public void testBuildingWhilstMissingScheduledExecutorServiceThrowsConfigurationException() {
ExponentialBackOffIntervalRetryScheduler.builder().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.axonframework.commandhandling.CommandMessage;
import org.axonframework.commandhandling.GenericCommandMessage;
import org.axonframework.common.AxonConfigurationException;
import org.axonframework.common.jdbc.JdbcException;
import org.junit.*;
import org.slf4j.Logger;
Expand Down Expand Up @@ -59,6 +60,7 @@ static long doScheduleRetry(RetryScheduler retryScheduler, int nrOfFailures) {
Class<?>[] arr = new Class[2];
arr[0] = JdbcException.class;
arr[1] = NullPointerException.class;
//noinspection unchecked
failures.add((Class<? extends Throwable>[]) arr);
}
if (retryScheduler.scheduleRetry(msg, exc, failures, after)) {
Expand Down Expand Up @@ -88,4 +90,9 @@ public void scheduleRetry() {
assertEquals("Scheduling a retry when past maxRetryCount should have failed.",
0, doScheduleRetry(retryScheduler, MAX_RETRIES + 1));
}

@Test(expected = AxonConfigurationException.class)
public void testBuildingWhilstMissingScheduledExecutorServiceThrowsConfigurationException() {
IntervalRetryScheduler.builder().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ public void doesNotCover() {
assertFalse(testSubject.covers(new MultiSourceTrackingToken(newTokens)));
}

@Test
public void coversNullConstituents() {
Map<String, TrackingToken> newTokens = new HashMap<>();
newTokens.put("token1", new GlobalSequenceTrackingToken(0));
newTokens.put("token2", null);
MultiSourceTrackingToken tokenWithNullConstituent = new MultiSourceTrackingToken(newTokens);

assertTrue(tokenWithNullConstituent.covers(tokenWithNullConstituent));
assertTrue(testSubject.covers(tokenWithNullConstituent));
assertFalse(tokenWithNullConstituent.covers(testSubject));
}


@Test(expected = IllegalArgumentException.class)
public void coversMismatchTokens() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@

@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration")
@AutoConfigureAfter(name = {
"org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration",
"org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration"
})
public class TransactionAutoConfiguration {

@Bean
Expand Down

0 comments on commit 5c966d6

Please sign in to comment.