commit
2bf2dba8d3
|
@ -677,6 +677,15 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
@Override
|
||||
int readInt();
|
||||
|
||||
/**
|
||||
* Gets a (potentially {@code null}) 32-bit integer at the current {@code readerIndex}
|
||||
* and increases the {@code readerIndex} by {@code 4} in this buffer.
|
||||
*
|
||||
* @return a (potentially {@code null}) 32-bit integer at the current {@code readerIndex}
|
||||
* @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 4}
|
||||
*/
|
||||
Integer readNullableInt();
|
||||
|
||||
/**
|
||||
* Gets an unsigned 32-bit integer at the current {@code readerIndex}
|
||||
* and increases the {@code readerIndex} by {@code 4} in this buffer.
|
||||
|
@ -696,6 +705,15 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
@Override
|
||||
long readLong();
|
||||
|
||||
/**
|
||||
* Gets a (potentially {@code null}) 64-bit integer at the current {@code readerIndex}
|
||||
* and increases the {@code readerIndex} by {@code 8} in this buffer.
|
||||
*
|
||||
* @return a (potentially {@code null}) 64-bit integer at the current {@code readerIndex}
|
||||
* @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 8}
|
||||
*/
|
||||
Long readNullableLong();
|
||||
|
||||
/**
|
||||
* Gets a char at the current {@code readerIndex}
|
||||
* and increases the {@code readerIndex} by {@code 2} in this buffer.
|
||||
|
@ -736,6 +754,15 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
@Override
|
||||
boolean readBoolean();
|
||||
|
||||
/**
|
||||
* Gets a (potentially {@code null}) boolean at the current {@code readerIndex}
|
||||
* and increases the {@code readerIndex} by {@code 1} in this buffer.
|
||||
*
|
||||
* @return a (potentially {@code null}) boolean at the current {@code readerIndex}
|
||||
* @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 1}
|
||||
*/
|
||||
Boolean readNullableBoolean();
|
||||
|
||||
/**
|
||||
* Gets a SimpleString (potentially {@code null}) at the current {@code readerIndex}
|
||||
*
|
||||
|
@ -917,6 +944,15 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
*/
|
||||
void writeInt(int value);
|
||||
|
||||
/**
|
||||
* Sets the specified (potentially {@code null}) 32-bit integer at the current {@code writerIndex}
|
||||
* and increases the {@code writerIndex} by {@code 4} in this buffer.
|
||||
*
|
||||
* @param value The specified (potentially {@code null}) 32-bit integer
|
||||
* @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4}
|
||||
*/
|
||||
void writeNullableInt(Integer value);
|
||||
|
||||
/**
|
||||
* Sets the specified 64-bit long integer at the current
|
||||
* {@code writerIndex} and increases the {@code writerIndex} by {@code 8}
|
||||
|
@ -927,6 +963,16 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
*/
|
||||
void writeLong(long value);
|
||||
|
||||
/**
|
||||
* Sets the specified (potentially {@code null}) 64-bit long integer at the current
|
||||
* {@code writerIndex} and increases the {@code writerIndex} by {@code 8}
|
||||
* in this buffer.
|
||||
*
|
||||
* @param value The specified (potentially {@code null}) 64-bit long integer
|
||||
* @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8}
|
||||
*/
|
||||
void writeNullableLong(Long value);
|
||||
|
||||
/**
|
||||
* Sets the specified char at the current {@code writerIndex}
|
||||
* and increases the {@code writerIndex} by {@code 2} in this buffer.
|
||||
|
@ -961,6 +1007,13 @@ public interface ActiveMQBuffer extends DataInput {
|
|||
*/
|
||||
void writeBoolean(boolean val);
|
||||
|
||||
/**
|
||||
* Sets the specified (potentially {@code null}) Boolean at the current {@code writerIndex}
|
||||
*
|
||||
* @param val The specified boolean
|
||||
*/
|
||||
void writeNullableBoolean(Boolean val);
|
||||
|
||||
/**
|
||||
* Sets the specified SimpleString (potentially {@code null}) at the current {@code writerIndex}
|
||||
*
|
||||
|
|
|
@ -64,6 +64,16 @@ public class ChannelBufferWrapper implements ActiveMQBuffer {
|
|||
return readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean readNullableBoolean() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleString readNullableSimpleString() {
|
||||
return SimpleString.readNullableSimpleString(buffer);
|
||||
|
@ -125,6 +135,16 @@ public class ChannelBufferWrapper implements ActiveMQBuffer {
|
|||
buffer.writeByte((byte) (val ? -1 : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableBoolean(Boolean val) {
|
||||
if (val == null) {
|
||||
buffer.writeByte(DataConstants.NULL);
|
||||
} else {
|
||||
buffer.writeByte(DataConstants.NOT_NULL);
|
||||
writeBoolean(val);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableSimpleString(final SimpleString val) {
|
||||
SimpleString.writeNullableSimpleString(buffer, val);
|
||||
|
@ -345,11 +365,31 @@ public class ChannelBufferWrapper implements ActiveMQBuffer {
|
|||
return buffer.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer readNullableInt() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
return buffer.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long readNullableLong() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readLong();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() {
|
||||
return buffer.readShort();
|
||||
|
@ -565,11 +605,31 @@ public class ChannelBufferWrapper implements ActiveMQBuffer {
|
|||
buffer.writeInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableInt(final Integer value) {
|
||||
if (value == null) {
|
||||
buffer.writeByte(DataConstants.NULL);
|
||||
} else {
|
||||
buffer.writeByte(DataConstants.NOT_NULL);
|
||||
writeInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(final long value) {
|
||||
buffer.writeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableLong(Long value) {
|
||||
if (value == null) {
|
||||
buffer.writeByte(DataConstants.NULL);
|
||||
} else {
|
||||
buffer.writeByte(DataConstants.NOT_NULL);
|
||||
writeLong(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writerIndex() {
|
||||
return buffer.writerIndex();
|
||||
|
|
|
@ -572,6 +572,33 @@ public final class ActiveMQDefaultConfiguration {
|
|||
|
||||
public static final CriticalAnalyzerPolicy DEFAULT_ANALYZE_CRITICAL_POLICY = CriticalAnalyzerPolicy.LOG;
|
||||
|
||||
// The period (in milliseconds) used to check if the federation connection has failed to receive pings from another server
|
||||
private static long DEFAULT_FEDERATION_FAILURE_CHECK_PERIOD = 30000;
|
||||
|
||||
// how long to keep a connection alive in the absence of any data arriving from the client
|
||||
private static long DEFAULT_FEDERATION_CONNECTION_TTL = getDefaultConnectionTtl();
|
||||
|
||||
// How long to wait for a reply
|
||||
private static long DEFAULT_FEDERATION_CALL_TIMEOUT = 30000;
|
||||
|
||||
// period (in ms) between successive retries
|
||||
private static long DEFAULT_FEDERATION_RETRY_INTERVAL = 500;
|
||||
|
||||
// multiplier to apply to the retry-interval
|
||||
private static double DEFAULT_FEDERATION_RETRY_INTERVAL_MULTIPLIER = getDefaultRetryIntervalMultiplier();
|
||||
|
||||
// Maximum value for retry-interval
|
||||
private static long DEFAULT_FEDERATION_MAX_RETRY_INTERVAL = getDefaultMaxRetryInterval();
|
||||
|
||||
// How many attempts should be made to connect initially
|
||||
private static int DEFAULT_FEDERATION_INITIAL_CONNECT_ATTEMPTS = -1;
|
||||
|
||||
// How many attempts should be made to reconnect after failure
|
||||
private static int DEFAULT_FEDERATION_RECONNECT_ATTEMPTS = -1;
|
||||
|
||||
// How long to wait for a reply if in the middle of a fail-over. -1 means wait forever.
|
||||
private static long DEFAULT_FEDERATION_CALL_FAILOVER_TIMEOUT = -1;
|
||||
|
||||
/**
|
||||
* If true then the ActiveMQ Artemis Server will make use of any Protocol Managers that are in available on the classpath. If false then only the core protocol will be available, unless in Embedded mode where users can inject their own Protocol Managers.
|
||||
*/
|
||||
|
@ -1537,4 +1564,68 @@ public final class ActiveMQDefaultConfiguration {
|
|||
public static long getDefaultRetryReplicationWait() {
|
||||
return DEFAULT_RETRY_REPLICATION_WAIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* The period (in milliseconds) used to check if the federation connection has failed to receive pings from another server
|
||||
*/
|
||||
public static long getDefaultFederationFailureCheckPeriod() {
|
||||
return DEFAULT_FEDERATION_FAILURE_CHECK_PERIOD;
|
||||
}
|
||||
|
||||
/**
|
||||
* how long to keep a connection alive in the absence of any data arriving from the client
|
||||
*/
|
||||
public static long getDefaultFederationConnectionTtl() {
|
||||
return DEFAULT_FEDERATION_CONNECTION_TTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* How long to wait for a reply
|
||||
*/
|
||||
public static long getDefaultFederationCallTimeout() {
|
||||
return DEFAULT_FEDERATION_CALL_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* period (in ms) between successive retries
|
||||
*/
|
||||
public static long getDefaultFederationRetryInterval() {
|
||||
return DEFAULT_FEDERATION_RETRY_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* multiplier to apply to the retry-interval
|
||||
*/
|
||||
public static double getDefaultFederationRetryIntervalMultiplier() {
|
||||
return DEFAULT_FEDERATION_RETRY_INTERVAL_MULTIPLIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum value for retry-interval
|
||||
*/
|
||||
public static long getDefaultFederationMaxRetryInterval() {
|
||||
return DEFAULT_FEDERATION_MAX_RETRY_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* How many attempts should be made to connect initially
|
||||
*/
|
||||
public static int getDefaultFederationInitialConnectAttempts() {
|
||||
return DEFAULT_FEDERATION_INITIAL_CONNECT_ATTEMPTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* How many attempts should be made to reconnect after failure
|
||||
*/
|
||||
public static int getDefaultFederationReconnectAttempts() {
|
||||
return DEFAULT_FEDERATION_RECONNECT_ATTEMPTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* How long to wait for a reply if in the middle of a fail-over. -1 means wait forever.
|
||||
*/
|
||||
public static long getDefaultFederationCallFailoverTimeout() {
|
||||
return DEFAULT_FEDERATION_CALL_FAILOVER_TIMEOUT;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -226,6 +226,13 @@ public final class ResetLimitWrappedActiveMQBuffer extends ChannelBufferWrapper
|
|||
super.writeBoolean(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableBoolean(final Boolean val) {
|
||||
changed();
|
||||
|
||||
super.writeNullableBoolean(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByte(final byte value) {
|
||||
changed();
|
||||
|
@ -304,6 +311,13 @@ public final class ResetLimitWrappedActiveMQBuffer extends ChannelBufferWrapper
|
|||
super.writeInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableInt(final Integer value) {
|
||||
changed();
|
||||
|
||||
super.writeNullableInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(final long value) {
|
||||
changed();
|
||||
|
@ -311,6 +325,13 @@ public final class ResetLimitWrappedActiveMQBuffer extends ChannelBufferWrapper
|
|||
super.writeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableLong(final Long value) {
|
||||
changed();
|
||||
|
||||
super.writeNullableLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableSimpleString(final SimpleString val) {
|
||||
changed();
|
||||
|
|
|
@ -375,6 +375,16 @@ final class CompressedLargeMessageControllerImpl implements LargeMessageControll
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer readNullableInt() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return readInt() & 0xFFFFFFFFL;
|
||||
|
@ -389,6 +399,16 @@ final class CompressedLargeMessageControllerImpl implements LargeMessageControll
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long readNullableLong() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readLong();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readBytes(final byte[] dst, final int dstIndex, final int length) {
|
||||
try {
|
||||
|
@ -487,11 +507,21 @@ final class CompressedLargeMessageControllerImpl implements LargeMessageControll
|
|||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableInt(final Integer value) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(final long value) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableLong(final Long value) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(final byte[] src, final int srcIndex, final int length) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
|
@ -532,6 +562,16 @@ final class CompressedLargeMessageControllerImpl implements LargeMessageControll
|
|||
return readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean readNullableBoolean() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return (char) readShort();
|
||||
|
@ -624,6 +664,11 @@ final class CompressedLargeMessageControllerImpl implements LargeMessageControll
|
|||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableBoolean(final Boolean val) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChar(final char val) {
|
||||
throw new IllegalAccessError(OPERATION_NOT_SUPPORTED);
|
||||
|
|
|
@ -744,6 +744,16 @@ public class LargeMessageControllerImpl implements LargeMessageController {
|
|||
return getInt(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer readNullableInt() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return readInt() & 0xFFFFFFFFL;
|
||||
|
@ -756,6 +766,16 @@ public class LargeMessageControllerImpl implements LargeMessageController {
|
|||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long readNullableLong() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readLong();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readBytes(final byte[] dst, final int dstIndex, final int length) {
|
||||
getBytes(readerIndex, dst, dstIndex, length);
|
||||
|
@ -833,11 +853,21 @@ public class LargeMessageControllerImpl implements LargeMessageController {
|
|||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableInt(final Integer value) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(final long value) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableLong(final Long value) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(final byte[] src, final int srcIndex, final int length) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
|
@ -915,6 +945,16 @@ public class LargeMessageControllerImpl implements LargeMessageController {
|
|||
return readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean readNullableBoolean() {
|
||||
int b = readByte();
|
||||
if (b == DataConstants.NULL) {
|
||||
return null;
|
||||
} else {
|
||||
return readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return (char) readShort();
|
||||
|
@ -1008,6 +1048,11 @@ public class LargeMessageControllerImpl implements LargeMessageController {
|
|||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullableBoolean(final Boolean val) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChar(final char val) {
|
||||
throw new IllegalAccessError(LargeMessageControllerImpl.READ_ONLY_ERROR_MESSAGE);
|
||||
|
|
|
@ -22,6 +22,9 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicy;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
|
@ -34,6 +37,8 @@ public class FederationConfiguration implements Serializable {
|
|||
|
||||
private List<FederationUpstreamConfiguration> upstreamConfigurations = new ArrayList<>();
|
||||
|
||||
private List<FederationDownstreamConfiguration> downstreamConfigurations = new ArrayList<>();
|
||||
|
||||
private Map<String, FederationPolicy> federationPolicyMap = new HashMap<>();
|
||||
|
||||
private Map<String, FederationTransformerConfiguration> transformerConfigurationMap = new HashMap<>();
|
||||
|
@ -47,11 +52,28 @@ public class FederationConfiguration implements Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public List<FederationDownstreamConfiguration> getDownstreamConfigurations() {
|
||||
return downstreamConfigurations;
|
||||
}
|
||||
|
||||
public FederationConfiguration addDownstreamConfiguration(FederationDownstreamConfiguration federationDownstreamConfiguration) {
|
||||
this.downstreamConfigurations.add(federationDownstreamConfiguration);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FederationConfiguration addFederationPolicy(FederationPolicy federationPolicy) {
|
||||
federationPolicyMap.put(federationPolicy.getName(), federationPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clearDownstreamConfigurations() {
|
||||
this.downstreamConfigurations.clear();
|
||||
}
|
||||
|
||||
public void clearUpstreamConfigurations() {
|
||||
this.upstreamConfigurations.clear();
|
||||
}
|
||||
|
||||
public Map<String, FederationPolicy> getFederationPolicyMap() {
|
||||
return federationPolicyMap;
|
||||
}
|
||||
|
@ -121,6 +143,16 @@ public class FederationConfiguration implements Serializable {
|
|||
public int hashCode() {
|
||||
return Objects.hash(user, password);
|
||||
}
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
buffer.writeNullableString(user);
|
||||
buffer.writeNullableString(password);
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
user = buffer.readNullableString();
|
||||
password = buffer.readNullableString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
|
@ -21,6 +21,9 @@ import java.util.HashSet;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.utils.Preconditions;
|
||||
|
||||
public class FederationAddressPolicyConfiguration implements FederationPolicy<FederationAddressPolicyConfiguration>, Serializable {
|
||||
|
||||
private String name;
|
||||
|
@ -106,6 +109,55 @@ public class FederationAddressPolicyConfiguration implements FederationPolicy<Fe
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkArgument(name != null, "name can not be null");
|
||||
buffer.writeString(name);
|
||||
buffer.writeNullableBoolean(autoDelete);
|
||||
buffer.writeNullableLong(autoDeleteDelay);
|
||||
buffer.writeNullableLong(autoDeleteMessageCount);
|
||||
buffer.writeInt(maxHops);
|
||||
buffer.writeNullableString(transformerRef);
|
||||
|
||||
encodeMatchers(buffer, includes);
|
||||
encodeMatchers(buffer, excludes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
name = buffer.readString();
|
||||
autoDelete = buffer.readNullableBoolean();
|
||||
autoDeleteDelay = buffer.readNullableLong();
|
||||
autoDeleteMessageCount = buffer.readNullableLong();
|
||||
maxHops = buffer.readInt();
|
||||
transformerRef = buffer.readNullableString();
|
||||
|
||||
includes = new HashSet<>();
|
||||
excludes = new HashSet<>();
|
||||
decodeMatchers(buffer, includes);
|
||||
decodeMatchers(buffer, excludes);
|
||||
|
||||
}
|
||||
|
||||
private void encodeMatchers(final ActiveMQBuffer buffer, final Set<Matcher> matchers) {
|
||||
buffer.writeInt(matchers == null ? 0 : matchers.size());
|
||||
if (matchers != null) {
|
||||
for (Matcher matcher : matchers) {
|
||||
matcher.encode(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeMatchers(final ActiveMQBuffer buffer, final Set<Matcher> matchers) {
|
||||
final int size = buffer.readInt();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
Matcher matcher = new Matcher();
|
||||
matcher.decode(buffer);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Matcher implements Serializable {
|
||||
|
||||
private String addressMatch;
|
||||
|
@ -131,6 +183,15 @@ public class FederationAddressPolicyConfiguration implements FederationPolicy<Fe
|
|||
public int hashCode() {
|
||||
return Objects.hash(addressMatch);
|
||||
}
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkArgument(addressMatch != null, "addressMatch can not be null");
|
||||
buffer.writeString(addressMatch);
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
addressMatch = buffer.readString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
|
||||
public class FederationConnectionConfiguration implements Serializable {
|
||||
|
||||
public static long DEFAULT_CIRCUIT_BREAKER_TIMEOUT = 30000;
|
||||
|
||||
private boolean isHA;
|
||||
private String discoveryGroupName;
|
||||
private List<String> staticConnectors;
|
||||
private int priorityAdjustment;
|
||||
|
||||
private long circuitBreakerTimeout = DEFAULT_CIRCUIT_BREAKER_TIMEOUT;
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean shareConnection;
|
||||
|
||||
private long clientFailureCheckPeriod = ActiveMQDefaultConfiguration.getDefaultFederationFailureCheckPeriod();
|
||||
private long connectionTTL = ActiveMQDefaultConfiguration.getDefaultFederationConnectionTtl();
|
||||
private long retryInterval = ActiveMQDefaultConfiguration.getDefaultFederationRetryInterval();
|
||||
private double retryIntervalMultiplier = ActiveMQDefaultConfiguration.getDefaultFederationRetryIntervalMultiplier();
|
||||
private long maxRetryInterval = ActiveMQDefaultConfiguration.getDefaultFederationMaxRetryInterval();
|
||||
private int initialConnectAttempts = ActiveMQDefaultConfiguration.getDefaultFederationInitialConnectAttempts();
|
||||
private int reconnectAttempts = ActiveMQDefaultConfiguration.getDefaultFederationReconnectAttempts();
|
||||
private long callTimeout = ActiveMQDefaultConfiguration.getDefaultFederationCallTimeout();
|
||||
private long callFailoverTimeout = ActiveMQDefaultConfiguration.getDefaultFederationCallFailoverTimeout();
|
||||
|
||||
public String getDiscoveryGroupName() {
|
||||
return discoveryGroupName;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setDiscoveryGroupName(String discoveryGroupName) {
|
||||
this.discoveryGroupName = discoveryGroupName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getStaticConnectors() {
|
||||
return staticConnectors;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setStaticConnectors(List<String> staticConnectors) {
|
||||
this.staticConnectors = staticConnectors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isHA() {
|
||||
return isHA;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setHA(boolean HA) {
|
||||
isHA = HA;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCircuitBreakerTimeout() {
|
||||
return circuitBreakerTimeout;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setCircuitBreakerTimeout(long circuitBreakerTimeout) {
|
||||
this.circuitBreakerTimeout = circuitBreakerTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getPriorityAdjustment() {
|
||||
return priorityAdjustment;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setPriorityAdjustment(int priorityAdjustment) {
|
||||
this.priorityAdjustment = priorityAdjustment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isShareConnection() {
|
||||
return shareConnection;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setShareConnection(boolean shareConnection) {
|
||||
this.shareConnection = shareConnection;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getClientFailureCheckPeriod() {
|
||||
return clientFailureCheckPeriod;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setClientFailureCheckPeriod(long clientFailureCheckPeriod) {
|
||||
this.clientFailureCheckPeriod = clientFailureCheckPeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getConnectionTTL() {
|
||||
return connectionTTL;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setConnectionTTL(long connectionTTL) {
|
||||
this.connectionTTL = connectionTTL;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getRetryInterval() {
|
||||
return retryInterval;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setRetryInterval(long retryInterval) {
|
||||
this.retryInterval = retryInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getRetryIntervalMultiplier() {
|
||||
return retryIntervalMultiplier;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setRetryIntervalMultiplier(double retryIntervalMultiplier) {
|
||||
this.retryIntervalMultiplier = retryIntervalMultiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getMaxRetryInterval() {
|
||||
return maxRetryInterval;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setMaxRetryInterval(long maxRetryInterval) {
|
||||
this.maxRetryInterval = maxRetryInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getInitialConnectAttempts() {
|
||||
return initialConnectAttempts;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setInitialConnectAttempts(int initialConnectAttempts) {
|
||||
this.initialConnectAttempts = initialConnectAttempts;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getReconnectAttempts() {
|
||||
return reconnectAttempts;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setReconnectAttempts(int reconnectAttempts) {
|
||||
this.reconnectAttempts = reconnectAttempts;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCallTimeout() {
|
||||
return callTimeout;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setCallTimeout(long callTimeout) {
|
||||
this.callTimeout = callTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCallFailoverTimeout() {
|
||||
return callFailoverTimeout;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setCallFailoverTimeout(long callFailoverTimeout) {
|
||||
this.callFailoverTimeout = callFailoverTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
FederationConnectionConfiguration that = (FederationConnectionConfiguration) o;
|
||||
return clientFailureCheckPeriod == that.clientFailureCheckPeriod &&
|
||||
connectionTTL == that.connectionTTL &&
|
||||
retryInterval == that.retryInterval &&
|
||||
Double.compare(that.retryIntervalMultiplier, retryIntervalMultiplier) == 0 &&
|
||||
maxRetryInterval == that.maxRetryInterval &&
|
||||
initialConnectAttempts == that.initialConnectAttempts &&
|
||||
reconnectAttempts == that.reconnectAttempts &&
|
||||
callTimeout == that.callTimeout &&
|
||||
callFailoverTimeout == that.callFailoverTimeout &&
|
||||
isHA == that.isHA &&
|
||||
priorityAdjustment == that.priorityAdjustment &&
|
||||
circuitBreakerTimeout == that.circuitBreakerTimeout &&
|
||||
shareConnection == that.shareConnection &&
|
||||
Objects.equals(discoveryGroupName, that.discoveryGroupName) &&
|
||||
Objects.equals(staticConnectors, that.staticConnectors) &&
|
||||
Objects.equals(username, that.username) &&
|
||||
Objects.equals(password, that.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects
|
||||
.hash(clientFailureCheckPeriod, connectionTTL, retryInterval, retryIntervalMultiplier,
|
||||
maxRetryInterval, initialConnectAttempts, reconnectAttempts, callTimeout,
|
||||
callFailoverTimeout, isHA, discoveryGroupName, staticConnectors, priorityAdjustment,
|
||||
circuitBreakerTimeout, username, password, shareConnection);
|
||||
}
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
|
||||
buffer.writeNullableString(username);
|
||||
buffer.writeNullableString(password);
|
||||
buffer.writeBoolean(shareConnection);
|
||||
buffer.writeInt(priorityAdjustment);
|
||||
|
||||
buffer.writeLong(clientFailureCheckPeriod);
|
||||
buffer.writeLong(connectionTTL);
|
||||
buffer.writeLong(retryInterval);
|
||||
buffer.writeDouble(retryIntervalMultiplier);
|
||||
buffer.writeLong(retryInterval);
|
||||
buffer.writeInt(initialConnectAttempts);
|
||||
buffer.writeInt(reconnectAttempts);
|
||||
buffer.writeLong(callTimeout);
|
||||
buffer.writeLong(callFailoverTimeout);
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
username = buffer.readNullableString();
|
||||
password = buffer.readNullableString();
|
||||
shareConnection = buffer.readBoolean();
|
||||
priorityAdjustment = buffer.readInt();
|
||||
|
||||
clientFailureCheckPeriod = buffer.readLong();
|
||||
connectionTTL = buffer.readLong();
|
||||
retryInterval = buffer.readLong();
|
||||
retryIntervalMultiplier = buffer.readDouble();
|
||||
maxRetryInterval = buffer.readLong();
|
||||
initialConnectAttempts = buffer.readInt();
|
||||
reconnectAttempts = buffer.readInt();
|
||||
callTimeout = buffer.readLong();
|
||||
callFailoverTimeout = buffer.readLong();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
|
||||
public class FederationDownstreamConfiguration extends FederationStreamConfiguration<FederationDownstreamConfiguration> {
|
||||
|
||||
private String upstreamConfigurationRef;
|
||||
private TransportConfiguration upstreamConfiguration;
|
||||
|
||||
public String getUpstreamConfigurationRef() {
|
||||
return upstreamConfigurationRef;
|
||||
}
|
||||
|
||||
public void setUpstreamConfigurationRef(String upstreamConfigurationRef) {
|
||||
this.upstreamConfigurationRef = upstreamConfigurationRef;
|
||||
}
|
||||
|
||||
public TransportConfiguration getUpstreamConfiguration() {
|
||||
return upstreamConfiguration;
|
||||
}
|
||||
|
||||
public void setUpstreamConfiguration(TransportConfiguration transportConfiguration) {
|
||||
|
||||
final Map<String, Object> params = new HashMap<>(transportConfiguration.getParams());
|
||||
|
||||
//clear any TLS settings as they won't apply to the federated server that uses this config
|
||||
//The federated server that creates the upstream back will rely on its config from the acceptor for TLS
|
||||
params.remove(TransportConstants.SSL_ENABLED_PROP_NAME);
|
||||
params.remove(TransportConstants.SSL_PROVIDER);
|
||||
params.remove(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME);
|
||||
params.remove(TransportConstants.KEYSTORE_PATH_PROP_NAME);
|
||||
params.remove(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME);
|
||||
params.remove(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME);
|
||||
params.remove(TransportConstants.TRUSTSTORE_PATH_PROP_NAME);
|
||||
params.remove(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME);
|
||||
params.remove(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME);
|
||||
|
||||
this.upstreamConfiguration = new TransportConfiguration(transportConfiguration.getFactoryClassName(), params,
|
||||
transportConfiguration.getName(), transportConfiguration.getExtraParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
super.encode(buffer);
|
||||
upstreamConfiguration.encode(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
super.decode(buffer);
|
||||
upstreamConfiguration = new TransportConfiguration();
|
||||
upstreamConfiguration.decode(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
FederationDownstreamConfiguration that = (FederationDownstreamConfiguration) o;
|
||||
return Objects.equals(upstreamConfigurationRef, that.upstreamConfigurationRef) &&
|
||||
Objects.equals(upstreamConfiguration, that.upstreamConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), upstreamConfigurationRef, upstreamConfiguration);
|
||||
}
|
||||
}
|
|
@ -16,9 +16,16 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
|
||||
public interface FederationPolicy<T> {
|
||||
|
||||
String getName();
|
||||
|
||||
T setName(String name);
|
||||
|
||||
void encode(ActiveMQBuffer buffer);
|
||||
|
||||
void decode(ActiveMQBuffer buffer);
|
||||
|
||||
}
|
|
@ -22,6 +22,9 @@ import java.util.HashSet;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.utils.Preconditions;
|
||||
|
||||
public class FederationPolicySet implements FederationPolicy<FederationPolicySet>, Serializable {
|
||||
|
||||
private String name;
|
||||
|
@ -65,4 +68,29 @@ public class FederationPolicySet implements FederationPolicy<FederationPolicySet
|
|||
public int hashCode() {
|
||||
return Objects.hash(name, policyRefs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkArgument(name != null, "name can not be null");
|
||||
buffer.writeString(name);
|
||||
|
||||
buffer.writeInt(policyRefs == null ? 0 : policyRefs.size());
|
||||
if (policyRefs != null) {
|
||||
for (String policyRef : policyRefs) {
|
||||
buffer.writeString(policyRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
name = buffer.readString();
|
||||
|
||||
final int policyRefsSize = buffer.readInt();
|
||||
policyRefs = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < policyRefsSize; i++) {
|
||||
policyRefs.add(buffer.readString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,9 @@ import java.util.HashSet;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.utils.Preconditions;
|
||||
|
||||
public class FederationQueuePolicyConfiguration implements FederationPolicy<FederationQueuePolicyConfiguration>, Serializable {
|
||||
|
||||
private String name;
|
||||
|
@ -86,6 +89,49 @@ public class FederationQueuePolicyConfiguration implements FederationPolicy<Fede
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkArgument(name != null, "name can not be null");
|
||||
buffer.writeString(name);
|
||||
buffer.writeBoolean(includeFederated);
|
||||
buffer.writeNullableInt(priorityAdjustment);
|
||||
buffer.writeNullableString(transformerRef);
|
||||
encodeMatchers(buffer, includes);
|
||||
encodeMatchers(buffer, excludes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
name = buffer.readString();
|
||||
includeFederated = buffer.readBoolean();
|
||||
priorityAdjustment = buffer.readNullableInt();
|
||||
transformerRef = buffer.readNullableString();
|
||||
|
||||
includes = new HashSet<>();
|
||||
excludes = new HashSet<>();
|
||||
decodeMatchers(buffer, includes);
|
||||
decodeMatchers(buffer, excludes);
|
||||
}
|
||||
|
||||
private void encodeMatchers(final ActiveMQBuffer buffer, final Set<Matcher> matchers) {
|
||||
buffer.writeInt(matchers == null ? 0 : matchers.size());
|
||||
if (matchers != null) {
|
||||
for (Matcher matcher : matchers) {
|
||||
matcher.encode(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeMatchers(final ActiveMQBuffer buffer, final Set<Matcher> matchers) {
|
||||
final int size = buffer.readInt();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
Matcher matcher = new Matcher();
|
||||
matcher.decode(buffer);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Matcher implements Serializable {
|
||||
|
||||
private String queueMatch;
|
||||
|
@ -122,6 +168,16 @@ public class FederationQueuePolicyConfiguration implements FederationPolicy<Fede
|
|||
public int hashCode() {
|
||||
return Objects.hash(queueMatch, addressMatch);
|
||||
}
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
buffer.writeNullableString(addressMatch);
|
||||
buffer.writeNullableString(queueMatch);
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
addressMatch = buffer.readNullableString();
|
||||
queueMatch = buffer.readNullableString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
|
@ -22,7 +22,9 @@ import java.util.HashSet;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class FederationUpstreamConfiguration implements Serializable {
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
|
||||
public abstract class FederationStreamConfiguration <T extends FederationStreamConfiguration<T>> implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
|
@ -33,23 +35,23 @@ public class FederationUpstreamConfiguration implements Serializable {
|
|||
return name;
|
||||
}
|
||||
|
||||
public FederationUpstreamConfiguration setName(String name) {
|
||||
public T setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public Set<String> getPolicyRefs() {
|
||||
return policyRefs;
|
||||
}
|
||||
|
||||
public FederationUpstreamConfiguration addPolicyRef(String name) {
|
||||
public T addPolicyRef(String name) {
|
||||
policyRefs.add(name);
|
||||
return this;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public FederationUpstreamConfiguration addPolicyRefs(Collection<String> names) {
|
||||
public T addPolicyRefs(Collection<String> names) {
|
||||
policyRefs.addAll(names);
|
||||
return this;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration getConnectionConfiguration() {
|
||||
|
@ -58,16 +60,35 @@ public class FederationUpstreamConfiguration implements Serializable {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FederationUpstreamConfiguration)) return false;
|
||||
FederationUpstreamConfiguration that = (FederationUpstreamConfiguration) o;
|
||||
return Objects.equals(name, that.name) &&
|
||||
Objects.equals(connectionConfiguration, that.connectionConfiguration) &&
|
||||
Objects.equals(policyRefs, that.policyRefs);
|
||||
if (this == o)
|
||||
return true;
|
||||
if (!(o instanceof FederationStreamConfiguration))
|
||||
return false;
|
||||
FederationStreamConfiguration that = (FederationStreamConfiguration) o;
|
||||
return Objects.equals(name, that.name) && Objects.equals(connectionConfiguration, that.connectionConfiguration) && Objects.equals(policyRefs, that.policyRefs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, connectionConfiguration, policyRefs);
|
||||
}
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
buffer.writeString(name);
|
||||
connectionConfiguration.encode(buffer);
|
||||
|
||||
buffer.writeInt(policyRefs == null ? 0 : policyRefs.size());
|
||||
for (String policyRef : policyRefs) {
|
||||
buffer.writeString(policyRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
name = buffer.readString();
|
||||
connectionConfiguration.decode(buffer);
|
||||
int policyRefNum = buffer.readInt();
|
||||
for (int i = 0; i < policyRefNum; i++) {
|
||||
policyRefs.add(buffer.readString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,8 +17,12 @@
|
|||
package org.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.core.config.TransformerConfiguration;
|
||||
import org.apache.activemq.artemis.utils.Preconditions;
|
||||
|
||||
public class FederationTransformerConfiguration implements Serializable {
|
||||
|
||||
|
@ -26,6 +30,9 @@ public class FederationTransformerConfiguration implements Serializable {
|
|||
|
||||
private TransformerConfiguration transformerConfiguration;
|
||||
|
||||
public FederationTransformerConfiguration() {
|
||||
}
|
||||
|
||||
public FederationTransformerConfiguration(String name, TransformerConfiguration transformerConfiguration) {
|
||||
this.name = name;
|
||||
this.transformerConfiguration = transformerConfiguration;
|
||||
|
@ -52,4 +59,30 @@ public class FederationTransformerConfiguration implements Serializable {
|
|||
public int hashCode() {
|
||||
return Objects.hash(name, transformerConfiguration);
|
||||
}
|
||||
|
||||
|
||||
public void encode(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkArgument(name != null, "name can not be null");
|
||||
Preconditions.checkArgument(transformerConfiguration != null, "transformerConfiguration can not be null");
|
||||
buffer.writeString(name);
|
||||
|
||||
buffer.writeString(transformerConfiguration.getClassName());
|
||||
buffer.writeInt(transformerConfiguration.getProperties() == null ? 0 : transformerConfiguration.getProperties().size());
|
||||
if (transformerConfiguration.getProperties() != null) {
|
||||
for (Map.Entry<String, String> entry : transformerConfiguration.getProperties().entrySet()) {
|
||||
buffer.writeString(entry.getKey());
|
||||
buffer.writeString(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void decode(ActiveMQBuffer buffer) {
|
||||
name = buffer.readString();
|
||||
transformerConfiguration = new TransformerConfiguration(buffer.readString());
|
||||
|
||||
final int propertiesSize = buffer.readInt();
|
||||
for (int i = 0; i < propertiesSize; i++) {
|
||||
transformerConfiguration.getProperties().put(buffer.readString(), buffer.readString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
public class FederationUpstreamConfiguration extends FederationStreamConfiguration<FederationUpstreamConfiguration> {
|
||||
|
||||
}
|
|
@ -64,6 +64,9 @@ public final class ChannelImpl implements Channel {
|
|||
* cluster used for controlling nodes in a cluster remotely
|
||||
*/
|
||||
CLUSTER(3),
|
||||
|
||||
FEDERATION(4),
|
||||
|
||||
/**
|
||||
* Channels [0-9] are reserved for the system, user channels must be greater than that.
|
||||
*/
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.Disconnect
|
|||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.DisconnectConsumerWithKillMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.DisconnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.DisconnectMessage_V2;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.FederationDownstreamConnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.NullResponseMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.NullResponseMessage_V2;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.PacketsConfirmedMessage;
|
||||
|
@ -109,6 +110,7 @@ import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.DIS
|
|||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.DISCONNECT_CONSUMER;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.DISCONNECT_V2;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.EXCEPTION;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.FEDERATION_DOWNSTREAM_CONNECT;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.NULL_RESPONSE;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.PACKETS_CONFIRMED;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.PING;
|
||||
|
@ -471,6 +473,10 @@ public abstract class PacketDecoder implements Serializable {
|
|||
packet = new DisconnectConsumerWithKillMessage();
|
||||
break;
|
||||
}
|
||||
case FEDERATION_DOWNSTREAM_CONNECT: {
|
||||
packet = new FederationDownstreamConnectMessage();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw ActiveMQClientMessageBundle.BUNDLE.invalidType(packetType);
|
||||
}
|
||||
|
|
|
@ -277,6 +277,8 @@ public class PacketImpl implements Packet {
|
|||
|
||||
public static final byte SESS_BINDINGQUERY_RESP_V4 = -15;
|
||||
|
||||
public static final byte FEDERATION_DOWNSTREAM_CONNECT = -16;
|
||||
|
||||
|
||||
// Static --------------------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.protocol.core.impl.wireformat;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
|
||||
public class FederationDownstreamConnectMessage extends FederationStreamConnectMessage<FederationDownstreamConfiguration> {
|
||||
|
||||
public static final String UPSTREAM_SUFFIX = "-upstream";
|
||||
|
||||
public FederationDownstreamConnectMessage() {
|
||||
super(FEDERATION_DOWNSTREAM_CONNECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FederationDownstreamConfiguration decodeStreamConfiguration(ActiveMQBuffer buffer) {
|
||||
final FederationDownstreamConfiguration downstreamConfiguration = new FederationDownstreamConfiguration();
|
||||
downstreamConfiguration.decode(buffer);
|
||||
return downstreamConfiguration;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.protocol.core.impl.wireformat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration.Credentials;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicy;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationStreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl;
|
||||
import org.apache.activemq.artemis.utils.Preconditions;
|
||||
|
||||
public abstract class FederationStreamConnectMessage <T extends FederationStreamConfiguration> extends PacketImpl {
|
||||
|
||||
private String name;
|
||||
private Credentials credentials;
|
||||
private Map<String, FederationPolicy> federationPolicyMap = new HashMap<>();
|
||||
private Map<String, FederationTransformerConfiguration> transformerConfigurationMap = new HashMap<>();
|
||||
private T streamConfiguration;
|
||||
|
||||
public FederationStreamConnectMessage(final byte type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Credentials getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public void setCredentials(
|
||||
Credentials credentials) {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public T getStreamConfiguration() {
|
||||
return streamConfiguration;
|
||||
}
|
||||
|
||||
public void setStreamConfiguration(T streamConfiguration) {
|
||||
this.streamConfiguration = streamConfiguration;
|
||||
}
|
||||
|
||||
public Map<String, FederationPolicy> getFederationPolicyMap() {
|
||||
return federationPolicyMap;
|
||||
}
|
||||
|
||||
public void setFederationPolicyMap(
|
||||
Map<String, FederationPolicy> federationPolicyMap) {
|
||||
this.federationPolicyMap = federationPolicyMap;
|
||||
}
|
||||
|
||||
public Map<String, FederationTransformerConfiguration> getTransformerConfigurationMap() {
|
||||
return transformerConfigurationMap;
|
||||
}
|
||||
|
||||
public void setTransformerConfigurationMap(
|
||||
Map<String, FederationTransformerConfiguration> transformerConfigurationMap) {
|
||||
this.transformerConfigurationMap = transformerConfigurationMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeRest(ActiveMQBuffer buffer) {
|
||||
Preconditions.checkNotNull(streamConfiguration);
|
||||
|
||||
super.encodeRest(buffer);
|
||||
buffer.writeString(name);
|
||||
|
||||
if (credentials != null) {
|
||||
buffer.writeBoolean(true);
|
||||
credentials.encode(buffer);
|
||||
} else {
|
||||
buffer.writeBoolean(false);
|
||||
}
|
||||
|
||||
buffer.writeInt(federationPolicyMap == null ? 0 : federationPolicyMap.size());
|
||||
if (federationPolicyMap != null) {
|
||||
for (FederationPolicy policy : federationPolicyMap.values()) {
|
||||
buffer.writeString(policy.getClass().getName());
|
||||
policy.encode(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.writeInt(transformerConfigurationMap == null ? 0 : transformerConfigurationMap.size());
|
||||
if (transformerConfigurationMap != null) {
|
||||
for (FederationTransformerConfiguration transformerConfiguration : transformerConfigurationMap.values()) {
|
||||
transformerConfiguration.encode(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
streamConfiguration.encode(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decodeRest(ActiveMQBuffer buffer) {
|
||||
super.decodeRest(buffer);
|
||||
|
||||
this.name = buffer.readString();
|
||||
boolean hasCredentials = buffer.readBoolean();
|
||||
if (hasCredentials) {
|
||||
credentials = new Credentials();
|
||||
credentials.decode(buffer);
|
||||
}
|
||||
|
||||
int policySize = buffer.readInt();
|
||||
for (int i = 0; i < policySize; i++) {
|
||||
String clazz = buffer.readString();
|
||||
FederationPolicy policy = getFederationPolicy(clazz);
|
||||
policy.decode(buffer);
|
||||
federationPolicyMap.put(policy.getName(), policy);
|
||||
}
|
||||
|
||||
int transformerSize = buffer.readInt();
|
||||
for (int i = 0; i < transformerSize; i++) {
|
||||
FederationTransformerConfiguration transformerConfiguration
|
||||
= new FederationTransformerConfiguration();
|
||||
transformerConfiguration.decode(buffer);
|
||||
transformerConfigurationMap.put(transformerConfiguration.getName(), transformerConfiguration);
|
||||
}
|
||||
|
||||
streamConfiguration = decodeStreamConfiguration(buffer);
|
||||
}
|
||||
|
||||
protected abstract T decodeStreamConfiguration(ActiveMQBuffer buffer);
|
||||
|
||||
private FederationPolicy getFederationPolicy(String clazz) {
|
||||
try {
|
||||
return (FederationPolicy) Class.forName(clazz).getConstructor(null).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Error. Unable to instantiate FederationPolicy: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.config.federation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FederationConnectionConfiguration implements Serializable {
|
||||
|
||||
public static long DEFAULT_CIRCUIT_BREAKER_TIMEOUT = 30000;
|
||||
|
||||
private boolean isHA;
|
||||
private String discoveryGroupName;
|
||||
private List<String> staticConnectors;
|
||||
private int priorityAdjustment;
|
||||
|
||||
private long circuitBreakerTimeout = DEFAULT_CIRCUIT_BREAKER_TIMEOUT;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getDiscoveryGroupName() {
|
||||
return discoveryGroupName;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setDiscoveryGroupName(String discoveryGroupName) {
|
||||
this.discoveryGroupName = discoveryGroupName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getStaticConnectors() {
|
||||
return staticConnectors;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setStaticConnectors(List<String> staticConnectors) {
|
||||
this.staticConnectors = staticConnectors;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isHA() {
|
||||
return isHA;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setHA(boolean HA) {
|
||||
isHA = HA;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCircuitBreakerTimeout() {
|
||||
return circuitBreakerTimeout;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setCircuitBreakerTimeout(long circuitBreakerTimeout) {
|
||||
this.circuitBreakerTimeout = circuitBreakerTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getPriorityAdjustment() {
|
||||
return priorityAdjustment;
|
||||
}
|
||||
|
||||
public FederationConnectionConfiguration setPriorityAdjustment(int priorityAdjustment) {
|
||||
this.priorityAdjustment = priorityAdjustment;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FederationConnectionConfiguration)) return false;
|
||||
FederationConnectionConfiguration that = (FederationConnectionConfiguration) o;
|
||||
return isHA == that.isHA &&
|
||||
circuitBreakerTimeout == that.circuitBreakerTimeout &&
|
||||
Objects.equals(discoveryGroupName, that.discoveryGroupName) &&
|
||||
Objects.equals(staticConnectors, that.staticConnectors) &&
|
||||
Objects.equals(priorityAdjustment, that.priorityAdjustment) &&
|
||||
Objects.equals(username, that.username) &&
|
||||
Objects.equals(password, that.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(isHA, discoveryGroupName, staticConnectors, priorityAdjustment, circuitBreakerTimeout, username, password);
|
||||
}
|
||||
}
|
|
@ -57,8 +57,11 @@ import org.apache.activemq.artemis.core.config.ScaleDownConfiguration;
|
|||
import org.apache.activemq.artemis.core.config.TransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.WildcardConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationAddressPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicySet;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationQueuePolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationStreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.ColocatedPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
|
||||
|
@ -2002,12 +2005,18 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
|
||||
if (child.getNodeName().equals("upstream")) {
|
||||
config.addUpstreamConfiguration(getUpstream((Element) child, mainConfig));
|
||||
} else if (child.getNodeName().equals("downstream")) {
|
||||
config.addDownstreamConfiguration(getDownstream((Element) child, mainConfig));
|
||||
} else if (child.getNodeName().equals("policy-set")) {
|
||||
config.addFederationPolicy(getPolicySet((Element)child, mainConfig));
|
||||
} else if (child.getNodeName().equals("queue-policy")) {
|
||||
config.addFederationPolicy(getQueuePolicy((Element)child, mainConfig));
|
||||
} else if (child.getNodeName().equals("address-policy")) {
|
||||
config.addFederationPolicy(getAddressPolicy((Element)child, mainConfig));
|
||||
} else if (child.getNodeName().equals("transformer")) {
|
||||
TransformerConfiguration transformerConfiguration = getTransformerConfiguration(child);
|
||||
config.addTransformerConfiguration(new FederationTransformerConfiguration(
|
||||
((Element)child).getAttribute("name"), transformerConfiguration));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2128,9 +2137,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
return config;
|
||||
}
|
||||
|
||||
private FederationUpstreamConfiguration getUpstream(Element upstreamNode, final Configuration mainConfig) throws Exception {
|
||||
|
||||
FederationUpstreamConfiguration config = new FederationUpstreamConfiguration();
|
||||
private <T extends FederationStreamConfiguration> T getFederationStream(final T config, final Element upstreamNode,
|
||||
final Configuration mainConfig) throws Exception {
|
||||
|
||||
String name = upstreamNode.getAttribute("name");
|
||||
config.setName(name);
|
||||
|
@ -2158,6 +2166,16 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
|
||||
long circuitBreakerTimeout = getLong(upstreamNode, "circuit-breaker-timeout", config.getConnectionConfiguration().getCircuitBreakerTimeout(), Validators.MINUS_ONE_OR_GE_ZERO);
|
||||
|
||||
long clientFailureCheckPeriod = getLong(upstreamNode, "check-period", ActiveMQDefaultConfiguration.getDefaultFederationFailureCheckPeriod(), Validators.GT_ZERO);
|
||||
long connectionTTL = getLong(upstreamNode, "connection-ttl", ActiveMQDefaultConfiguration.getDefaultFederationConnectionTtl(), Validators.GT_ZERO);
|
||||
long retryInterval = getLong(upstreamNode, "retry-interval", ActiveMQDefaultConfiguration.getDefaultFederationRetryInterval(), Validators.GT_ZERO);
|
||||
long callTimeout = getLong(upstreamNode, "call-timeout", ActiveMQClient.DEFAULT_CALL_TIMEOUT, Validators.GT_ZERO);
|
||||
long callFailoverTimeout = getLong(upstreamNode, "call-failover-timeout", ActiveMQClient.DEFAULT_CALL_FAILOVER_TIMEOUT, Validators.MINUS_ONE_OR_GT_ZERO);
|
||||
double retryIntervalMultiplier = getDouble(upstreamNode, "retry-interval-multiplier", ActiveMQDefaultConfiguration.getDefaultFederationRetryIntervalMultiplier(), Validators.GT_ZERO);
|
||||
long maxRetryInterval = getLong(upstreamNode, "max-retry-interval", ActiveMQDefaultConfiguration.getDefaultFederationMaxRetryInterval(), Validators.GT_ZERO);
|
||||
int initialConnectAttempts = getInteger(upstreamNode, "initial-connect-attempts", ActiveMQDefaultConfiguration.getDefaultFederationInitialConnectAttempts(), Validators.MINUS_ONE_OR_GE_ZERO);
|
||||
int reconnectAttempts = getInteger(upstreamNode, "reconnect-attempts", ActiveMQDefaultConfiguration.getDefaultFederationReconnectAttempts(), Validators.MINUS_ONE_OR_GE_ZERO);
|
||||
|
||||
List<String> staticConnectorNames = new ArrayList<>();
|
||||
|
||||
String discoveryGroupName = null;
|
||||
|
@ -2181,8 +2199,17 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
config.addPolicyRefs(policyRefs);
|
||||
|
||||
config.getConnectionConfiguration()
|
||||
.setCircuitBreakerTimeout(circuitBreakerTimeout)
|
||||
.setHA(ha);
|
||||
.setCircuitBreakerTimeout(circuitBreakerTimeout)
|
||||
.setHA(ha)
|
||||
.setClientFailureCheckPeriod(clientFailureCheckPeriod)
|
||||
.setConnectionTTL(connectionTTL)
|
||||
.setRetryInterval(retryInterval)
|
||||
.setRetryIntervalMultiplier(retryIntervalMultiplier)
|
||||
.setMaxRetryInterval(maxRetryInterval)
|
||||
.setInitialConnectAttempts(initialConnectAttempts)
|
||||
.setReconnectAttempts(reconnectAttempts)
|
||||
.setCallTimeout(callTimeout)
|
||||
.setCallFailoverTimeout(callFailoverTimeout);
|
||||
|
||||
if (!staticConnectorNames.isEmpty()) {
|
||||
config.getConnectionConfiguration().setStaticConnectors(staticConnectorNames);
|
||||
|
@ -2192,6 +2219,20 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
|||
return config;
|
||||
}
|
||||
|
||||
private FederationUpstreamConfiguration getUpstream(final Element upstreamNode, final Configuration mainConfig) throws Exception {
|
||||
return getFederationStream(new FederationUpstreamConfiguration(), upstreamNode, mainConfig);
|
||||
}
|
||||
|
||||
private FederationDownstreamConfiguration getDownstream(final Element downstreamNode, final Configuration mainConfig) throws Exception {
|
||||
final FederationDownstreamConfiguration downstreamConfiguration =
|
||||
getFederationStream(new FederationDownstreamConfiguration(), downstreamNode, mainConfig);
|
||||
|
||||
final String upstreamRef = getString(downstreamNode,"upstream-connector-ref", null, Validators.NOT_NULL_OR_EMPTY);
|
||||
downstreamConfiguration.setUpstreamConfigurationRef(upstreamRef);
|
||||
|
||||
return downstreamConfiguration;
|
||||
}
|
||||
|
||||
private void getStaticConnectors(List<String> staticConnectorNames, Node child) {
|
||||
NodeList children2 = ((Element) child).getElementsByTagName("connector-ref");
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.BackupRequ
|
|||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.BackupResponseMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ClusterConnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ClusterConnectReplyMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.FederationDownstreamConnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.NodeAnnounceMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.QuorumVoteMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.QuorumVoteReplyMessage;
|
||||
|
@ -59,6 +60,7 @@ import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.BAC
|
|||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.BACKUP_REQUEST_RESPONSE;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.CLUSTER_CONNECT;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.CLUSTER_CONNECT_REPLY;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.FEDERATION_DOWNSTREAM_CONNECT;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.NODE_ANNOUNCE;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.QUORUM_VOTE;
|
||||
import static org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl.QUORUM_VOTE_REPLY;
|
||||
|
@ -252,6 +254,10 @@ public class ServerPacketDecoder extends ClientPacketDecoder {
|
|||
packet = new ScaleDownAnnounceMessage();
|
||||
break;
|
||||
}
|
||||
case FEDERATION_DOWNSTREAM_CONNECT: {
|
||||
packet = new FederationDownstreamConnectMessage();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
packet = super.decode(packetType, connection);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.protocol.core.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -27,6 +28,7 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
import io.netty.channel.ChannelPipeline;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffers;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.BaseInterceptor;
|
||||
import org.apache.activemq.artemis.api.core.Interceptor;
|
||||
import org.apache.activemq.artemis.api.core.Pair;
|
||||
|
@ -37,6 +39,12 @@ import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
|||
import org.apache.activemq.artemis.api.core.client.ClusterTopologyListener;
|
||||
import org.apache.activemq.artemis.api.core.client.TopologyMember;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationConnectionConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicy;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.protocol.ServerPacketDecoder;
|
||||
import org.apache.activemq.artemis.core.protocol.core.Channel;
|
||||
import org.apache.activemq.artemis.core.protocol.core.ChannelHandler;
|
||||
|
@ -47,10 +55,12 @@ import org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.CHANNEL_I
|
|||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ClusterTopologyChangeMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ClusterTopologyChangeMessage_V2;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ClusterTopologyChangeMessage_V3;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.FederationDownstreamConnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.Ping;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SubscribeClusterTopologyUpdatesMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SubscribeClusterTopologyUpdatesMessageV2;
|
||||
import org.apache.activemq.artemis.core.remoting.CloseListener;
|
||||
import org.apache.activemq.artemis.core.remoting.FailureListener;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.ActiveMQFrameDecoder2;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyServerConnection;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
|
@ -111,12 +121,15 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConnectionEntry createConnectionEntry(final Acceptor acceptorUsed, final Connection connection) {
|
||||
public ConnectionEntry createConnectionEntry(final Acceptor acceptorUsed,
|
||||
final Connection connection) {
|
||||
final Configuration config = server.getConfiguration();
|
||||
|
||||
Executor connectionExecutor = server.getExecutorFactory().getExecutor();
|
||||
|
||||
final CoreRemotingConnection rc = new RemotingConnectionImpl(new ServerPacketDecoder(), connection, incomingInterceptors, outgoingInterceptors, server.getNodeID(), connectionExecutor);
|
||||
final CoreRemotingConnection rc = new RemotingConnectionImpl(new ServerPacketDecoder(),
|
||||
connection, incomingInterceptors, outgoingInterceptors, server.getNodeID(),
|
||||
connectionExecutor);
|
||||
|
||||
Channel channel1 = rc.getChannel(CHANNEL_ID.SESSION.id, -1);
|
||||
|
||||
|
@ -130,13 +143,19 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
ttl = config.getConnectionTTLOverride();
|
||||
}
|
||||
|
||||
final ConnectionEntry entry = new ConnectionEntry(rc, connectionExecutor, System.currentTimeMillis(), ttl);
|
||||
final ConnectionEntry entry = new ConnectionEntry(rc, connectionExecutor,
|
||||
System.currentTimeMillis(), ttl);
|
||||
|
||||
final Channel channel0 = rc.getChannel(ChannelImpl.CHANNEL_ID.PING.id, -1);
|
||||
|
||||
channel0.setHandler(new LocalChannelHandler(config, entry, channel0, acceptorUsed, rc));
|
||||
|
||||
server.getClusterManager().addClusterChannelHandler(rc.getChannel(CHANNEL_ID.CLUSTER.id, -1), acceptorUsed, rc, server.getActivation());
|
||||
server.getClusterManager()
|
||||
.addClusterChannelHandler(rc.getChannel(CHANNEL_ID.CLUSTER.id, -1), acceptorUsed, rc,
|
||||
server.getActivation());
|
||||
|
||||
final Channel federationChannel = rc.getChannel(CHANNEL_ID.FEDERATION.id, -1);
|
||||
federationChannel.setHandler(new LocalChannelHandler(config, entry, channel0, acceptorUsed, rc));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
@ -249,18 +268,22 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
|
||||
// Just send a ping back
|
||||
channel0.send(packet);
|
||||
} else if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY || packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) {
|
||||
} else if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY
|
||||
|| packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) {
|
||||
SubscribeClusterTopologyUpdatesMessage msg = (SubscribeClusterTopologyUpdatesMessage) packet;
|
||||
|
||||
if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) {
|
||||
channel0.getConnection().setChannelVersion(((SubscribeClusterTopologyUpdatesMessageV2) msg).getClientVersion());
|
||||
channel0.getConnection().setChannelVersion(
|
||||
((SubscribeClusterTopologyUpdatesMessageV2) msg).getClientVersion());
|
||||
}
|
||||
|
||||
final ClusterTopologyListener listener = new ClusterTopologyListener() {
|
||||
@Override
|
||||
public void nodeUP(final TopologyMember topologyMember, final boolean last) {
|
||||
try {
|
||||
final Pair<TransportConfiguration, TransportConfiguration> connectorPair = BackwardsCompatibilityUtils.checkTCPPairConversion(channel0.getConnection().getChannelVersion(), topologyMember);
|
||||
final Pair<TransportConfiguration, TransportConfiguration> connectorPair = BackwardsCompatibilityUtils
|
||||
.checkTCPPairConversion(
|
||||
channel0.getConnection().getChannelVersion(), topologyMember);
|
||||
|
||||
final String nodeID = topologyMember.getNodeId();
|
||||
// Using an executor as most of the notifications on the Topology
|
||||
|
@ -270,11 +293,20 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
@Override
|
||||
public void run() {
|
||||
if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V3)) {
|
||||
channel0.send(new ClusterTopologyChangeMessage_V3(topologyMember.getUniqueEventID(), nodeID, topologyMember.getBackupGroupName(), topologyMember.getScaleDownGroupName(), connectorPair, last));
|
||||
channel0.send(new ClusterTopologyChangeMessage_V3(
|
||||
topologyMember.getUniqueEventID(), nodeID,
|
||||
topologyMember.getBackupGroupName(),
|
||||
topologyMember.getScaleDownGroupName(), connectorPair,
|
||||
last));
|
||||
} else if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
|
||||
channel0.send(new ClusterTopologyChangeMessage_V2(topologyMember.getUniqueEventID(), nodeID, topologyMember.getBackupGroupName(), connectorPair, last));
|
||||
channel0.send(new ClusterTopologyChangeMessage_V2(
|
||||
topologyMember.getUniqueEventID(), nodeID,
|
||||
topologyMember.getBackupGroupName(), connectorPair,
|
||||
last));
|
||||
} else {
|
||||
channel0.send(new ClusterTopologyChangeMessage(nodeID, connectorPair, last));
|
||||
channel0.send(
|
||||
new ClusterTopologyChangeMessage(nodeID, connectorPair,
|
||||
last));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -295,7 +327,9 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
@Override
|
||||
public void run() {
|
||||
if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
|
||||
channel0.send(new ClusterTopologyChangeMessage_V2(uniqueEventID, nodeID));
|
||||
channel0.send(
|
||||
new ClusterTopologyChangeMessage_V2(uniqueEventID,
|
||||
nodeID));
|
||||
} else {
|
||||
channel0.send(new ClusterTopologyChangeMessage(nodeID));
|
||||
}
|
||||
|
@ -309,7 +343,8 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Remote Proxy on channel " + Integer.toHexString(System.identityHashCode(this));
|
||||
return "Remote Proxy on channel " + Integer
|
||||
.toHexString(System.identityHashCode(this));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -319,7 +354,8 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
rc.addCloseListener(new CloseListener() {
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
acceptorUsed.getClusterConnection().removeClusterTopologyListener(listener);
|
||||
acceptorUsed.getClusterConnection()
|
||||
.removeClusterTopologyListener(listener);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -329,20 +365,120 @@ public class CoreProtocolManager implements ProtocolManager<Interceptor> {
|
|||
@Override
|
||||
public void run() {
|
||||
String nodeId = server.getNodeID().toString();
|
||||
Pair<TransportConfiguration, TransportConfiguration> emptyConfig = new Pair<>(null, null);
|
||||
Pair<TransportConfiguration, TransportConfiguration> emptyConfig = new Pair<>(
|
||||
null, null);
|
||||
if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
|
||||
channel0.send(new ClusterTopologyChangeMessage_V2(System.currentTimeMillis(), nodeId, null, emptyConfig, true));
|
||||
channel0.send(
|
||||
new ClusterTopologyChangeMessage_V2(System.currentTimeMillis(),
|
||||
nodeId, null, emptyConfig, true));
|
||||
} else {
|
||||
channel0.send(new ClusterTopologyChangeMessage(nodeId, emptyConfig, true));
|
||||
channel0.send(
|
||||
new ClusterTopologyChangeMessage(nodeId, emptyConfig, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (packet.getType() == PacketImpl.FEDERATION_DOWNSTREAM_CONNECT) {
|
||||
//If we receive this packet then a remote broker is requesting us to create federated upstream connection
|
||||
//back to it which simulates a downstream connection
|
||||
final FederationDownstreamConnectMessage message = (FederationDownstreamConnectMessage) packet;
|
||||
final FederationDownstreamConfiguration downstreamConfiguration = message.getStreamConfiguration();
|
||||
|
||||
//Create a new Upstream Federation configuration based on the received Downstream connection message
|
||||
//from the remote broker
|
||||
//The idea here is to set all the same configuration parameters that apply to the upstream connection
|
||||
final FederationConfiguration config = new FederationConfiguration();
|
||||
config.setName(message.getName() + FederationDownstreamConnectMessage.UPSTREAM_SUFFIX);
|
||||
config.setCredentials(message.getCredentials());
|
||||
|
||||
//Add the policy map configuration
|
||||
for (FederationPolicy policy : message.getFederationPolicyMap().values()) {
|
||||
config.addFederationPolicy(policy);
|
||||
}
|
||||
|
||||
//Add any transformer configurations
|
||||
for (FederationTransformerConfiguration transformerConfiguration : message.getTransformerConfigurationMap().values()) {
|
||||
config.addTransformerConfiguration(transformerConfiguration);
|
||||
}
|
||||
|
||||
//Create an upstream configuration with the same name but apply the upstream suffix so it is unique
|
||||
final FederationUpstreamConfiguration upstreamConfiguration = new FederationUpstreamConfiguration()
|
||||
.setName(downstreamConfiguration.getName() + FederationDownstreamConnectMessage.UPSTREAM_SUFFIX)
|
||||
.addPolicyRefs(downstreamConfiguration.getPolicyRefs());
|
||||
|
||||
//Use the provided Transport Configuration information to create an upstream connection back to the broker that
|
||||
//created the downstream connection
|
||||
final TransportConfiguration upstreamConfig = downstreamConfiguration.getUpstreamConfiguration();
|
||||
|
||||
//Initialize the upstream transport with the config from the acceptor as this will apply
|
||||
//relevant settings such as SSL, then override with settings from the downstream config
|
||||
final Map<String, Object> params = new HashMap<>(acceptorUsed.getConfiguration());
|
||||
params.putAll(upstreamConfig.getParams());
|
||||
|
||||
//Add the new upstream configuration that was created so we can connect back to the downstream server
|
||||
final TransportConfiguration upstreamConf = new TransportConfiguration(
|
||||
upstreamConfig.getFactoryClassName(), params, upstreamConfig.getName() + FederationDownstreamConnectMessage.UPSTREAM_SUFFIX,
|
||||
new HashMap<>());
|
||||
server.getConfiguration()
|
||||
.addConnectorConfiguration(upstreamConf.getName() + FederationDownstreamConnectMessage.UPSTREAM_SUFFIX, upstreamConf);
|
||||
|
||||
//Create a new upstream connection config based on the downstream configuration
|
||||
FederationConnectionConfiguration downstreamConConf = downstreamConfiguration.getConnectionConfiguration();
|
||||
FederationConnectionConfiguration upstreamConConf = upstreamConfiguration.getConnectionConfiguration();
|
||||
List<String> connectorNames = new ArrayList<>();
|
||||
connectorNames.add(upstreamConf.getName() + FederationDownstreamConnectMessage.UPSTREAM_SUFFIX);
|
||||
|
||||
//Configure all of the upstream connection parameters from the downstream connection that are relevant
|
||||
//Note that HA and discoveryGroupName are skipped because the downstream connection will manage that
|
||||
//In this case we just want to create a connection back to the broker that sent the downstream packet.
|
||||
//If this broker goes down then the original broker (if configured with HA) will re-establish a new
|
||||
//connection to another broker which will then create another upstream, etc
|
||||
upstreamConConf.setStaticConnectors(connectorNames);
|
||||
upstreamConConf.setUsername(downstreamConConf.getUsername());
|
||||
upstreamConConf.setPassword(downstreamConConf.getPassword());
|
||||
upstreamConConf.setShareConnection(downstreamConConf.isShareConnection());
|
||||
upstreamConConf.setPriorityAdjustment(downstreamConConf.getPriorityAdjustment());
|
||||
upstreamConConf.setClientFailureCheckPeriod(downstreamConConf.getClientFailureCheckPeriod());
|
||||
upstreamConConf.setConnectionTTL(downstreamConConf.getConnectionTTL());
|
||||
upstreamConConf.setRetryInterval(downstreamConConf.getRetryInterval());
|
||||
upstreamConConf.setRetryIntervalMultiplier(downstreamConConf.getRetryIntervalMultiplier());
|
||||
upstreamConConf.setMaxRetryInterval(downstreamConConf.getMaxRetryInterval());
|
||||
upstreamConConf.setInitialConnectAttempts(downstreamConConf.getInitialConnectAttempts());
|
||||
upstreamConConf.setReconnectAttempts(downstreamConConf.getReconnectAttempts());
|
||||
upstreamConConf.setCallTimeout(downstreamConConf.getCallTimeout());
|
||||
upstreamConConf.setCallFailoverTimeout(downstreamConConf.getCallFailoverTimeout());
|
||||
config.addUpstreamConfiguration(upstreamConfiguration);
|
||||
|
||||
//Register close and failure listeners, if the initial downstream connection goes down then we
|
||||
//want to terminate the upstream connection
|
||||
rc.addCloseListener(() -> {
|
||||
server.getFederationManager().undeploy(config.getName());
|
||||
});
|
||||
|
||||
rc.addFailureListener(new FailureListener() {
|
||||
@Override
|
||||
public void connectionFailed(ActiveMQException exception, boolean failedOver) {
|
||||
server.getFederationManager().undeploy(config.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionFailed(ActiveMQException exception, boolean failedOver,
|
||||
String scaleDownTargetNodeID) {
|
||||
server.getFederationManager().undeploy(config.getName());
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
server.getFederationManager().deploy(config);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error deploying federation: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<TransportConfiguration, TransportConfiguration> getPair(TransportConfiguration conn,
|
||||
boolean isBackup) {
|
||||
private Pair<TransportConfiguration, TransportConfiguration> getPair(
|
||||
TransportConfiguration conn,
|
||||
boolean isBackup) {
|
||||
if (isBackup) {
|
||||
return new Pair<>(null, conn);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.server;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
@ -25,14 +26,13 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.BridgeConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.DivertConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl;
|
||||
import org.apache.activemq.artemis.core.paging.PagingManager;
|
||||
import org.apache.activemq.artemis.core.persistence.OperationContext;
|
||||
|
@ -46,7 +46,7 @@ import org.apache.activemq.artemis.core.security.SecurityAuth;
|
|||
import org.apache.activemq.artemis.core.security.SecurityStore;
|
||||
import org.apache.activemq.artemis.core.server.cluster.ClusterManager;
|
||||
import org.apache.activemq.artemis.core.server.cluster.ha.HAPolicy;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.federation.FederationManager;
|
||||
import org.apache.activemq.artemis.core.server.group.GroupingHandler;
|
||||
import org.apache.activemq.artemis.core.server.impl.Activation;
|
||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||
|
@ -64,7 +64,6 @@ import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerCriticalPlug
|
|||
import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerMessagePlugin;
|
||||
import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerQueuePlugin;
|
||||
import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerSessionPlugin;
|
||||
import org.apache.activemq.artemis.core.server.federation.FederationManager;
|
||||
import org.apache.activemq.artemis.core.server.reload.ReloadManager;
|
||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
|
||||
|
@ -749,5 +748,4 @@ public interface ActiveMQServer extends ServiceComponent {
|
|||
void removeAddressInfo(SimpleString address, SecurityAuth auth, boolean force) throws Exception;
|
||||
|
||||
String getInternalNamingPrefix();
|
||||
|
||||
}
|
||||
|
|
|
@ -1638,7 +1638,19 @@ public interface ActiveMQServerLogger extends BasicLogger {
|
|||
void federationAvoidStackOverflowPolicyRef(String upstreamName, String policyRef);
|
||||
|
||||
@LogMessage(level = Logger.Level.WARN)
|
||||
@Message(id = 222282, value = "File {0} at {1} is empty. Delete the empty file to stop this message.",
|
||||
@Message(id = 222282, value = "Federation downstream {0} upstream transport configuration ref {1} could not be resolved in federation configuration", format = Message.Format.MESSAGE_FORMAT)
|
||||
void federationCantFindUpstreamConnector(String downstreamName, String upstreamRef);
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 222283, value = "Federation downstream {0} has been deployed", format = Message.Format.MESSAGE_FORMAT)
|
||||
void federationDownstreamDeployed(String downstreamName);
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 222284, value = "Federation downstream {0} has been undeployed", format = Message.Format.MESSAGE_FORMAT)
|
||||
void federationDownstreamUnDeployed(String downstreamName);
|
||||
|
||||
@LogMessage(level = Logger.Level.WARN)
|
||||
@Message(id = 222285, value = "File {0} at {1} is empty. Delete the empty file to stop this message.",
|
||||
format = Message.Format.MESSAGE_FORMAT)
|
||||
void emptyAddressFile(String addressFile, String directory);
|
||||
|
||||
|
|
|
@ -20,15 +20,16 @@ package org.apache.activemq.artemis.core.server.federation;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException;
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.MessageHandler;
|
||||
import org.apache.activemq.artemis.api.core.client.SessionFailureListener;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.transformer.Transformer;
|
||||
|
||||
|
@ -47,7 +48,7 @@ public class FederatedQueueConsumer implements MessageHandler, SessionFailureLis
|
|||
private final int intialConnectDelayMax = 30;
|
||||
private final ClientSessionCallback clientSessionCallback;
|
||||
|
||||
private ClientSessionFactory clientSessionFactory;
|
||||
private ClientSessionFactoryInternal clientSessionFactory;
|
||||
private ClientSession clientSession;
|
||||
private ClientConsumer clientConsumer;
|
||||
|
||||
|
@ -83,7 +84,7 @@ public class FederatedQueueConsumer implements MessageHandler, SessionFailureLis
|
|||
}, delay, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static int getNextDelay(int delay, int delayMultiplier, int delayMax) {
|
||||
public static int getNextDelay(int delay, int delayMultiplier, int delayMax) {
|
||||
int nextDelay;
|
||||
if (delay == 0) {
|
||||
nextDelay = 1;
|
||||
|
@ -100,7 +101,7 @@ public class FederatedQueueConsumer implements MessageHandler, SessionFailureLis
|
|||
try {
|
||||
if (clientConsumer == null) {
|
||||
synchronized (this) {
|
||||
this.clientSessionFactory = upstream.getConnection().clientSessionFactory();
|
||||
this.clientSessionFactory = (ClientSessionFactoryInternal) upstream.getConnection().clientSessionFactory();
|
||||
this.clientSession = clientSessionFactory.createSession(upstream.getUser(), upstream.getPassword(), false, true, true, clientSessionFactory.getServerLocator().isPreAcknowledge(), clientSessionFactory.getServerLocator().getAckBatchSize());
|
||||
this.clientSession.addFailureListener(this);
|
||||
this.clientSession.addMetaData(FEDERATION_NAME, federation.getName().toString());
|
||||
|
@ -149,13 +150,14 @@ public class FederatedQueueConsumer implements MessageHandler, SessionFailureLis
|
|||
if (clientSession != null) {
|
||||
clientSession.close();
|
||||
}
|
||||
if (clientSessionFactory != null) {
|
||||
clientSessionFactory.close();
|
||||
}
|
||||
clientConsumer = null;
|
||||
clientSession = null;
|
||||
clientSessionFactory = null;
|
||||
|
||||
if (clientSessionFactory != null && (!upstream.getConnection().isSharedConnection() ||
|
||||
clientSessionFactory.numSessions() == 0)) {
|
||||
clientSessionFactory.close();
|
||||
clientSessionFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,9 +20,11 @@ package org.apache.activemq.artemis.core.server.federation;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicy;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
|
@ -34,9 +36,12 @@ public class Federation {
|
|||
private final SimpleString name;
|
||||
|
||||
private final Map<String, FederationUpstream> upstreams = new HashMap<>();
|
||||
private final Map<String, FederationDownstream> downstreams = new HashMap<>();
|
||||
private final FederationConfiguration config;
|
||||
private FederationManager.State state;
|
||||
|
||||
private final Map<String, FederationConnection> connections = new HashMap<>();
|
||||
|
||||
enum State {
|
||||
STOPPED,
|
||||
STOPPING,
|
||||
|
@ -64,6 +69,9 @@ public class Federation {
|
|||
for (FederationUpstream connection : upstreams.values()) {
|
||||
connection.start();
|
||||
}
|
||||
for (FederationDownstream connection : downstreams.values()) {
|
||||
connection.start();
|
||||
}
|
||||
state = FederationManager.State.STARTED;
|
||||
}
|
||||
|
||||
|
@ -74,7 +82,11 @@ public class Federation {
|
|||
for (FederationUpstream connection : upstreams.values()) {
|
||||
connection.stop();
|
||||
}
|
||||
for (FederationDownstream connection : downstreams.values()) {
|
||||
connection.stop();
|
||||
}
|
||||
upstreams.clear();
|
||||
downstreams.clear();
|
||||
state = FederationManager.State.STOPPED;
|
||||
}
|
||||
|
||||
|
@ -82,6 +94,9 @@ public class Federation {
|
|||
for (FederationUpstreamConfiguration upstreamConfiguration : config.getUpstreamConfigurations()) {
|
||||
deploy(upstreamConfiguration, config.getFederationPolicyMap());
|
||||
}
|
||||
for (FederationDownstreamConfiguration downstreamConfiguration : config.getDownstreamConfigurations()) {
|
||||
deploy(downstreamConfiguration, config.getFederationPolicyMap());
|
||||
}
|
||||
if (state != FederationManager.State.STARTED) {
|
||||
state = FederationManager.State.DEPLOYED;
|
||||
}
|
||||
|
@ -96,11 +111,14 @@ public class Federation {
|
|||
if (federationConnection != null) {
|
||||
federationConnection.stop();
|
||||
}
|
||||
FederationDownstream federationConnectionDownstream = downstreams.remove(name);
|
||||
if (federationConnectionDownstream != null) {
|
||||
federationConnectionDownstream.undeploy();
|
||||
federationConnectionDownstream.stop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public synchronized boolean deploy(FederationUpstreamConfiguration upstreamConfiguration, Map<String, FederationPolicy> federationPolicyMap) throws ActiveMQException {
|
||||
String name = upstreamConfiguration.getName();
|
||||
FederationUpstream upstream = upstreams.get(name);
|
||||
|
@ -127,11 +145,52 @@ public class Federation {
|
|||
return upstream;
|
||||
}
|
||||
|
||||
public synchronized boolean deploy(FederationDownstreamConfiguration downstreamConfiguration, Map<String, FederationPolicy> federationPolicyMap) throws ActiveMQException {
|
||||
String name = downstreamConfiguration.getName();
|
||||
FederationDownstream downstream = downstreams.get(name);
|
||||
|
||||
//If connection has changed we will need to do a full undeploy and redeploy.
|
||||
if (downstream == null) {
|
||||
undeploy(name);
|
||||
downstream = deploy(name, downstreamConfiguration);
|
||||
} else if (!downstream.getConnection().getConfig().equals(downstreamConfiguration.getConnectionConfiguration())) {
|
||||
undeploy(name);
|
||||
downstream = deploy(name, downstreamConfiguration);
|
||||
}
|
||||
|
||||
downstream.deploy(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
private synchronized FederationDownstream deploy(String name, FederationDownstreamConfiguration downstreamConfiguration) {
|
||||
//If we have a matching upstream connection already configured then use it for the initiating downstream connection
|
||||
FederationConnection connection = null;
|
||||
if (downstreamConfiguration.getConnectionConfiguration().isShareConnection()) {
|
||||
for (FederationUpstream upstream : upstreams.values()) {
|
||||
if (upstream.getConfig().getConnectionConfiguration()
|
||||
.equals(downstreamConfiguration.getConnectionConfiguration())) {
|
||||
connection = upstream.getConnection();
|
||||
connection.setSharedConnection(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FederationDownstream downstream = new FederationDownstream(server, this, name, downstreamConfiguration, connection);
|
||||
downstreams.put(name, downstream);
|
||||
if (state == FederationManager.State.STARTED) {
|
||||
downstream.start();
|
||||
}
|
||||
return downstream;
|
||||
}
|
||||
|
||||
public FederationUpstream get(String name) {
|
||||
return upstreams.get(name);
|
||||
}
|
||||
|
||||
|
||||
public FederationDownstream getDownstream(String name) {
|
||||
return downstreams.get(name);
|
||||
}
|
||||
|
||||
public void register(FederatedAbstract federatedAbstract) {
|
||||
server.registerBrokerPlugin(federatedAbstract);
|
||||
|
|
|
@ -34,6 +34,7 @@ public class FederationConnection {
|
|||
private final long circuitBreakerTimeout;
|
||||
private volatile ClientSessionFactory clientSessionFactory;
|
||||
private volatile boolean started;
|
||||
private volatile boolean sharedConnection;
|
||||
|
||||
public FederationConnection(Configuration configuration, String name, FederationConnectionConfiguration config) {
|
||||
this.config = config;
|
||||
|
@ -67,6 +68,17 @@ public class FederationConnection {
|
|||
serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcConfigs);
|
||||
}
|
||||
}
|
||||
|
||||
serverLocator.setConnectionTTL(config.getConnectionTTL());
|
||||
serverLocator.setClientFailureCheckPeriod(config.getClientFailureCheckPeriod());
|
||||
serverLocator.setReconnectAttempts(config.getReconnectAttempts());
|
||||
serverLocator.setInitialConnectAttempts(config.getInitialConnectAttempts());
|
||||
serverLocator.setRetryInterval(config.getRetryInterval());
|
||||
serverLocator.setRetryIntervalMultiplier(config.getRetryIntervalMultiplier());
|
||||
serverLocator.setMaxRetryInterval(config.getMaxRetryInterval());
|
||||
serverLocator.setCallTimeout(config.getCallTimeout());
|
||||
serverLocator.setCallFailoverTimeout(config.getCallFailoverTimeout());
|
||||
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
|
@ -87,6 +99,14 @@ public class FederationConnection {
|
|||
return started;
|
||||
}
|
||||
|
||||
public boolean isSharedConnection() {
|
||||
return sharedConnection;
|
||||
}
|
||||
|
||||
public void setSharedConnection(boolean sharedConnection) {
|
||||
this.sharedConnection = sharedConnection;
|
||||
}
|
||||
|
||||
public final ClientSessionFactory clientSessionFactory() throws Exception {
|
||||
ClientSessionFactory clientSessionFactory = this.clientSessionFactory;
|
||||
if (started) {
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.server.federation;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.SessionFailureListener;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.protocol.core.Channel;
|
||||
import org.apache.activemq.artemis.core.protocol.core.CoreRemotingConnection;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.CHANNEL_ID;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.FederationDownstreamConnectMessage;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.FederationStreamConnectMessage;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class FederationDownstream extends FederationStream implements SessionFailureListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FederationDownstream.class);
|
||||
|
||||
private FederationDownstreamConfiguration config;
|
||||
private ClientSessionFactoryInternal clientSessionFactory;
|
||||
private ClientSessionInternal clientSession;
|
||||
private Channel channel;
|
||||
private AtomicBoolean initialized = new AtomicBoolean();
|
||||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
private final int intialConnectDelayMultiplier = 2;
|
||||
private final int intialConnectDelayMax = 30;
|
||||
|
||||
public static final String FEDERATION_DOWNSTREAM_NAME = "federation-downstream-name";
|
||||
private AtomicBoolean started = new AtomicBoolean();
|
||||
private FederationConfiguration federationConfiguration;
|
||||
|
||||
public FederationDownstream(ActiveMQServer server, Federation federation, String name, FederationDownstreamConfiguration config,
|
||||
final FederationConnection connection) {
|
||||
super(server, federation, name, config, connection);
|
||||
this.config = config;
|
||||
this.scheduledExecutorService = server.getScheduledPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
super.start();
|
||||
try {
|
||||
deploy(federationConfiguration);
|
||||
} catch (ActiveMQException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop() {
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public void deploy(FederationConfiguration federationConfiguration)
|
||||
throws ActiveMQException {
|
||||
|
||||
this.federationConfiguration = federationConfiguration;
|
||||
|
||||
if (connection.isStarted() && started.compareAndSet(false, true)) {
|
||||
final FederationStreamConnectMessage message = new FederationDownstreamConnectMessage();
|
||||
message.setName(federationConfiguration.getName());
|
||||
message.setCredentials(federationConfiguration.getCredentials());
|
||||
message.setStreamConfiguration(config);
|
||||
message.setFederationPolicyMap(federationConfiguration.getFederationPolicyMap());
|
||||
message.setTransformerConfigurationMap(federationConfiguration.getTransformerConfigurationMap());
|
||||
|
||||
if (config.getUpstreamConfigurationRef() != null
|
||||
&& config.getUpstreamConfiguration() == null) {
|
||||
TransportConfiguration[] configs = server.getConfiguration()
|
||||
.getTransportConfigurations(config.getUpstreamConfigurationRef());
|
||||
if (configs != null && configs.length > 0) {
|
||||
config.setUpstreamConfiguration(configs[0]);
|
||||
} else {
|
||||
ActiveMQServerLogger.LOGGER.federationCantFindUpstreamConnector(config.getName(), config
|
||||
.getUpstreamConfigurationRef());
|
||||
throw new ActiveMQException("Could not locate upstream transport configuration for federation downstream: " + config.getName()
|
||||
+ "; upstream ref: " + config.getUpstreamConfigurationRef());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
scheduleConnect(0, message);
|
||||
} catch (Exception e) {
|
||||
throw new ActiveMQException(e.getMessage(), e, ActiveMQExceptionType.GENERIC_EXCEPTION);
|
||||
}
|
||||
|
||||
ActiveMQServerLogger.LOGGER.federationDownstreamDeployed(config.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void undeploy() {
|
||||
try {
|
||||
if (started.compareAndSet(true, false)) {
|
||||
disconnect();
|
||||
ActiveMQServerLogger.LOGGER.federationDownstreamUnDeployed(config.getName());
|
||||
}
|
||||
} catch (ActiveMQException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleConnect(final int delay, final FederationStreamConnectMessage message) {
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
try {
|
||||
connect();
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
channel.send(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
scheduleConnect(FederatedQueueConsumer.getNextDelay(delay, intialConnectDelayMultiplier, intialConnectDelayMax),
|
||||
message);
|
||||
}
|
||||
}, delay, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void connect() throws Exception {
|
||||
try {
|
||||
if (clientSession == null) {
|
||||
synchronized (this) {
|
||||
this.clientSessionFactory = (ClientSessionFactoryInternal) getConnection().clientSessionFactory();
|
||||
this.clientSession = (ClientSessionInternal) clientSessionFactory.createSession(getUser(), getPassword(), false, true, true, clientSessionFactory.getServerLocator().isPreAcknowledge(), clientSessionFactory.getServerLocator().getAckBatchSize());
|
||||
this.clientSession.addFailureListener(this);
|
||||
this.clientSession.addMetaData(FederatedQueueConsumer.FEDERATION_NAME, federation.getName().toString());
|
||||
this.clientSession.addMetaData(FEDERATION_DOWNSTREAM_NAME, config.getName().toString());
|
||||
this.clientSession.start();
|
||||
|
||||
CoreRemotingConnection connection = (CoreRemotingConnection) clientSessionFactory.getConnection();
|
||||
channel = connection.getChannel(CHANNEL_ID.FEDERATION.id, -1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
if (clientSessionFactory != null) {
|
||||
clientSessionFactory.cleanup();
|
||||
}
|
||||
disconnect();
|
||||
} catch (ActiveMQException ignored) {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionFailed(ActiveMQException exception, boolean failedOver) {
|
||||
connectionFailed(exception, failedOver, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionFailed(ActiveMQException exception, boolean failedOver, String scaleDownTargetNodeID) {
|
||||
try {
|
||||
started.set(false);
|
||||
initialized.set(false);
|
||||
channel.close();
|
||||
clientSessionFactory.cleanup();
|
||||
clientSessionFactory.close();
|
||||
channel = null;
|
||||
clientSession = null;
|
||||
clientSessionFactory = null;
|
||||
} catch (Throwable dontCare) {
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
private void disconnect() throws ActiveMQException {
|
||||
initialized.set(false);
|
||||
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
if (clientSession != null) {
|
||||
clientSession.close();
|
||||
}
|
||||
channel = null;
|
||||
clientSession = null;
|
||||
|
||||
if (clientSessionFactory != null && (!getConnection().isSharedConnection() || clientSessionFactory.numSessions() == 0)) {
|
||||
clientSessionFactory.close();
|
||||
clientSessionFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeReconnect(ActiveMQException exception) {
|
||||
}
|
||||
|
||||
}
|
|
@ -122,8 +122,6 @@ public class FederationManager implements ActiveMQComponent {
|
|||
return federations.get(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void register(FederatedAbstract federatedAbstract) {
|
||||
server.registerBrokerPlugin(federatedAbstract);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.core.server.federation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationStreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.federation.address.FederatedAddress;
|
||||
import org.apache.activemq.artemis.core.server.federation.queue.FederatedQueue;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public abstract class FederationStream {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FederationStream.class);
|
||||
protected final ActiveMQServer server;
|
||||
protected final Federation federation;
|
||||
protected final SimpleString name;
|
||||
protected final FederationConnection connection;
|
||||
private FederationStreamConfiguration config;
|
||||
protected Map<String, FederatedQueue> federatedQueueMap = new HashMap<>();
|
||||
protected Map<String, FederatedAddress> federatedAddressMap = new HashMap<>();
|
||||
|
||||
|
||||
public FederationStream(ActiveMQServer server, Federation federation, String name, FederationStreamConfiguration config) {
|
||||
this(server, federation, name, config, null);
|
||||
}
|
||||
|
||||
public FederationStream(final ActiveMQServer server, final Federation federation, final String name, final FederationStreamConfiguration config,
|
||||
final FederationConnection connection) {
|
||||
this.server = server;
|
||||
this.federation = federation;
|
||||
Objects.requireNonNull(config.getName());
|
||||
this.name = SimpleString.toSimpleString(config.getName());
|
||||
this.config = config;
|
||||
this.connection = connection != null ? connection : new FederationConnection(server.getConfiguration(), name, config.getConnectionConfiguration());
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
if (connection != null) {
|
||||
connection.start();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (connection != null) {
|
||||
connection.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public Federation getFederation() {
|
||||
return federation;
|
||||
}
|
||||
|
||||
public FederationStreamConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public SimpleString getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public FederationConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
public String getUser() {
|
||||
String user = config.getConnectionConfiguration().getUsername();
|
||||
if (user == null || user.isEmpty()) {
|
||||
return federation.getFederationUser();
|
||||
} else {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
String password = config.getConnectionConfiguration().getPassword();
|
||||
if (password == null || password.isEmpty()) {
|
||||
return federation.getFederationPassword();
|
||||
} else {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPriorityAdjustment() {
|
||||
return config.getConnectionConfiguration().getPriorityAdjustment();
|
||||
}
|
||||
|
||||
}
|
|
@ -17,12 +17,10 @@
|
|||
|
||||
package org.apache.activemq.artemis.core.server.federation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationAddressPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicy;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationPolicySet;
|
||||
|
@ -33,28 +31,18 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
|||
import org.apache.activemq.artemis.core.server.federation.address.FederatedAddress;
|
||||
import org.apache.activemq.artemis.core.server.federation.queue.FederatedQueue;
|
||||
|
||||
public class FederationUpstream {
|
||||
|
||||
private final ActiveMQServer server;
|
||||
private final Federation federation;
|
||||
private final SimpleString name;
|
||||
private FederationConnection connection;
|
||||
public class FederationUpstream extends FederationStream {
|
||||
private FederationUpstreamConfiguration config;
|
||||
private Map<String, FederatedQueue> federatedQueueMap = new HashMap<>();
|
||||
private Map<String, FederatedAddress> federatedAddressMap = new HashMap<>();
|
||||
|
||||
public FederationUpstream(ActiveMQServer server, Federation federation, String name, FederationUpstreamConfiguration config) {
|
||||
this.server = server;
|
||||
this.federation = federation;
|
||||
Objects.requireNonNull(config.getName());
|
||||
this.name = SimpleString.toSimpleString(config.getName());
|
||||
super(server, federation, name, config);
|
||||
this.config = config;
|
||||
this.connection = new FederationConnection(server.getConfiguration(), name, config.getConnectionConfiguration());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
connection.start();
|
||||
super.start();
|
||||
|
||||
for (FederatedQueue federatedQueue : federatedQueueMap.values()) {
|
||||
federatedQueue.start();
|
||||
}
|
||||
|
@ -63,6 +51,7 @@ public class FederationUpstream {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop() {
|
||||
for (FederatedAddress federatedAddress : federatedAddressMap.values()) {
|
||||
federatedAddress.stop();
|
||||
|
@ -74,7 +63,7 @@ public class FederationUpstream {
|
|||
}
|
||||
federatedQueueMap.clear();
|
||||
|
||||
connection.stop();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public void deploy(Set<String> policyRefsToDeploy, Map<String, FederationPolicy> policyMap) throws ActiveMQException {
|
||||
|
@ -156,41 +145,8 @@ public class FederationUpstream {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FederationUpstreamConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
private Exception circuitBreakerException;
|
||||
private long lastCreateClientSessionFactoryExceptionTimestamp;
|
||||
|
||||
public SimpleString getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public FederationConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
public String getUser() {
|
||||
String user = config.getConnectionConfiguration().getUsername();
|
||||
if (user == null || user.isEmpty()) {
|
||||
return federation.getFederationUser();
|
||||
} else {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
String password = config.getConnectionConfiguration().getPassword();
|
||||
if (password == null || password.isEmpty()) {
|
||||
return federation.getFederationPassword();
|
||||
} else {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPriorityAdjustment() {
|
||||
return config.getConnectionConfiguration().getPriorityAdjustment();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Objects;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.QueueAttributes;
|
||||
|
@ -31,11 +32,11 @@ import org.apache.activemq.artemis.api.core.RoutingType;
|
|||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.core.config.WildcardConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationAddressPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.postoffice.QueueBinding;
|
||||
import org.apache.activemq.artemis.core.security.SecurityAuth;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationAddressPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.federation.FederatedAbstract;
|
||||
import org.apache.activemq.artemis.core.server.federation.FederatedConsumerKey;
|
||||
import org.apache.activemq.artemis.core.server.federation.Federation;
|
||||
|
@ -57,6 +58,7 @@ import org.apache.activemq.artemis.utils.ByteUtil;
|
|||
*/
|
||||
public class FederatedAddress extends FederatedAbstract implements ActiveMQServerQueuePlugin, Serializable {
|
||||
|
||||
public static final String FEDERATED_QUEUE_PREFIX = "federated";
|
||||
public static final SimpleString HDR_HOPS = new SimpleString("_AMQ_Hops");
|
||||
private final SimpleString queueNameFormat;
|
||||
private final SimpleString filterString;
|
||||
|
@ -74,7 +76,7 @@ public class FederatedAddress extends FederatedAbstract implements ActiveMQServe
|
|||
} else {
|
||||
this.filterString = HDR_HOPS.concat(" IS NULL OR ").concat(HDR_HOPS).concat("<").concat(Integer.toString(config.getMaxHops()));
|
||||
}
|
||||
this.queueNameFormat = SimpleString.toSimpleString("federated.${federation}.${upstream}.${address}.${routeType}");
|
||||
this.queueNameFormat = SimpleString.toSimpleString(FEDERATED_QUEUE_PREFIX + ".${federation}.${upstream}.${address}.${routeType}");
|
||||
if (config.getIncludes().isEmpty()) {
|
||||
includes = Collections.emptySet();
|
||||
} else {
|
||||
|
|
|
@ -69,6 +69,7 @@ public class ServiceRegistryImpl implements ServiceRegistry {
|
|||
this.connectorServices = new ConcurrentHashMap<>();
|
||||
this.divertTransformers = new ConcurrentHashMap<>();
|
||||
this.bridgeTransformers = new ConcurrentHashMap<>();
|
||||
this.federationTransformers = new ConcurrentHashMap<>();
|
||||
this.acceptorFactories = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
|
|
|
@ -1589,13 +1589,11 @@
|
|||
<xsd:attributeGroup ref="xml:specialAttrs"/>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FEDERATION CONFIGURATION -->
|
||||
<xsd:complexType name="federationType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="upstream" type="upstreamType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="downstream" type="downstreamType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="policy-set" type="policySetType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="queue-policy" type="queuePolicyType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="address-policy" type="addressPolicyType" minOccurs="0" maxOccurs="unbounded" />
|
||||
|
@ -1607,9 +1605,31 @@
|
|||
<xsd:attributeGroup ref="xml:specialAttrs"/>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<xsd:complexType name="downstreamType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="streamType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="upstream-connector-ref" type="xsd:string" maxOccurs="1" minOccurs="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Name of the transport connector reference to use for the new upstream connection
|
||||
back to this broker.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="xml:specialAttrs"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="upstreamType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="streamType"/>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="streamType">
|
||||
<xsd:sequence>
|
||||
|
||||
<xsd:element name="ha" type="xsd:boolean" default="false" maxOccurs="1" minOccurs="0">
|
||||
|
@ -1628,6 +1648,88 @@
|
|||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="share-connection" type="xsd:boolean" default="false" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
if there is a downstream and upstream connection configured for the same broker then
|
||||
the same connection will be shared as long as both stream configs set this flag to true
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="connection-ttl" type="xsd:long" default="60000" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
how long to keep a connection alive in the absence of any data arriving from the client
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="call-timeout" type="xsd:long" default="30000" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
How long to wait for a reply
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="retry-interval" type="xsd:long" default="500" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
period (in ms) between successive retries
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="retry-interval-multiplier" type="xsd:double" default="1" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
multiplier to apply to the retry-interval
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="max-retry-interval" type="xsd:long" default="2000" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Maximum value for retry-interval
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="initial-connect-attempts" type="xsd:int" default="-1" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
How many attempts should be made to connect initially
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="reconnect-attempts" type="xsd:int" default="-1" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
How many attempts should be made to reconnect after failure
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="check-period" type="xsd:long" default="30000" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The period (in milliseconds) used to check if the federation connection has failed to receive pings from
|
||||
another server
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="call-failover-timeout" type="xsd:long" default="-1" maxOccurs="1" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
How long to wait for a reply if in the middle of a fail-over. -1 means wait forever.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:choice>
|
||||
<xsd:element name="static-connectors" maxOccurs="1" minOccurs="1">
|
||||
<xsd:complexType>
|
||||
|
|
|
@ -278,6 +278,36 @@
|
|||
<property key="federationTransformerKey2" value="federationTransformerValue2"/>
|
||||
</transformer>
|
||||
</federation>
|
||||
|
||||
<federation name="federation4" user="globaluser" password="32a10275cf4ab4e9">
|
||||
<upstream name="asia-3">
|
||||
<static-connectors>
|
||||
<connector-ref>connector1</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="queue-federation-asia"/>
|
||||
<policy ref="address-federation-asia"/>
|
||||
</upstream>
|
||||
<downstream name="asia-4" >
|
||||
<ha>true</ha>
|
||||
<discovery-group-ref discovery-group-name="dg1"/>
|
||||
<policy ref="queue-federation-asia"/>
|
||||
<policy ref="address-federation-asia"/>
|
||||
<upstream-connector-ref>connector1</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<queue-policy name="queue-federation-asia2" transformer-ref="federation-transformer-4" >
|
||||
<exclude queue-match="the_queue" address-match="#" />
|
||||
</queue-policy>
|
||||
<address-policy name="address-federation-asia2" transformer-ref="federation-transformer-4" >
|
||||
<include address-match="the_address" />
|
||||
</address-policy>
|
||||
|
||||
<transformer name="federation-transformer-4">
|
||||
<class-name>org.foo.FederationTransformer4</class-name>
|
||||
<property key="federationTransformerKey1" value="federationTransformerValue1"/>
|
||||
<property key="federationTransformerKey2" value="federationTransformerValue2"/>
|
||||
</transformer>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
<metrics-plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.SimpleMetricsPlugin">
|
||||
|
|
|
@ -6,12 +6,11 @@ Address federation is like full multicast over the connected brokers, in that ev
|
|||
on `Broker-A` will be delivered to every queue on that broker, but like wise will be delivered to `Broker-B`
|
||||
and all attached queues there.
|
||||
|
||||
|
||||
Address federation dynamically links to other addresses in upstream brokers. It automatically creates a queue on the remote address for itself,
|
||||
Address federation dynamically links to other addresses in upstream or downstream brokers. It automatically creates a queue on the remote address for itself,
|
||||
to which then it consumes, copying to the local address, as though they were published directly to it.
|
||||
|
||||
The upstream brokers do not need to be reconfigured or the address, simply permissions to the address need to be
|
||||
given to the address for the downstream broker.
|
||||
given to the address for the downstream broker. Similarly the same applies for downstream configurations.
|
||||
|
||||
|
||||
![Address Federation](images/federation-address.png)
|
||||
|
@ -182,14 +181,125 @@ Finally look at `upstream`, this is what defines the upstream broker connection
|
|||
information about what discovery-groups are and how to configure them, please
|
||||
see [Discovery Groups](clusters.md).
|
||||
|
||||
|
||||
- `ha`. This optional parameter determines whether or not this bridge should
|
||||
support high availability. True means it will connect to any available server
|
||||
in a cluster and support failover. The default value is `false`.
|
||||
|
||||
- `circuit-breaker-timeout` in milliseconds, When a connection issue occurs,
|
||||
as the single connection is shared by many federated queue and address consumers,
|
||||
to avoid each one trying to reconnect and possibly causing a thrundering heard issue,
|
||||
to avoid each one trying to reconnect and possibly causing a thundering heard issue,
|
||||
the first one will try, if unsuccessful the circuit breaker will open,
|
||||
returning the same exception to all, this is the timeout until the circuit can be closed and connection retried.
|
||||
|
||||
- `share-connection`. If there is a downstream and upstream connection configured for the same broker then
|
||||
the same connection will be shared as long as both stream configs set this flag to true.
|
||||
Default is false.
|
||||
|
||||
- `check-period`. The period (in milliseconds) used to check if the
|
||||
federation connection has failed to receive pings from another server.
|
||||
Default is 30000.
|
||||
|
||||
- `connection-ttl`. This is how long a federation connection should stay
|
||||
alive if it stops receiving messages from the remote broker. Default is 60000.
|
||||
|
||||
- `call-timeout`. When a packet is sent via a federation connection and
|
||||
is a blocking call, i.e. for acknowledgements, this is how long it
|
||||
will wait (in milliseconds) for the reply before throwing an
|
||||
exception. Default is 30000.
|
||||
|
||||
- `call-failover-timeout`. Similar to `call-timeout` but used when a
|
||||
call is made during a failover attempt. Default is -1 (no timeout).
|
||||
|
||||
- `retry-interval`. This optional parameter determines the period in
|
||||
milliseconds between subsequent reconnection attempts, if the connection to
|
||||
the target server has failed. The default value is `500` milliseconds.
|
||||
|
||||
- `retry-interval-multiplier`. This is a multiplier used to increase
|
||||
the `retry-interval` after each reconnect attempt, default is 1.
|
||||
|
||||
- `max-retry-interval`. The maximum delay (in milliseconds) for
|
||||
retries. Default is 2000.
|
||||
|
||||
- `initial-connect-attempts`. The number of times the system will try
|
||||
to connect to the remote broker in the federation. If the max-retry is
|
||||
achieved this broker will be considered permanently down and the
|
||||
system will not route messages to this broker. Default is -1 (infinite
|
||||
retries).
|
||||
|
||||
- `reconnect-attempts`. The number of times the system will try to
|
||||
reconnect to the remote broker in the federation. If the max-retry is achieved
|
||||
this broker will be considered permanently down and the system will
|
||||
stop routing messages to this broker. Default is -1 (infinite
|
||||
retries).
|
||||
|
||||
## Configuring Downstream Federation
|
||||
|
||||
Similarly to `upstream` configuration, a downstream configuration can be configured. This works by sending a command
|
||||
to the `downstream` broker to have it create an `upstream` connection back to the downstream broker. The benefit of
|
||||
this is being able to configure everything for federation on one broker in some cases to make it easier, such
|
||||
as a hub and spoke topology
|
||||
|
||||
All of the same configuration options apply to to `downstream` as does `upstream` with the exception of one
|
||||
extra configuration flag that needs to be set:
|
||||
|
||||
The `transport-connector-ref` is an element pointing to a
|
||||
`connector` elements defined elsewhere. This ref is used to tell the downstream broker
|
||||
what connector to use to create a new upstream connection back to the downstream broker.
|
||||
|
||||
A *connector* encapsulates knowledge of what transport to use (TCP, SSL, HTTP etc) as well as
|
||||
the server connection parameters (host, port etc). For more information about what connectors are and
|
||||
how to configure them, please see [Configuring the
|
||||
Transport](configuring-transports.md).
|
||||
|
||||
Sample Downstream Address Federation setup:
|
||||
|
||||
```xml
|
||||
|
||||
<!--Other config Here -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
</connectors>
|
||||
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!--Other config Here -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
|
||||
<downstream name="eu-east-1">
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-connector1</connector-ref>
|
||||
</static-connectors>
|
||||
<transport-connector-ref>netty-connector</transport-connector-ref>
|
||||
<policy ref="news-address-federation"/>
|
||||
</downstream>
|
||||
<downstream name="eu-west-1" >
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-connector1</connector-ref>
|
||||
</static-connectors>
|
||||
<transport-connector-ref>netty-connector</transport-connector-ref>
|
||||
<policy ref="news-address-federation"/>
|
||||
</downstream>
|
||||
|
||||
<address-policy name="news-address-federation" max-hops="1" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" transformer-ref="federation-transformer-3">
|
||||
<include address-match="queue.bbc.new" />
|
||||
<include address-match="queue.usatoday" />
|
||||
<include address-match="queue.news.#" />
|
||||
|
||||
<exclude address-match="queue.news.sport.#" />
|
||||
</address-policy>
|
||||
|
||||
<transformer name="news-transformer">
|
||||
<class-name>org.foo.NewsTransformer</class-name>
|
||||
<property key="key1" value="value1"/>
|
||||
<property key="key2" value="value2"/>
|
||||
</transformer>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
```
|
|
@ -162,7 +162,6 @@ Finally look at `upstream`, this is what defines the upstream broker connection
|
|||
information about what discovery-groups are and how to configure them, please
|
||||
see [Discovery Groups](clusters.md).
|
||||
|
||||
|
||||
- `ha`. This optional parameter determines whether or not this bridge should
|
||||
support high availability. True means it will connect to any available server
|
||||
in a cluster and support failover. The default value is `false`.
|
||||
|
@ -173,3 +172,116 @@ to avoid each one trying to reconnect and possibly causing a thrundering heard i
|
|||
the first one will try, if unsuccessful the circuit breaker will open,
|
||||
returning the same exception to all, this is the timeout until the circuit can be closed and connection retried.
|
||||
|
||||
- `share-connection`. If there is a downstream and upstream connection configured for the same broker then
|
||||
the same connection will be shared as long as both stream configs set this flag to true.
|
||||
Default is false.
|
||||
|
||||
- `check-period`. The period (in milliseconds) used to check if the
|
||||
federation connection has failed to receive pings from another server.
|
||||
Default is 30000.
|
||||
|
||||
- `connection-ttl`. This is how long a federation connection should stay
|
||||
alive if it stops receiving messages from the remote broker. Default is 60000.
|
||||
|
||||
- `call-timeout`. When a packet is sent via a federation connection and
|
||||
is a blocking call, i.e. for acknowledgements, this is how long it
|
||||
will wait (in milliseconds) for the reply before throwing an
|
||||
exception. Default is 30000.
|
||||
|
||||
- `call-failover-timeout`. Similar to `call-timeout` but used when a
|
||||
call is made during a failover attempt. Default is -1 (no timeout).
|
||||
|
||||
- `retry-interval`. This optional parameter determines the period in
|
||||
milliseconds between subsequent reconnection attempts, if the connection to
|
||||
the target server has failed. The default value is `500` milliseconds.
|
||||
|
||||
- `retry-interval-multiplier`. This is a multiplier used to increase
|
||||
the `retry-interval` after each reconnect attempt, default is 1.
|
||||
|
||||
- `max-retry-interval`. The maximum delay (in milliseconds) for
|
||||
retries. Default is 2000.
|
||||
|
||||
- `initial-connect-attempts`. The number of times the system will try
|
||||
to connect to the remote broker in the federation. If the max-retry is
|
||||
achieved this broker will be considered permanently down and the
|
||||
system will not route messages to this broker. Default is -1 (infinite
|
||||
retries).
|
||||
|
||||
- `reconnect-attempts`. The number of times the system will try to
|
||||
reconnect to the remote broker in the federation. If the max-retry is achieved
|
||||
this broker will be considered permanently down and the system will
|
||||
stop routing messages to this broker. Default is -1 (infinite
|
||||
retries).
|
||||
|
||||
## Configuring Downstream Federation
|
||||
|
||||
Similarly to `upstream` configuration, a downstream configuration can be configured. This works by sending a command
|
||||
to the `downstream` broker to have it create an `upstream` connection back to the downstream broker. The benefit of
|
||||
this is being able to configure everything for federation on one broker in some cases to make it easier, such
|
||||
as a hub and spoke topology.
|
||||
|
||||
All of the same configuration options apply to to `downstream` as does `upstream` with the exception of one
|
||||
extra configuration flag that needs to be set:
|
||||
|
||||
The `transport-connector-ref` is an element pointing to a
|
||||
`connector` elements defined elsewhere. This ref is used to tell the downstream broker
|
||||
what connector to use to create a new upstream connection back to the downstream broker.
|
||||
|
||||
A *connector* encapsulates knowledge of what transport to use (TCP, SSL, HTTP etc) as well as
|
||||
the server connection parameters (host, port etc). For more information about what connectors are and
|
||||
how to configure them, please see [Configuring the
|
||||
Transport](configuring-transports.md).
|
||||
|
||||
|
||||
Sample Downstream Address Federation setup:
|
||||
|
||||
```xml
|
||||
|
||||
<!--Other config Here -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
</connectors>
|
||||
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!--Other config Here -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
|
||||
<downstream name="eu-east-1">
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-connector1</connector-ref>
|
||||
</static-connectors>
|
||||
<transport-connector-ref>netty-connector</transport-connector-ref>
|
||||
<policy ref="news-address-federation"/>
|
||||
</downstream>
|
||||
<downstream name="eu-west-1" >
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-connector1</connector-ref>
|
||||
</static-connectors>
|
||||
<transport-connector-ref>netty-connector</transport-connector-ref>
|
||||
<policy ref="news-address-federation"/>
|
||||
</downstream>
|
||||
|
||||
<queue-policy name="news-queue-federation" priority-adjustment="-5" include-federated="true" transformer-ref="federation-transformer-3">
|
||||
<include queue-match="#" address-match="queue.bbc.new" />
|
||||
<include queue-match="#" address-match="queue.usatoday" />
|
||||
<include queue-match="#" address-match="queue.news.#" />
|
||||
|
||||
<exclude queue-match="#.local" address-match="#" />
|
||||
</queue-policy>
|
||||
|
||||
<transformer name="news-transformer">
|
||||
<class-name>org.foo.NewsTransformer</class-name>
|
||||
<property key="key1" value="value1"/>
|
||||
<property key="key2" value="value2"/>
|
||||
</transformer>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
|
@ -0,0 +1,215 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>broker-federation</artifactId>
|
||||
<version>2.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>federated-address-downstream-upstream</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ActiveMQ Artemis Downstream/Upstream Federated Address Example</name>
|
||||
|
||||
<properties>
|
||||
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-address</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create0</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server0</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server0</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create1</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server1</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server1</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create2</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server2</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server2</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<testURI>tcp://localhost:61616</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-west-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<testURI>tcp://localhost:61617</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-east-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<testURI>tcp://localhost:61618</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>us-central-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>runClient</id>
|
||||
<goals>
|
||||
<goal>runClient</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<clientClass>org.apache.activemq.artemis.jms.example.FederatedAddressDownstreamUpstreamExample</clientClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-address-downstream-upstream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.vladsch.flexmark</groupId>
|
||||
<artifactId>markdown-page-generator-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,34 @@
|
|||
# Federated Address Example
|
||||
|
||||
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the broker manually.
|
||||
|
||||
This example demonstrates a core multicast address deployed on three different brokers. The three brokers are configured to form a federated address mesh.
|
||||
|
||||
In the example we name the brokers, eu-west, eu-east and us-central to give an idea of the use case.
|
||||
|
||||
![EU West, EU East and US Central Diagram](eu-west-east-us-central.png)
|
||||
|
||||
The following is then carried out:
|
||||
|
||||
1. create a consumer on the queue on each node, and we create a producer on only one of the nodes.
|
||||
|
||||
2. send some messages via the producer on EU West, and we verify that **all** the consumers receive the sent messages, in essence multicasting the messages within and accross brokers.
|
||||
|
||||
3. Next then verify the same on US Central.
|
||||
|
||||
4. Next then verify the same on EU East.
|
||||
|
||||
|
||||
|
||||
In other words, we are showing how with Federated Address, ActiveMQ Artemis **replicates** sent messages to all addresses and subsequently delivered to all all consumers, regardless if the consumer is local or is on a distant broker. Decoupling the location where producers and consumers need to be.
|
||||
|
||||
The config that defines the federation you can see in the broker.xml for each broker is within the following tags. You will note upstreams are different in each as well as the federation name, which has to be globally unique.
|
||||
|
||||
```
|
||||
<federations>
|
||||
...
|
||||
</federations>
|
||||
```
|
||||
|
||||
|
||||
For more information on ActiveMQ Artemis Federation please see the federation section of the user manual.
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.jms.example;
|
||||
|
||||
/**
|
||||
* A simple example that demonstrates multicast address replication between remote servers,
|
||||
* using Address Federation downstream and upstream feature combined.
|
||||
*/
|
||||
public class FederatedAddressDownstreamUpstreamExample {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
//Re-use the same Federated address test for upstream
|
||||
FederatedAddressExample.main(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-west-1-master</name>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
<!-- Connectors -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-west-1-federation">
|
||||
<upstream name="eu-east-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<upstream name="us-central-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<downstream name="eu-east-1-downstream" >
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="address-federation" />
|
||||
</policy-set>
|
||||
|
||||
<address-policy name="address-federation">
|
||||
<include address-match="exampleTopic" />
|
||||
</address-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-east-1-master</name>
|
||||
|
||||
<bindings-directory>target/server1/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server1/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server1/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server1/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61617</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61617</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-east-1-federation">
|
||||
<upstream name="us-central-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<downstream name="us-central-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="address-federation" />
|
||||
</policy-set>
|
||||
|
||||
<address-policy name="address-federation" >
|
||||
<include address-match="exampleTopic" />
|
||||
</address-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>us-central-1-master</name>
|
||||
|
||||
<bindings-directory>target/server2/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server2/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server2/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server2/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61618</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<!--No federation configuration necessary as the other brokers will be creating downstreams/upstreams
|
||||
to this broker-->
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
|
@ -0,0 +1,215 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>broker-federation</artifactId>
|
||||
<version>2.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>federated-address-downstream</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ActiveMQ Artemis Downstream Federated Address Example</name>
|
||||
|
||||
<properties>
|
||||
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-address</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create0</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server0</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server0</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create1</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server1</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server1</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create2</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server2</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server2</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<testURI>tcp://localhost:61616</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-west-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<testURI>tcp://localhost:61617</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-east-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<testURI>tcp://localhost:61618</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>us-central-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>runClient</id>
|
||||
<goals>
|
||||
<goal>runClient</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<clientClass>org.apache.activemq.artemis.jms.example.FederatedAddressDownstreamExample</clientClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-address-downstream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.vladsch.flexmark</groupId>
|
||||
<artifactId>markdown-page-generator-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,34 @@
|
|||
# Federated Address Example
|
||||
|
||||
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the broker manually.
|
||||
|
||||
This example demonstrates a core multicast address deployed on three different brokers. The three brokers are configured to form a federated address mesh.
|
||||
|
||||
In the example we name the brokers, eu-west, eu-east and us-central to give an idea of the use case.
|
||||
|
||||
![EU West, EU East and US Central Diagram](eu-west-east-us-central.png)
|
||||
|
||||
The following is then carried out:
|
||||
|
||||
1. create a consumer on the queue on each node, and we create a producer on only one of the nodes.
|
||||
|
||||
2. send some messages via the producer on EU West, and we verify that **all** the consumers receive the sent messages, in essence multicasting the messages within and accross brokers.
|
||||
|
||||
3. Next then verify the same on US Central.
|
||||
|
||||
4. Next then verify the same on EU East.
|
||||
|
||||
|
||||
|
||||
In other words, we are showing how with Federated Address, ActiveMQ Artemis **replicates** sent messages to all addresses and subsequently delivered to all all consumers, regardless if the consumer is local or is on a distant broker. Decoupling the location where producers and consumers need to be.
|
||||
|
||||
The config that defines the federation you can see in the broker.xml for each broker is within the following tags. You will note upstreams are different in each as well as the federation name, which has to be globally unique.
|
||||
|
||||
```
|
||||
<federations>
|
||||
...
|
||||
</federations>
|
||||
```
|
||||
|
||||
|
||||
For more information on ActiveMQ Artemis Federation please see the federation section of the user manual.
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.jms.example;
|
||||
|
||||
/**
|
||||
* A simple example that demonstrates multicast address replication between remote servers,
|
||||
* using Address Federation downstream feature.
|
||||
*/
|
||||
public class FederatedAddressDownstreamExample {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
//Re-use the same Federated address test for upstream
|
||||
FederatedAddressExample.main(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-west-1-master</name>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
<!-- Connectors -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-west-1-federation">
|
||||
<downstream name="eu-east-1-downstream" >
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="address-federation" />
|
||||
</policy-set>
|
||||
|
||||
<address-policy name="address-federation">
|
||||
<include address-match="exampleTopic" />
|
||||
</address-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-east-1-master</name>
|
||||
|
||||
<bindings-directory>target/server1/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server1/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server1/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server1/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61617</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61617</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-east-1-federation">
|
||||
<downstream name="eu-west-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="address-federation" />
|
||||
</policy-set>
|
||||
|
||||
<address-policy name="address-federation" >
|
||||
<include address-match="exampleTopic" />
|
||||
</address-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>us-central-1-master</name>
|
||||
|
||||
<bindings-directory>target/server2/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server2/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server2/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server2/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61618</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61618</acceptor>
|
||||
</acceptors>
|
||||
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="us-central-1-federation">
|
||||
<downstream name="eu-east-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="eu-west-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="address-federation" />
|
||||
</policy-set>
|
||||
|
||||
<address-policy name="address-federation">
|
||||
<include address-match="exampleTopic" />
|
||||
</address-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleTopic">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleTopic">
|
||||
<multicast>
|
||||
<queue name="exampleSubscription"/>
|
||||
</multicast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
|
@ -0,0 +1,215 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>broker-federation</artifactId>
|
||||
<version>2.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>federated-queue-downstream-upstream</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ActiveMQ Artemis Downstream/Upstream Federated Queue Example</name>
|
||||
|
||||
<properties>
|
||||
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-queue</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create0</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server0</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server0</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create1</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server1</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server1</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create2</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server2</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server2</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<testURI>tcp://localhost:61616</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-west-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<testURI>tcp://localhost:61617</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-east-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<testURI>tcp://localhost:61618</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>us-central-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>runClient</id>
|
||||
<goals>
|
||||
<goal>runClient</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<clientClass>org.apache.activemq.artemis.jms.example.FederatedQueueDownstreamUpstreamExample</clientClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-queue-downstream-upstream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.vladsch.flexmark</groupId>
|
||||
<artifactId>markdown-page-generator-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,51 @@
|
|||
# Federated Queue Example
|
||||
|
||||
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the broker manually.
|
||||
|
||||
This example demonstrates a core queue deployed on three different brokers. The three brokers are configured to form a federated queue mesh.
|
||||
|
||||
In the example we name the brokers, eu-west, eu-east and us-central to give an idea of the use case.
|
||||
|
||||
![EU West, EU East and US Central Diagram](eu-west-east-us-central.png)
|
||||
|
||||
The following is then carried out:
|
||||
|
||||
1. create a consumer on the queue on each node, and we create a producer on only one of the nodes.
|
||||
|
||||
2. send some messages via the producer on EU West, and we verify that **only the local** consumer receives the sent messages.
|
||||
|
||||
3. Next then verify the same on US Central.
|
||||
|
||||
4. Now the consumer on EU West is closed leaving it no local consumers.
|
||||
|
||||
5. Send some more messages to server EU West
|
||||
|
||||
6. We now consume those messages on EU East demonstrating that messages will **re-route** to the another broker based on upstream priority. You will note, US Central is configured to be -1 priority compared to EU East,
|
||||
there for messages should re-route to EU East as it will have a slightly higher priority for its consumers to consume.
|
||||
If US Central and EU East were even priority then the re-direct would be loaded between the two.
|
||||
|
||||
7. Next the consumer on US Central is closed leaving it no local consumers. And we send some more messages to US Cental
|
||||
|
||||
8. Again we consume on EU East demonstrating that US Central messages also can **re-route**, if no local-consumer.
|
||||
|
||||
9. Now we restart EU West and US Centrals consumers.
|
||||
|
||||
10. We produce and consume on US Central, showing that dynamically re-adjusts now local consumers exist and messages delivery by priority to local consumer.
|
||||
|
||||
11. And repeat the same on EU West.
|
||||
|
||||
|
||||
In other words, we are showing how with Federated Queues, ActiveMQ Artemis **routes** sent messages to local consumers as priority, but is able to re-route the sent messages to other distant brokers if consumers are attached to those brokers. Decoupling the location where producers and consumers need to be.
|
||||
|
||||
Here's the relevant snippet from the broker configuration, which tells the broker to form a cluster between the two nodes and to load balance the messages between the nodes.
|
||||
|
||||
The config that defines the federation you can see in the broker.xml for each broker is within the following tags. You will note upstreams are different in each as well as the federation name, which has to be globally unique.
|
||||
|
||||
```
|
||||
<federations>
|
||||
...
|
||||
</federations>
|
||||
```
|
||||
|
||||
|
||||
For more information on ActiveMQ Artemis Federation please see the federation section of the user manual.
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.jms.example;
|
||||
|
||||
/**
|
||||
* A simple example that demonstrates dynamic queue messaging routing between remote servers,
|
||||
* as consumers come and go, routing based on priorities.
|
||||
* using Queue Federation feature.
|
||||
*/
|
||||
public class FederatedQueueDownstreamUpstreamExample {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
FederatedQueueExample.main(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-west-1-master</name>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
<!-- Connectors -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-west-1-federation">
|
||||
<upstream name="eu-east-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<upstream name="us-central-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<downstream name="eu-east-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="queue-federation" />
|
||||
</policy-set>
|
||||
|
||||
<queue-policy name="queue-federation" >
|
||||
<include queue-match="exampleQueue" address-match="#" />
|
||||
</queue-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-east-1-master</name>
|
||||
|
||||
<bindings-directory>target/server1/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server1/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server1/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server1/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61617</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61617</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-east-1-federation">
|
||||
<upstream name="us-central-1-upstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
</upstream>
|
||||
<downstream name="us-central-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<share-connection>true</share-connection>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="queue-federation" />
|
||||
</policy-set>
|
||||
|
||||
<queue-policy name="queue-federation" >
|
||||
<include queue-match="exampleQueue" address-match="#" />
|
||||
</queue-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>us-central-1-master</name>
|
||||
|
||||
<bindings-directory>target/server2/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server2/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server2/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server2/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61618</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61618</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<!--No federation configuration necessary as the other brokers will be creating downstreams/upstreams
|
||||
to this broker-->
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
|
@ -0,0 +1,215 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>broker-federation</artifactId>
|
||||
<version>2.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>federated-queue-downstream</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ActiveMQ Artemis Downstream Federated Queue Example</name>
|
||||
|
||||
<properties>
|
||||
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-queue</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create0</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server0</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server0</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create1</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server1</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server1</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create2</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<instance>${basedir}/target/server2</instance>
|
||||
<configuration>${basedir}/target/classes/activemq/server2</configuration>
|
||||
<!-- this makes it easier in certain envs -->
|
||||
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<testURI>tcp://localhost:61616</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-west-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<testURI>tcp://localhost:61617</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>eu-east-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>start2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<testURI>tcp://localhost:61618</testURI>
|
||||
<args>
|
||||
<param>run</param>
|
||||
</args>
|
||||
<name>us-central-1</name>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>runClient</id>
|
||||
<goals>
|
||||
<goal>runClient</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<clientClass>org.apache.activemq.artemis.jms.example.FederatedQueueDownstreamExample</clientClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop0</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server0</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop1</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server1</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop2</id>
|
||||
<goals>
|
||||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignore>${noServer}</ignore>
|
||||
<location>${basedir}/target/server2</location>
|
||||
<args>
|
||||
<param>stop</param>
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.examples.federation</groupId>
|
||||
<artifactId>federated-queue-downstream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.vladsch.flexmark</groupId>
|
||||
<artifactId>markdown-page-generator-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,51 @@
|
|||
# Federated Queue Example
|
||||
|
||||
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the broker manually.
|
||||
|
||||
This example demonstrates a core queue deployed on three different brokers. The three brokers are configured to form a federated queue mesh.
|
||||
|
||||
In the example we name the brokers, eu-west, eu-east and us-central to give an idea of the use case.
|
||||
|
||||
![EU West, EU East and US Central Diagram](eu-west-east-us-central.png)
|
||||
|
||||
The following is then carried out:
|
||||
|
||||
1. create a consumer on the queue on each node, and we create a producer on only one of the nodes.
|
||||
|
||||
2. send some messages via the producer on EU West, and we verify that **only the local** consumer receives the sent messages.
|
||||
|
||||
3. Next then verify the same on US Central.
|
||||
|
||||
4. Now the consumer on EU West is closed leaving it no local consumers.
|
||||
|
||||
5. Send some more messages to server EU West
|
||||
|
||||
6. We now consume those messages on EU East demonstrating that messages will **re-route** to the another broker based on upstream priority. You will note, US Central is configured to be -1 priority compared to EU East,
|
||||
there for messages should re-route to EU East as it will have a slightly higher priority for its consumers to consume.
|
||||
If US Central and EU East were even priority then the re-direct would be loaded between the two.
|
||||
|
||||
7. Next the consumer on US Central is closed leaving it no local consumers. And we send some more messages to US Cental
|
||||
|
||||
8. Again we consume on EU East demonstrating that US Central messages also can **re-route**, if no local-consumer.
|
||||
|
||||
9. Now we restart EU West and US Centrals consumers.
|
||||
|
||||
10. We produce and consume on US Central, showing that dynamically re-adjusts now local consumers exist and messages delivery by priority to local consumer.
|
||||
|
||||
11. And repeat the same on EU West.
|
||||
|
||||
|
||||
In other words, we are showing how with Federated Queues, ActiveMQ Artemis **routes** sent messages to local consumers as priority, but is able to re-route the sent messages to other distant brokers if consumers are attached to those brokers. Decoupling the location where producers and consumers need to be.
|
||||
|
||||
Here's the relevant snippet from the broker configuration, which tells the broker to form a cluster between the two nodes and to load balance the messages between the nodes.
|
||||
|
||||
The config that defines the federation you can see in the broker.xml for each broker is within the following tags. You will note upstreams are different in each as well as the federation name, which has to be globally unique.
|
||||
|
||||
```
|
||||
<federations>
|
||||
...
|
||||
</federations>
|
||||
```
|
||||
|
||||
|
||||
For more information on ActiveMQ Artemis Federation please see the federation section of the user manual.
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.activemq.artemis.jms.example;
|
||||
|
||||
/**
|
||||
* A simple example that demonstrates dynamic queue messaging routing between remote servers,
|
||||
* as consumers come and go, routing based on priorities.
|
||||
* using Queue Federation feature.
|
||||
*/
|
||||
public class FederatedQueueDownstreamExample {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
FederatedQueueExample.main(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-west-1-master</name>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
<!-- Connectors -->
|
||||
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-west-1-federation">
|
||||
<downstream name="eu-east-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="queue-federation" />
|
||||
</policy-set>
|
||||
|
||||
<queue-policy name="queue-federation" >
|
||||
<include queue-match="exampleQueue" address-match="#" />
|
||||
</queue-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>eu-east-1-master</name>
|
||||
|
||||
<bindings-directory>target/server1/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server1/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server1/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server1/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61617</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61617</acceptor>
|
||||
</acceptors>
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="eu-east-1-federation">
|
||||
<downstream name="eu-west-1-downstream">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="us-central-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>us-central-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="queue-federation" />
|
||||
</policy-set>
|
||||
|
||||
<queue-policy name="queue-federation" >
|
||||
<include queue-match="exampleQueue" address-match="#" />
|
||||
</queue-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
<core xmlns="urn:activemq:core">
|
||||
|
||||
<name>us-central-1-master</name>
|
||||
|
||||
<bindings-directory>target/server2/data/messaging/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>target/server2/data/messaging/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>target/server2/data/messaging/largemessages</large-messages-directory>
|
||||
|
||||
<paging-directory>target/server2/data/messaging/paging</paging-directory>
|
||||
|
||||
<!-- Connectors -->
|
||||
<connectors>
|
||||
<connector name="netty-connector">tcp://localhost:61618</connector>
|
||||
<connector name="eu-west-1-connector">tcp://localhost:61616</connector>
|
||||
<connector name="eu-east-1-connector">tcp://localhost:61617</connector>
|
||||
<connector name="us-central-1-connector">tcp://localhost:61618</connector>
|
||||
</connectors>
|
||||
|
||||
<!-- Acceptors -->
|
||||
<acceptors>
|
||||
<acceptor name="netty-acceptor">tcp://localhost:61618</acceptor>
|
||||
</acceptors>
|
||||
|
||||
|
||||
<!-- Federation -->
|
||||
|
||||
<federations>
|
||||
<federation name="us-central-1-federation">
|
||||
<downstream name="eu-east-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-east-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
<downstream name="eu-west-1-downstream" priority-adjustment="-1">
|
||||
<circuit-breaker-timeout>1000</circuit-breaker-timeout>
|
||||
<static-connectors>
|
||||
<connector-ref>eu-west-1-connector</connector-ref>
|
||||
</static-connectors>
|
||||
<policy ref="policySetA"/>
|
||||
<upstream-connector-ref>netty-connector</upstream-connector-ref>
|
||||
</downstream>
|
||||
|
||||
<policy-set name="policySetA">
|
||||
<policy ref="queue-federation" />
|
||||
</policy-set>
|
||||
|
||||
<queue-policy name="queue-federation" >
|
||||
<include queue-match="exampleQueue" address-match="#" />
|
||||
</queue-policy>
|
||||
</federation>
|
||||
</federations>
|
||||
|
||||
<!-- Other config -->
|
||||
|
||||
<security-settings>
|
||||
<!--security for example queue-->
|
||||
<security-setting match="exampleQueue">
|
||||
<permission roles="guest" type="createDurableQueue"/>
|
||||
<permission roles="guest" type="deleteDurableQueue"/>
|
||||
<permission roles="guest" type="createNonDurableQueue"/>
|
||||
<permission roles="guest" type="deleteNonDurableQueue"/>
|
||||
<permission roles="guest" type="consume"/>
|
||||
<permission roles="guest" type="send"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="exampleQueue">
|
||||
<anycast>
|
||||
<queue name="exampleQueue"/>
|
||||
</anycast>
|
||||
</address>
|
||||
</addresses>
|
||||
</core>
|
||||
</configuration>
|
|
@ -23,6 +23,7 @@ import javax.jms.MessageProducer;
|
|||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.TextMessage;
|
||||
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
|
||||
|
|
|
@ -48,14 +48,21 @@ under the License.
|
|||
<id>examples</id>
|
||||
<modules>
|
||||
<module>federated-queue</module>
|
||||
<module>federated-queue-downstream</module>
|
||||
<module>federated-queue-downstream-upstream</module>
|
||||
<module>federated-address</module>
|
||||
<module>federated-address-downstream</module>
|
||||
<module>federated-address-downstream-upstream</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<modules>
|
||||
<module>federated-queue</module>
|
||||
<module>federated-queue-downstream</module>
|
||||
<module>federated-queue-downstream-upstream</module>
|
||||
<module>federated-address</module>
|
||||
<module>federated-address-downstream-upstream</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.tests.integration.federation;
|
||||
|
||||
import java.util.Collections;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.JMSException;
|
||||
|
@ -25,10 +24,17 @@ import javax.jms.MessageConsumer;
|
|||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.Topic;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.TransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationAddressPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.transformer.Transformer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.junit.Before;
|
||||
|
@ -46,25 +52,133 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
super.setUp();
|
||||
}
|
||||
|
||||
|
||||
protected ConnectionFactory getCF(int i) throws Exception {
|
||||
return new ActiveMQConnectionFactory("vm://" + i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testFederatedAddressReplication() throws Exception {
|
||||
public void testDownstreamFederatedAddressReplication() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", address);
|
||||
FederationConfiguration federationConfiguration = createDownstreamFederationConfiguration("server1", address,
|
||||
getServer(0).getConfiguration().getTransportConfigurations("server0")[0]);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
FederationConfiguration federationConfiguration2 = createFederationConfiguration("server0", address);
|
||||
FederationConfiguration federationConfiguration2 = createDownstreamFederationConfiguration("server0", address,
|
||||
getServer(1).getConfiguration().getTransportConfigurations("server1")[0]);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration2);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedAddressReplication(address);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownstreamFederatedAddressReplicationRef() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createDownstreamFederationConfiguration("server1", address,
|
||||
"server0");
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
FederationConfiguration federationConfiguration2 = createDownstreamFederationConfiguration("server0", address,
|
||||
"server1");
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration2);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedAddressReplication(address);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownstreamFederatedAddressReplicationRefOneWay() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration2 = createDownstreamFederationConfiguration("server0", address,
|
||||
"server1");
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration2);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedAddressReplication(address);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpstreamFederatedAddressReplication() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
FederationConfiguration federationConfiguration2 = createUpstreamFederationConfiguration("server0", address);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration2);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedAddressReplication(address);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownstreamFederatedAddressReplicationRefOneWayTransformer() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration2 = createDownstreamFederationConfiguration("server0", address, "server1");
|
||||
addTransformerConfiguration(federationConfiguration2, address);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration2);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
verifyTransformer(address);
|
||||
}
|
||||
|
||||
private void verifyTransformer(String address) throws Exception {
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
connection1.start();
|
||||
connection0.start();
|
||||
|
||||
Session session1 = connection1.createSession();
|
||||
Topic topic1 = session1.createTopic(address);
|
||||
MessageProducer producer1 = session1.createProducer(topic1);
|
||||
|
||||
Session session0 = connection0.createSession();
|
||||
Topic topic0 = session0.createTopic(address);
|
||||
MessageConsumer consumer0 = session0.createConsumer(topic0);
|
||||
|
||||
assertTrue(Wait.waitFor(() -> getServer(1).getPostOffice().getBindingsForAddress(
|
||||
SimpleString.toSimpleString(address)).getBindings().size() == 1));
|
||||
|
||||
producer1.send(session1.createTextMessage("hello"));
|
||||
Message message = consumer0.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals(message.getBooleanProperty(FederatedQueueTest.TestTransformer.TEST_PROPERTY), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpstreamFederatedAddressReplicationOneWay() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedAddressReplication(address);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpstreamFederatedAddressReplicationOneWayTransformer() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
addTransformerConfiguration(federationConfiguration, address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
verifyTransformer(address);
|
||||
}
|
||||
|
||||
private void testFederatedAddressReplication(String address) throws Exception {
|
||||
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
|
@ -81,7 +195,7 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
Topic topic0 = session0.createTopic(address);
|
||||
MessageConsumer consumer0 = session0.createConsumer(topic0);
|
||||
|
||||
Wait.waitFor(() -> getServer(1).getPostOffice().getBindingsForAddress(SimpleString.toSimpleString(address)).getBindings().size() == 1);
|
||||
assertTrue(Wait.waitFor(() -> getServer(1).getPostOffice().getBindingsForAddress(SimpleString.toSimpleString(address)).getBindings().size() == 1));
|
||||
|
||||
producer.send(session1.createTextMessage("hello"));
|
||||
|
||||
|
@ -143,7 +257,7 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
|
||||
assertNull(consumer0.receive(100));
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", address);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -161,7 +275,7 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
public void testFederatedAddressRemoteBrokerRestart() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", address);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -219,7 +333,7 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
public void testFederatedAddressLocalBrokerRestart() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", address);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", address);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -274,27 +388,125 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedAddressChainOfBrokers() throws Exception {
|
||||
String address = getName();
|
||||
|
||||
private FederationConfiguration createFederationConfiguration(String connector, String address) {
|
||||
//Set queue up on all three brokers
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
// }
|
||||
|
||||
//Connect broker 0 (consumer will be here at end of chain) to broker 1
|
||||
FederationConfiguration federationConfiguration0 = createUpstreamFederationConfiguration("server1", address, 2);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
//Connect broker 1 (middle of chain) to broker 2
|
||||
FederationConfiguration federationConfiguration1 = createUpstreamFederationConfiguration("server2", address, 2);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration1);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
//Broker 2 we dont setup any federation as he is the upstream (head of the chain)
|
||||
|
||||
//Now the test.
|
||||
|
||||
|
||||
ConnectionFactory cf2 = getCF(2);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection2 = cf2.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
connection0.start();
|
||||
Session session0 = connection0.createSession();
|
||||
Topic topic0 = session0.createTopic(address);
|
||||
|
||||
connection2.start();
|
||||
Session session2 = connection2.createSession();
|
||||
Topic topic2 = session2.createTopic(address);
|
||||
|
||||
MessageProducer producer2 = session2.createProducer(topic2);
|
||||
MessageConsumer consumer0 = session0.createConsumer(topic0);
|
||||
|
||||
assertTrue(Wait.waitFor(() -> getServer(1).getPostOffice().getBindingsForAddress(SimpleString.toSimpleString(address)).getBindings().size() == 1));
|
||||
assertTrue(Wait.waitFor(() -> getServer(2).getPostOffice().getBindingsForAddress(SimpleString.toSimpleString(address)).getBindings().size() == 1));
|
||||
|
||||
//Test producers being on broker 2 and consumer on broker 0, with broker 2 being in the middle of the chain.
|
||||
producer2.send(session2.createTextMessage("hello"));
|
||||
assertNotNull(consumer0.receive(1000));
|
||||
}
|
||||
}
|
||||
|
||||
private FederationConfiguration createFederationConfiguration(String address, int hops) {
|
||||
FederationAddressPolicyConfiguration addressPolicyConfiguration = new FederationAddressPolicyConfiguration();
|
||||
addressPolicyConfiguration.setName( "AddressPolicy" + address);
|
||||
addressPolicyConfiguration.addInclude(new FederationAddressPolicyConfiguration.Matcher().setAddressMatch(address));
|
||||
addressPolicyConfiguration.setMaxHops(hops);
|
||||
|
||||
FederationConfiguration federationConfiguration = new FederationConfiguration();
|
||||
federationConfiguration.setName("default");
|
||||
federationConfiguration.addFederationPolicy(addressPolicyConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private FederationConfiguration createUpstreamFederationConfiguration(String connector, String address, int hops) {
|
||||
FederationUpstreamConfiguration upstreamConfiguration = new FederationUpstreamConfiguration();
|
||||
upstreamConfiguration.setName(connector);
|
||||
upstreamConfiguration.getConnectionConfiguration().setStaticConnectors(Collections.singletonList(connector));
|
||||
upstreamConfiguration.getConnectionConfiguration().setCircuitBreakerTimeout(-1);
|
||||
upstreamConfiguration.addPolicyRef("AddressPolicy" + address);
|
||||
|
||||
|
||||
FederationAddressPolicyConfiguration addressPolicyConfiguration = new FederationAddressPolicyConfiguration();
|
||||
addressPolicyConfiguration.setName( "AddressPolicy" + address);
|
||||
addressPolicyConfiguration.addInclude(new FederationAddressPolicyConfiguration.Matcher().setAddressMatch(address));
|
||||
addressPolicyConfiguration.setMaxHops(1);
|
||||
|
||||
FederationConfiguration federationConfiguration = new FederationConfiguration();
|
||||
federationConfiguration.setName("default");
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration(address, hops);
|
||||
federationConfiguration.addUpstreamConfiguration(upstreamConfiguration);
|
||||
federationConfiguration.addFederationPolicy(addressPolicyConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
private FederationConfiguration createUpstreamFederationConfiguration(String connector, String address) {
|
||||
return createUpstreamFederationConfiguration(connector, address, 1);
|
||||
}
|
||||
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String address, TransportConfiguration transportConfiguration) {
|
||||
return createDownstreamFederationConfiguration(connector, address, transportConfiguration, 1);
|
||||
}
|
||||
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String address, TransportConfiguration transportConfiguration,
|
||||
int hops) {
|
||||
FederationDownstreamConfiguration downstreamConfiguration = new FederationDownstreamConfiguration();
|
||||
downstreamConfiguration.setName(connector);
|
||||
downstreamConfiguration.getConnectionConfiguration().setStaticConnectors(Collections.singletonList(connector));
|
||||
downstreamConfiguration.getConnectionConfiguration().setCircuitBreakerTimeout(-1);
|
||||
downstreamConfiguration.addPolicyRef("AddressPolicy" + address);
|
||||
downstreamConfiguration.setUpstreamConfiguration(transportConfiguration);
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration(address, hops);
|
||||
federationConfiguration.addDownstreamConfiguration(downstreamConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String address, String transportConfigurationRef,
|
||||
int hops) {
|
||||
FederationDownstreamConfiguration downstreamConfiguration = new FederationDownstreamConfiguration();
|
||||
downstreamConfiguration.setName(connector);
|
||||
downstreamConfiguration.getConnectionConfiguration().setStaticConnectors(Collections.singletonList(connector));
|
||||
downstreamConfiguration.getConnectionConfiguration().setCircuitBreakerTimeout(-1);
|
||||
downstreamConfiguration.addPolicyRef("AddressPolicy" + address);
|
||||
downstreamConfiguration.setUpstreamConfigurationRef(transportConfigurationRef);
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration(address, hops);
|
||||
federationConfiguration.addDownstreamConfiguration(downstreamConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String address, String transportConfigurationRef) {
|
||||
return createDownstreamFederationConfiguration(connector, address, transportConfigurationRef, 1);
|
||||
}
|
||||
|
||||
private void addTransformerConfiguration(final FederationConfiguration federationConfiguration, final String address) {
|
||||
federationConfiguration.addTransformerConfiguration(
|
||||
new FederationTransformerConfiguration("transformer", new TransformerConfiguration(TestTransformer.class.getName())));
|
||||
FederationAddressPolicyConfiguration policy = (FederationAddressPolicyConfiguration) federationConfiguration.getFederationPolicyMap().get("AddressPolicy" + address);
|
||||
policy.setTransformerRef("transformer");
|
||||
}
|
||||
|
||||
private Message createTextMessage(Session session1, String group) throws JMSException {
|
||||
Message message = session1.createTextMessage("hello");
|
||||
|
@ -302,5 +514,15 @@ public class FederatedAddressTest extends FederatedTestBase {
|
|||
return message;
|
||||
}
|
||||
|
||||
public static class TestTransformer implements Transformer {
|
||||
|
||||
static String TEST_PROPERTY = "transformed";
|
||||
|
||||
@Override
|
||||
public org.apache.activemq.artemis.api.core.Message transform(org.apache.activemq.artemis.api.core.Message message) {
|
||||
message.putBooleanProperty(TEST_PROPERTY, true);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.tests.integration.federation;
|
||||
|
||||
import java.util.Collections;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.JMSException;
|
||||
|
@ -26,12 +25,18 @@ import javax.jms.MessageProducer;
|
|||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.TextMessage;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.postoffice.QueueBinding;
|
||||
import org.apache.activemq.artemis.core.config.FederationConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.TransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationDownstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationQueuePolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationTransformerConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.federation.FederationUpstreamConfiguration;
|
||||
import org.apache.activemq.artemis.core.postoffice.QueueBinding;
|
||||
import org.apache.activemq.artemis.core.server.transformer.Transformer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.junit.Before;
|
||||
|
@ -54,16 +59,136 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
return new ActiveMQConnectionFactory("vm://" + i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsume() throws Exception {
|
||||
public void testFederatedQueueRemoteConsumeUpstream() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", queueName);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueRemoteConsume(queueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsumeUpstreamPriorityAdjustment() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
FederationQueuePolicyConfiguration policy = (FederationQueuePolicyConfiguration) federationConfiguration.getFederationPolicyMap().get("QueuePolicy" + queueName);
|
||||
//Favor federated broker over local consumers
|
||||
policy.setPriorityAdjustment(1);
|
||||
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueRemoteConsumeUpstreamPriorityAdjustment(queueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsumeDownstreamPriorityAdjustment() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createDownstreamFederationConfiguration("server0", queueName, "server1");
|
||||
FederationQueuePolicyConfiguration policy = (FederationQueuePolicyConfiguration) federationConfiguration.getFederationPolicyMap().get("QueuePolicy" + queueName);
|
||||
//Favor federated broker over local consumers
|
||||
policy.setPriorityAdjustment(1);
|
||||
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueRemoteConsumeUpstreamPriorityAdjustment(queueName);
|
||||
}
|
||||
|
||||
private void testFederatedQueueRemoteConsumeUpstreamPriorityAdjustment(final String queueName) throws Exception {
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
connection0.start();
|
||||
connection1.start();
|
||||
Session session0 = connection0.createSession();
|
||||
Session session1 = connection1.createSession();
|
||||
Queue queue0 = session0.createQueue(queueName);
|
||||
Queue queue1 = session1.createQueue(queueName);
|
||||
|
||||
MessageConsumer consumer0 = session0.createConsumer(queue0);
|
||||
MessageConsumer consumer1 = session1.createConsumer(queue1);
|
||||
|
||||
//Wait for local and federated consumer to be established on Server 1
|
||||
assertTrue(Wait.waitFor(() -> getServer(1).locateQueue(SimpleString.toSimpleString(queueName)).getConsumerCount() == 2,
|
||||
5000, 100));
|
||||
|
||||
MessageProducer producer1 = session1.createProducer(queue1);
|
||||
producer1.send(session1.createTextMessage("hello"));
|
||||
|
||||
//Consumer 0 should receive the message over consumer because of adjusted priority
|
||||
//to favor the federated broker
|
||||
assertNull(consumer1.receive(500));
|
||||
assertNotNull(consumer0.receive(1000));
|
||||
|
||||
consumer0.close();
|
||||
consumer1.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyTransformer(String queueName) throws Exception {
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
connection1.start();
|
||||
Session session1 = connection1.createSession();
|
||||
Queue queue1 = session1.createQueue(queueName);
|
||||
MessageProducer producer1 = session1.createProducer(queue1);
|
||||
producer1.send(session1.createTextMessage("hello"));
|
||||
|
||||
connection0.start();
|
||||
Session session0 = connection0.createSession();
|
||||
Queue queue0 = session0.createQueue(queueName);
|
||||
MessageConsumer consumer0 = session0.createConsumer(queue0);
|
||||
|
||||
Message message = consumer0.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals(message.getBooleanProperty(TestTransformer.TEST_PROPERTY), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsumeUpstreamTransformer() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
addTransformerConfiguration(federationConfiguration, queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
verifyTransformer(queueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsumeDownstream() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createDownstreamFederationConfiguration("server0", queueName, "server1");
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueRemoteConsume(queueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueRemoteConsumeDownstreamTransformer() throws Exception {
|
||||
String queueName = getName();
|
||||
|
||||
FederationConfiguration federationConfiguration = createDownstreamFederationConfiguration("server0", queueName, "server1");
|
||||
addTransformerConfiguration(federationConfiguration, queueName);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
verifyTransformer(queueName);
|
||||
}
|
||||
|
||||
private void testFederatedQueueRemoteConsume(final String queueName) throws Exception {
|
||||
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
|
@ -130,7 +255,7 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
|
||||
assertNull(consumer0.receive(100));
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", queueName);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -141,20 +266,134 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueBiDirectional() throws Exception {
|
||||
public void testFederatedQueueBiDirectionalUpstream() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
FederationConfiguration federationConfiguration0 = createFederationConfiguration("server1", queueName);
|
||||
FederationConfiguration federationConfiguration0 = createUpstreamFederationConfiguration("server1", queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
FederationConfiguration federationConfiguration1 = createFederationConfiguration("server0", queueName);
|
||||
FederationConfiguration federationConfiguration1 = createUpstreamFederationConfiguration("server0", queueName);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration1);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueBiDirectional(queueName, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueBiDirectionalDownstream() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
FederationConfiguration federationConfiguration0 = createDownstreamFederationConfiguration("server1", queueName, "server0");
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
FederationConfiguration federationConfiguration1 = createDownstreamFederationConfiguration("server0", queueName, "server1");
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration1);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueBiDirectional(queueName, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueBiDirectionalDownstreamUpstream() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration0 = createDownstreamFederationConfiguration("server1-downstream",
|
||||
"server1", queueName, null, false, "server0");
|
||||
FederationUpstreamConfiguration upstreamConfig = createFederationUpstream("server1", queueName);
|
||||
federationConfiguration0.addUpstreamConfiguration(upstreamConfig);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueBiDirectional(queueName, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueBiDirectionalDownstreamUpstreamSharedConnection() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration0 = createDownstreamFederationConfiguration("server1-downstream",
|
||||
"server1", queueName, null, true, "server0");
|
||||
FederationUpstreamConfiguration upstreamConfig = createFederationUpstream("server1", queueName);
|
||||
upstreamConfig.getConnectionConfiguration().setShareConnection(true);
|
||||
federationConfiguration0.addUpstreamConfiguration(upstreamConfig);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueBiDirectional(queueName, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueShareUpstreamConnectionFalse() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration0 = createDownstreamFederationConfiguration("server1-downstream",
|
||||
"server1", queueName, null, false, "server0");
|
||||
federationConfiguration0.addUpstreamConfiguration(createFederationUpstream("server1", queueName));
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueShareUpstreamConnection(queueName, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueShareUpstreamConnectionTrue() throws Exception {
|
||||
String queueName = getName();
|
||||
//Set queue up on both brokers
|
||||
for (int i = 0; i < 2; i++) {
|
||||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration0 = createDownstreamFederationConfiguration("server1-downstream",
|
||||
"server1", queueName, null, true, "server0");
|
||||
FederationUpstreamConfiguration upstreamConfiguration = createFederationUpstream("server1", queueName);
|
||||
upstreamConfiguration.getConnectionConfiguration().setShareConnection(true);
|
||||
federationConfiguration0.addUpstreamConfiguration(upstreamConfiguration);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
testFederatedQueueShareUpstreamConnection(queueName, 2, 2);
|
||||
}
|
||||
|
||||
private void testFederatedQueueShareUpstreamConnection(String queueName, int server0Connections, int server1Connections) throws Exception {
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
connection0.start();
|
||||
connection1.start();
|
||||
Session session0 = connection0.createSession();
|
||||
Session session1 = connection1.createSession();
|
||||
|
||||
MessageConsumer consumer0 = session0.createConsumer(session0.createQueue(queueName));
|
||||
MessageConsumer consumer1 = session1.createConsumer(session1.createQueue(queueName));
|
||||
|
||||
assertTrue(Wait.waitFor(() -> getServer(0).getConnectionCount() == server0Connections, 500, 100));
|
||||
assertTrue(Wait.waitFor(() -> getServer(1).getConnectionCount() == server1Connections, 500, 100));
|
||||
assertFalse(Wait.waitFor(() -> getServer(0).getConnectionCount() > server0Connections, 500, 100));
|
||||
assertFalse(Wait.waitFor(() -> getServer(1).getConnectionCount() > server1Connections, 500, 100));
|
||||
}
|
||||
}
|
||||
|
||||
private void testFederatedQueueBiDirectional(String queueName, boolean shared) throws Exception {
|
||||
ConnectionFactory cf1 = getCF(1);
|
||||
ConnectionFactory cf0 = getCF(0);
|
||||
try (Connection connection1 = cf1.createConnection(); Connection connection0 = cf0.createConnection()) {
|
||||
|
@ -169,7 +408,6 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
MessageProducer producer1 = session1.createProducer(queue1);
|
||||
MessageConsumer consumer0 = session0.createConsumer(queue0);
|
||||
|
||||
|
||||
//Test producers being on broker 0 and broker 1 and consumer on broker 0.
|
||||
producer0.send(session1.createTextMessage("hello"));
|
||||
assertNotNull(consumer0.receive(1000));
|
||||
|
@ -183,13 +421,21 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
assertFalse(Wait.waitFor(() -> getServer(1).locateQueue(SimpleString.toSimpleString(queueName)).getConsumerCount() > 1, 500, 100));
|
||||
|
||||
//Test consumer move from broker 0, to broker 1
|
||||
final int server1ConsumerCount = getServer(1).getConnectionCount();
|
||||
consumer0.close();
|
||||
Wait.waitFor(() -> ((QueueBinding) getServer(0).getPostOffice().getBinding(SimpleString.toSimpleString(queueName))).consumerCount() == 0, 1000);
|
||||
|
||||
//Make sure we don't drop connection if shared
|
||||
if (shared) {
|
||||
assertFalse(Wait.waitFor(() -> getServer(1).getConnectionCount() == server1ConsumerCount - 1,
|
||||
500, 100));
|
||||
assertTrue(server1ConsumerCount == getServer(1).getConnectionCount());
|
||||
}
|
||||
|
||||
MessageConsumer consumer1 = session1.createConsumer(queue1);
|
||||
|
||||
producer0.send(session1.createTextMessage("hello"));
|
||||
assertNotNull(consumer1.receive(10000));
|
||||
assertNotNull(consumer1.receive(1000));
|
||||
|
||||
producer1.send(session1.createTextMessage("hello"));
|
||||
assertNotNull(consumer1.receive(1000));
|
||||
|
@ -210,7 +456,6 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueChainOfBrokers() throws Exception {
|
||||
String queueName = getName();
|
||||
|
@ -221,12 +466,12 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
}
|
||||
|
||||
//Connect broker 0 (consumer will be here at end of chain) to broker 1
|
||||
FederationConfiguration federationConfiguration0 = createFederationConfiguration("server1", queueName, true);
|
||||
FederationConfiguration federationConfiguration0 = createUpstreamFederationConfiguration("server1", queueName, true);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration0);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
//Connect broker 1 (middle of chain) to broker 2
|
||||
FederationConfiguration federationConfiguration1 = createFederationConfiguration("server2", queueName, true);
|
||||
FederationConfiguration federationConfiguration1 = createUpstreamFederationConfiguration("server2", queueName, true);
|
||||
getServer(1).getConfiguration().getFederationConfigurations().add(federationConfiguration1);
|
||||
getServer(1).getFederationManager().deploy();
|
||||
//Broker 2 we dont setup any federation as he is the upstream (head of the chain)
|
||||
|
@ -263,7 +508,7 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", queueName);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -307,7 +552,6 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
assertNotNull(consumer0.receive(1000));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFederatedQueueLocalBrokerRestart() throws Exception {
|
||||
String queueName = getName();
|
||||
|
@ -317,7 +561,7 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
getServer(i).createQueue(SimpleString.toSimpleString(queueName), RoutingType.ANYCAST, SimpleString.toSimpleString(queueName), null, true, false);
|
||||
}
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration("server1", queueName);
|
||||
FederationConfiguration federationConfiguration = createUpstreamFederationConfiguration("server1", queueName);
|
||||
getServer(0).getConfiguration().getFederationConfigurations().add(federationConfiguration);
|
||||
getServer(0).getFederationManager().deploy();
|
||||
|
||||
|
@ -365,17 +609,56 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
assertNotNull(consumer0.receive(1000));
|
||||
}
|
||||
|
||||
private FederationConfiguration createFederationConfiguration(String connector, String queueName) {
|
||||
return createFederationConfiguration(connector, queueName, null);
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String queueName, Boolean includeFederated,
|
||||
String transportConfigurationRef) {
|
||||
return createDownstreamFederationConfiguration(null, connector, queueName, includeFederated, false, transportConfigurationRef);
|
||||
}
|
||||
|
||||
private FederationConfiguration createFederationConfiguration(String connector, String queueName, Boolean includeFederated) {
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String name, String connector, String queueName, Boolean includeFederated,
|
||||
boolean shareConnection, String transportConfigurationRef) {
|
||||
FederationDownstreamConfiguration downstreamConfiguration = new FederationDownstreamConfiguration();
|
||||
downstreamConfiguration.setName(name != null ? name : connector);
|
||||
downstreamConfiguration.getConnectionConfiguration().setStaticConnectors(Collections.singletonList(connector));
|
||||
downstreamConfiguration.getConnectionConfiguration().setCircuitBreakerTimeout(-1);
|
||||
downstreamConfiguration.getConnectionConfiguration().setShareConnection(shareConnection);
|
||||
downstreamConfiguration.addPolicyRef("QueuePolicy" + queueName);
|
||||
downstreamConfiguration.setUpstreamConfigurationRef(transportConfigurationRef);
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration(connector, queueName, includeFederated);
|
||||
federationConfiguration.addDownstreamConfiguration(downstreamConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private FederationConfiguration createDownstreamFederationConfiguration(String connector, String queueName, String transportConfigurationRef) {
|
||||
return createDownstreamFederationConfiguration(null, connector, queueName, null, false, transportConfigurationRef);
|
||||
}
|
||||
|
||||
private FederationConfiguration createUpstreamFederationConfiguration(String connector, String queueName, Boolean includeFederated) {
|
||||
FederationUpstreamConfiguration upstreamConfiguration = createFederationUpstream(connector, queueName);
|
||||
|
||||
FederationConfiguration federationConfiguration = createFederationConfiguration(connector, queueName, includeFederated);
|
||||
federationConfiguration.addUpstreamConfiguration(upstreamConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private FederationUpstreamConfiguration createFederationUpstream(String connector, String queueName) {
|
||||
|
||||
FederationUpstreamConfiguration upstreamConfiguration = new FederationUpstreamConfiguration();
|
||||
upstreamConfiguration.setName(connector);
|
||||
upstreamConfiguration.setName("server1-upstream");
|
||||
upstreamConfiguration.getConnectionConfiguration().setStaticConnectors(Collections.singletonList(connector));
|
||||
upstreamConfiguration.getConnectionConfiguration().setCircuitBreakerTimeout(-1);
|
||||
upstreamConfiguration.addPolicyRef("QueuePolicy" + queueName);
|
||||
|
||||
return upstreamConfiguration;
|
||||
}
|
||||
|
||||
private FederationConfiguration createUpstreamFederationConfiguration(String connector, String queueName) {
|
||||
return createUpstreamFederationConfiguration(connector, queueName, null);
|
||||
}
|
||||
|
||||
private FederationConfiguration createFederationConfiguration(String connector, String queueName, Boolean includeFederated) {
|
||||
|
||||
FederationQueuePolicyConfiguration queuePolicyConfiguration = new FederationQueuePolicyConfiguration();
|
||||
queuePolicyConfiguration.setName( "QueuePolicy" + queueName);
|
||||
|
@ -387,17 +670,33 @@ public class FederatedQueueTest extends FederatedTestBase {
|
|||
|
||||
FederationConfiguration federationConfiguration = new FederationConfiguration();
|
||||
federationConfiguration.setName("default");
|
||||
federationConfiguration.addUpstreamConfiguration(upstreamConfiguration);
|
||||
federationConfiguration.addFederationPolicy(queuePolicyConfiguration);
|
||||
|
||||
return federationConfiguration;
|
||||
}
|
||||
|
||||
private void addTransformerConfiguration(final FederationConfiguration federationConfiguration, final String queueName) {
|
||||
federationConfiguration.addTransformerConfiguration(
|
||||
new FederationTransformerConfiguration("transformer", new TransformerConfiguration(TestTransformer.class.getName())));
|
||||
FederationQueuePolicyConfiguration policy = (FederationQueuePolicyConfiguration) federationConfiguration.getFederationPolicyMap().get("QueuePolicy" + queueName);
|
||||
policy.setTransformerRef("transformer");
|
||||
}
|
||||
|
||||
private Message createTextMessage(Session session1, String group) throws JMSException {
|
||||
Message message = session1.createTextMessage("hello");
|
||||
message.setStringProperty("JMSXGroupID", group);
|
||||
return message;
|
||||
}
|
||||
|
||||
public static class TestTransformer implements Transformer {
|
||||
|
||||
static String TEST_PROPERTY = "transformed";
|
||||
|
||||
@Override
|
||||
public org.apache.activemq.artemis.api.core.Message transform(org.apache.activemq.artemis.api.core.Message message) {
|
||||
message.putBooleanProperty(TEST_PROPERTY, true);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -158,6 +158,27 @@ public abstract class ActiveMQBufferTestBase extends ActiveMQTestBase {
|
|||
Assert.assertFalse(wrapper.readBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutNullableTrueBoolean() throws Exception {
|
||||
wrapper.writeNullableBoolean(true);
|
||||
|
||||
Assert.assertTrue(wrapper.readNullableBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutNullableFalseBoolean() throws Exception {
|
||||
wrapper.writeNullableBoolean(false);
|
||||
|
||||
Assert.assertFalse(wrapper.readNullableBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullBoolean() throws Exception {
|
||||
wrapper.writeNullableBoolean(null);
|
||||
|
||||
Assert.assertNull(wrapper.readNullableBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChar() throws Exception {
|
||||
wrapper.writeChar('a');
|
||||
|
@ -195,6 +216,21 @@ public abstract class ActiveMQBufferTestBase extends ActiveMQTestBase {
|
|||
Assert.assertEquals(l, wrapper.readLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullableLong() throws Exception {
|
||||
Long l = RandomUtil.randomLong();
|
||||
wrapper.writeNullableLong(l);
|
||||
|
||||
Assert.assertEquals(l, wrapper.readNullableLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullLong() throws Exception {
|
||||
wrapper.writeNullableLong(null);
|
||||
|
||||
Assert.assertNull(wrapper.readNullableLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsignedShort() throws Exception {
|
||||
short s1 = Short.MAX_VALUE;
|
||||
|
|
Loading…
Reference in New Issue