Skip to content

Commit

Permalink
Adjust the Simply mode to AcceptAllCommands
Browse files Browse the repository at this point in the history
The SimpleCapabilityDiscoveryMode isn't clarifying the intent of this
implementation. It should instead be called
AcceptAllCommandsDiscoveryMode, as that's what it does. Furthermore, it
 should not be a hard implementation of the RestCapabilityDiscoveryMode,
 but rather use a delegate CapabilityDiscoveryMode. This switches it to
 a decorator i.o. an full implementation, which is fine for it's use
 case. Reflect this in the auto configuration, by removing the SIMPLE
 mode in favor of a property. Lastly, the decorators (ignore listing and
  accept-all) should be wrapped around another CapabilityDiscoveryMode
  instance.

#23
  • Loading branch information
smcvb committed Jan 6, 2021
1 parent 822ebc8 commit 7221e8a
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ public static class SpringCloudProperties {
*/
private boolean enabledIgnoreListing = true;

/**
* Defines whether the created {@link org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode}
* should tell others it accepts all types of commands. If {@code true}, the created {@link
* org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode} is wrapped in a {@link
* org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode}. Defaults to
* {@code false}.
*/
private boolean enableAcceptAllCommands = false;

/**
* Defines the {@link org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode}
* used by the {@link org.axonframework.extensions.springcloud.commandhandling.SpringCloudCommandRouter}.
Expand Down Expand Up @@ -289,21 +298,36 @@ public void setEnabledIgnoreListing(boolean enabledIgnoreListing) {
this.enabledIgnoreListing = enabledIgnoreListing;
}

/**
* Defines whether the created {@link org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode}
* (defined through the {@link #mode} settings) is wrapped in an {@link org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode}.
* Defaults to {@code false}, meaning that this node does not by definition accept all commands.
*
* @return a {@code boolean} specifying whether ignore listing has been disabled
*/
public boolean shouldEnableAcceptAllCommands() {
return enableAcceptAllCommands;
}

/**
* Sets whether the used {@link org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode}
* should be wrapped in an {@link org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode}.
*
* @param enableAcceptAllCommands a {@code boolean} defining whether the used {@link org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode}
* should be wrapped in an {@link org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode}
*/
public void setEnableAcceptAllCommands(boolean enableAcceptAllCommands) {
this.enableAcceptAllCommands = enableAcceptAllCommands;
}

public enum Mode {

/**
* On "REST" mode, the {@link org.axonframework.extensions.springcloud.commandhandling.SpringCloudCommandRouter}
* will use a {@link org.axonframework.extensions.springcloud.commandhandling.mode.RestCapabilityDiscoveryMode}
* to discover other nodes and to share its own capabilities.
*/
REST,

/**
* On "simple" mode, the {@link org.axonframework.extensions.springcloud.commandhandling.SpringCloudCommandRouter}
* will use a {@link org.axonframework.extensions.springcloud.commandhandling.mode.SimpleCapabilityDiscoveryMode}
* to discover other nodes and to share its own capabilities.
*/
SIMPLE
REST
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@
import org.axonframework.commandhandling.distributed.CommandRouter;
import org.axonframework.commandhandling.distributed.DistributedCommandBus;
import org.axonframework.commandhandling.distributed.RoutingStrategy;
import org.axonframework.common.AxonConfigurationException;
import org.axonframework.extensions.springcloud.DistributedCommandBusProperties;
import org.axonframework.extensions.springcloud.commandhandling.SpringCloudCommandRouter;
import org.axonframework.extensions.springcloud.commandhandling.SpringHttpCommandBusConnector;
import org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.IgnoreListingCapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.IgnoreListingDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.RestCapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.SimpleCapabilityDiscoveryMode;
import org.axonframework.serialization.Serializer;
import org.axonframework.springboot.autoconfig.InfraConfiguration;
import org.springframework.beans.factory.annotation.Qualifier;
Expand Down Expand Up @@ -86,30 +85,29 @@ public RestTemplate restTemplate() {

@Bean
@ConditionalOnMissingBean
public CapabilityDiscoveryMode capabilityDiscoveryMode(Serializer serializer, RestTemplate restTemplate) {
switch (springCloudProperties.getMode()) {
case REST:
return buildRestCapabilityDiscoveryMode(
RestCapabilityDiscoveryMode.builder(), serializer, restTemplate
);
case SIMPLE:
return buildRestCapabilityDiscoveryMode(
SimpleCapabilityDiscoveryMode.builder(), serializer, restTemplate
);
default:
throw new AxonConfigurationException(
"The configured mode [" + springCloudProperties.getMode() + "] is not supported"
);
}
@ConditionalOnProperty(value = "axon.distributed.spring-cloud.mode", havingValue = "REST")
public RestCapabilityDiscoveryMode restCapabilityDiscoveryMode(Serializer serializer, RestTemplate restTemplate) {
return RestCapabilityDiscoveryMode.builder()
.serializer(serializer)
.restTemplate(restTemplate)
.messageCapabilitiesEndpoint(springCloudProperties.getRestModeUrl())
.build();
}

private RestCapabilityDiscoveryMode buildRestCapabilityDiscoveryMode(RestCapabilityDiscoveryMode.Builder builder,
Serializer serializer,
RestTemplate restTemplate) {
return builder.serializer(serializer)
.restTemplate(restTemplate)
.messageCapabilitiesEndpoint(springCloudProperties.getRestModeUrl())
.build();
@Primary
@Bean("capabilityDiscoveryMode")
@ConditionalOnBean(CapabilityDiscoveryMode.class)
public CapabilityDiscoveryMode decorateCapabilityDiscoveryMode(CapabilityDiscoveryMode capabilityDiscoveryMode) {
CapabilityDiscoveryMode decoratedDiscoveryMode = capabilityDiscoveryMode;
if (springCloudProperties.shouldEnableAcceptAllCommands()) {
decoratedDiscoveryMode = AcceptAllCommandsDiscoveryMode.builder()
.delegate(decoratedDiscoveryMode)
.build();
}
if (springCloudProperties.shouldEnabledIgnoreListing()) {
decoratedDiscoveryMode = new IgnoreListingDiscoveryMode(decoratedDiscoveryMode);
}
return decoratedDiscoveryMode;
}

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
Expand All @@ -121,22 +119,13 @@ public CommandRouter springCloudCommandRouter(DiscoveryClient discoveryClient,
RoutingStrategy routingStrategy,
CapabilityDiscoveryMode capabilityDiscoveryMode,
Serializer serializer) {
SpringCloudCommandRouter.Builder routerBuilder = SpringCloudCommandRouter.builder();
if (shouldEnableIgnoreListing(capabilityDiscoveryMode.getClass())) {
routerBuilder.capabilityDiscoveryMode(new IgnoreListingCapabilityDiscoveryMode(capabilityDiscoveryMode));
} else {
routerBuilder.capabilityDiscoveryMode(capabilityDiscoveryMode);
}
return routerBuilder.discoveryClient(discoveryClient)
.localServiceInstance(localServiceInstance)
.routingStrategy(routingStrategy)
.serializer(serializer)
.build();
}

private boolean shouldEnableIgnoreListing(Class<? extends CapabilityDiscoveryMode> discoveryModeClass) {
return !discoveryModeClass.isAssignableFrom(IgnoreListingCapabilityDiscoveryMode.class)
&& !springCloudProperties.shouldDisableIgnoreListing();
return SpringCloudCommandRouter.builder()
.discoveryClient(discoveryClient)
.localServiceInstance(localServiceInstance)
.routingStrategy(routingStrategy)
.capabilityDiscoveryMode(capabilityDiscoveryMode)
.serializer(serializer)
.build();
}

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import org.axonframework.extensions.springcloud.commandhandling.mode.CapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.IgnoreListingDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.RestCapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.SimpleCapabilityDiscoveryMode;
import org.axonframework.extensions.springcloud.commandhandling.mode.AcceptAllCommandsDiscoveryMode;
import org.axonframework.springboot.autoconfig.AxonServerAutoConfiguration;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.*;
Expand Down Expand Up @@ -177,7 +177,7 @@ void testDisabledIgnoreListingAndSimpleModeCreatesSimpleCapabilityDiscoveryMode(
assertThat(context).getBeanNames(CapabilityDiscoveryMode.class)
.hasSize(1);
assertThat(context).getBean(CapabilityDiscoveryMode.class)
.isExactlyInstanceOf(SimpleCapabilityDiscoveryMode.class);
.isExactlyInstanceOf(AcceptAllCommandsDiscoveryMode.class);
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2010-2020. Axon Framework
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.axonframework.extensions.springcloud.commandhandling.mode;

import org.axonframework.commandhandling.distributed.CommandMessageFilter;
import org.axonframework.commandhandling.distributed.commandfilter.AcceptAll;
import org.axonframework.common.AxonConfigurationException;
import org.axonframework.serialization.Serializer;
import org.springframework.cloud.client.ServiceInstance;

import java.util.Optional;

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

/**
* Implementation of the {@link CapabilityDiscoveryMode} which defaults it's own {@link MemberCapabilities} to accept
* <b>all</b> incoming commands. It does so by enforcing the {@link CommandMessageFilter} to {@link AcceptAll} on each
* invocation of {@link #updateLocalCapabilities(ServiceInstance, int, CommandMessageFilter)}. This implementation thus
* <em>does not</em> take into account the given {@link CommandMessageFilter} upon {@link
* #updateLocalCapabilities(ServiceInstance, int, CommandMessageFilter)}.
* <p>
* Using this implementation would be a valid solution in a homogeneous command handling system, where every node can
* handling everything.
* <p>
* Note that both the {@link #updateLocalCapabilities(ServiceInstance, int, CommandMessageFilter)} and {@link
* #capabilities(ServiceInstance)} operations are delegated towards another {@code CapabilityDiscoveryMode} instance to
* ensure {@code MemberCapabilities} can still be found and delegated correctly.
*
* @author Steven van Beelen
* @since 4.4
*/
public class AcceptAllCommandsDiscoveryMode implements CapabilityDiscoveryMode {

private final CapabilityDiscoveryMode delegate;

/**
* Instantiate a {@link Builder} to be able to create a {@link AcceptAllCommandsDiscoveryMode}.
* <p>
* The {@link Serializer} is defaulted to a {@link org.axonframework.serialization.xml.XStreamSerializer} instance
* The delegate {@link CapabilityDiscoveryMode} is a <b>hard requirement</b> and as such should be provided.
*
* @return a {@link Builder} to be able to create a {@link AcceptAllCommandsDiscoveryMode}
*/
public static Builder builder() {
return new Builder();
}

/**
* Instantiate a {@link AcceptAllCommandsDiscoveryMode} based on the fields contained in the {@link Builder}.
* <p>
* Will assert that the delegate {@link CapabilityDiscoveryMode} is not {@code null} and will throw an {@link
* AxonConfigurationException} if this is the case.
*
* @param builder the {@link Builder} used to instantiate a {@link AcceptAllCommandsDiscoveryMode} instance
*/
protected AcceptAllCommandsDiscoveryMode(Builder builder) {
builder.validate();
this.delegate = builder.delegate;
}

@Override
public void updateLocalCapabilities(ServiceInstance localInstance,
int loadFactor,
CommandMessageFilter commandFilter) {
delegate.updateLocalCapabilities(localInstance, loadFactor, AcceptAll.INSTANCE);
}

@Override
public Optional<MemberCapabilities> capabilities(ServiceInstance serviceInstance)
throws ServiceInstanceClientException {
return delegate.capabilities(serviceInstance);
}

/**
* Builder class to instantiate a {@link AcceptAllCommandsDiscoveryMode}.
* <p>
* The {@link Serializer} is defaulted to a {@link org.axonframework.serialization.xml.XStreamSerializer} instance
* The delegate {@link CapabilityDiscoveryMode} is a <b>hard requirement</b> and as such should be provided.
*/
public static class Builder {

private CapabilityDiscoveryMode delegate;

/**
* Sets the delegate {@link CapabilityDiscoveryMode} used to delegate the {@link #capabilities(ServiceInstance)}
* operation too.
*
* @param delegate a {@link CapabilityDiscoveryMode} used to delegate the {@link #capabilities(ServiceInstance)}
* operation too
* @return the current Builder instance, for fluent interfacing
*/
public Builder delegate(CapabilityDiscoveryMode delegate) {
assertNonNull(delegate, "The delegate CapabilityDiscovery may not be null or empty");
this.delegate = delegate;
return this;
}

public AcceptAllCommandsDiscoveryMode build() {
return new AcceptAllCommandsDiscoveryMode(this);
}

protected void validate() {
assertNonNull(
delegate, "The delegate CapabilityDiscoveryMode is a hard requirement and should be provided"
);
}
}
}
Loading

0 comments on commit 7221e8a

Please sign in to comment.