From 6ab133ab896874c2bbcdc0bbbe56b879764f25a4 Mon Sep 17 00:00:00 2001 From: Francesco Nigro Date: Mon, 5 Dec 2016 19:04:21 +0100 Subject: [PATCH] ARTEMIS-878 Added/Modified CLI commands and tests --- .../apache/activemq/artemis/cli/Artemis.java | 8 +- .../cli/commands/address/AddRoutingType.java | 78 ++++++++++++++++ .../cli/commands/address/CreateAddress.java | 34 +------ .../cli/commands/address/DeleteAddress.java | 2 +- .../commands/address/RemoveRoutingType.java | 78 ++++++++++++++++ .../cli/commands/address/ShowAddress.java | 4 +- .../cli/commands/queue/CreateQueue.java | 13 ++- .../management/ActiveMQServerControl.java | 15 +++- .../impl/ActiveMQServerControlImpl.java | 48 +++++++--- .../core/postoffice/AddressManager.java | 4 + .../artemis/core/postoffice/PostOffice.java | 5 ++ .../core/postoffice/impl/PostOfficeImpl.java | 34 +++++++ .../postoffice/impl/SimpleAddressManager.java | 7 ++ .../core/server/ActiveMQMessageBundle.java | 3 + .../artemis/core/server/ActiveMQServer.java | 20 +++++ .../core/server/impl/ActiveMQServerImpl.java | 13 +++ .../integration/cli/AddressCommandTest.java | 90 +++++++++++++++++++ .../integration/cli/QueueCommandTest.java | 12 ++- .../ActiveMQServerControlUsingCoreTest.java | 15 +++- .../server/impl/fakes/FakePostOffice.java | 12 +++ 20 files changed, 443 insertions(+), 52 deletions(-) create mode 100644 artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/AddRoutingType.java create mode 100644 artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/RemoveRoutingType.java diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java index 94779fc6f2..13e2f7cada 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java @@ -30,8 +30,12 @@ import org.apache.activemq.artemis.cli.commands.Kill; import org.apache.activemq.artemis.cli.commands.Mask; import org.apache.activemq.artemis.cli.commands.Run; import org.apache.activemq.artemis.cli.commands.Stop; +import org.apache.activemq.artemis.cli.commands.address.AddRoutingType; import org.apache.activemq.artemis.cli.commands.address.CreateAddress; import org.apache.activemq.artemis.cli.commands.address.DeleteAddress; +import org.apache.activemq.artemis.cli.commands.address.HelpAddress; +import org.apache.activemq.artemis.cli.commands.address.RemoveRoutingType; +import org.apache.activemq.artemis.cli.commands.address.ShowAddress; import org.apache.activemq.artemis.cli.commands.queue.CreateQueue; import org.apache.activemq.artemis.cli.commands.queue.DeleteQueue; import org.apache.activemq.artemis.cli.commands.queue.HelpQueue; @@ -133,8 +137,8 @@ public class Artemis { builder.withGroup("queue").withDescription("Queue tools group (create|delete) (example ./artemis queue create)"). withDefaultCommand(HelpQueue.class).withCommands(CreateQueue.class, DeleteQueue.class); - builder.withGroup("address").withDescription("Queue tools group (create|delete) (example ./artemis queue create)"). - withDefaultCommand(HelpQueue.class).withCommands(CreateAddress.class, DeleteAddress.class); + builder.withGroup("address").withDescription("Address tools group (create|delete|addRoutingType|removeRoutingType|show) (example ./artemis address create)"). + withDefaultCommand(HelpAddress.class).withCommands(CreateAddress.class, DeleteAddress.class, AddRoutingType.class, RemoveRoutingType.class, ShowAddress.class); if (instance != null) { builder.withGroup("data").withDescription("data tools group (print|exp|imp|exp|encode|decode|compact) (example ./artemis data print)"). diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/AddRoutingType.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/AddRoutingType.java new file mode 100644 index 0000000000..fd79620f73 --- /dev/null +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/AddRoutingType.java @@ -0,0 +1,78 @@ +/** + * 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.cli.commands.address; + +import io.airlift.airline.Command; +import io.airlift.airline.Option; +import org.apache.activemq.artemis.api.core.client.ClientMessage; +import org.apache.activemq.artemis.api.core.management.ManagementHelper; +import org.apache.activemq.artemis.cli.commands.AbstractAction; +import org.apache.activemq.artemis.cli.commands.ActionContext; + +@Command(name = "addRoutingType", description = "add the provided routing types to an address") +public class AddRoutingType extends AbstractAction { + + @Option(name = "--name", description = "The name of this address", required = true) + String name; + + @Option(name = "--routingType", description = "The routing types to be added to this address, options are 'anycast' or 'multicast'", required = true) + String routingType; + + @Override + public Object execute(ActionContext context) throws Exception { + super.execute(context); + addRoutingType(context); + return null; + } + + private void addRoutingType(final ActionContext context) throws Exception { + performCoreManagement(new AbstractAction.ManagementCallback() { + @Override + public void setUpInvocation(ClientMessage message) throws Exception { + ManagementHelper.putOperationInvocation(message, "broker", "addRoutingType", name, routingType); + } + + @Override + public void requestSuccessful(ClientMessage reply) throws Exception { + context.out.println("Address " + name + " updated successfully."); + } + + @Override + public void requestFailed(ClientMessage reply) throws Exception { + String errMsg = (String) ManagementHelper.getResult(reply, String.class); + context.err.println("Failed to update address " + name + ". Reason: " + errMsg); + } + }); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRoutingType() { + return routingType; + } + + public void setRoutingType(String routingType) { + this.routingType = routingType; + } +} diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/CreateAddress.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/CreateAddress.java index 42f721aaf7..2795238383 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/CreateAddress.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/CreateAddress.java @@ -19,11 +19,11 @@ package org.apache.activemq.artemis.cli.commands.address; import io.airlift.airline.Command; import io.airlift.airline.Option; +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.cli.commands.AbstractAction; import org.apache.activemq.artemis.cli.commands.ActionContext; -import org.apache.activemq.artemis.core.server.RoutingType; @Command(name = "create", description = "create an address") public class CreateAddress extends AbstractAction { @@ -32,13 +32,7 @@ public class CreateAddress extends AbstractAction { String name; @Option(name = "--routingTypes", description = "The routing types supported by this address, options are 'anycast' or 'multicast', enter comma separated list, defaults to 'multicast' only") - String[] routingTypes = new String[] {RoutingType.MULTICAST.toString()}; - - @Option(name = "--defaultMaxConsumers", description = "Sets the default max consumers for any queues created under this address, default = -1 (no limit)") - int defaultMaxConsumers = -1; - - @Option(name = "--defaultDeleteOnNoConsumers", description = "Sets the default delete on no consumers for any queues created under this address, default = false") - boolean defaultDeleteOnNoConsumers = false; + String routingTypes = ActiveMQDefaultConfiguration.getDefaultRoutingType().name(); @Override public Object execute(ActionContext context) throws Exception { @@ -75,32 +69,12 @@ public class CreateAddress extends AbstractAction { return name; } - public String[] getRoutingTypes() { + public String getRoutingTypes() { return routingTypes; } public void setRoutingTypes(String routingTypes) { - String[] split = routingTypes.split(","); - this.routingTypes = new String[split.length]; - for (int i = 0; i < split.length; i++) { - RoutingType.valueOf(split[i].trim()); - this.routingTypes[i] = split[i].trim(); - } + this.routingTypes = routingTypes; } - public int getDefaultMaxConsumers() { - return defaultMaxConsumers; - } - - public void setDefaultMaxConsumers(int defaultMaxConsumers) { - this.defaultMaxConsumers = defaultMaxConsumers; - } - - public boolean getDefaultDeleteOnNoConsumers() { - return defaultDeleteOnNoConsumers; - } - - public void setDefaultDeleteOnNoConsumers(boolean defaultDeleteOnNoConsumers) { - this.defaultDeleteOnNoConsumers = defaultDeleteOnNoConsumers; - } } diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/DeleteAddress.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/DeleteAddress.java index 36c922451b..c63d4f97fa 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/DeleteAddress.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/DeleteAddress.java @@ -24,7 +24,7 @@ import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.cli.commands.AbstractAction; import org.apache.activemq.artemis.cli.commands.ActionContext; -@Command(name = "delete", description = "delete a queue") +@Command(name = "delete", description = "delete an address") public class DeleteAddress extends AbstractAction { @Option(name = "--name", description = "The name of this address") diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/RemoveRoutingType.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/RemoveRoutingType.java new file mode 100644 index 0000000000..637de6b37d --- /dev/null +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/RemoveRoutingType.java @@ -0,0 +1,78 @@ +/** + * 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.cli.commands.address; + +import io.airlift.airline.Command; +import io.airlift.airline.Option; +import org.apache.activemq.artemis.api.core.client.ClientMessage; +import org.apache.activemq.artemis.api.core.management.ManagementHelper; +import org.apache.activemq.artemis.cli.commands.AbstractAction; +import org.apache.activemq.artemis.cli.commands.ActionContext; + +@Command(name = "removeRoutingType", description = "remove the provided routing types from an address") +public class RemoveRoutingType extends AbstractAction { + + @Option(name = "--name", description = "The name of the address", required = true) + String name; + + @Option(name = "--routingType", description = "The routing types to be removed from this address, options are 'anycast' or 'multicast'", required = true) + String routingType; + + @Override + public Object execute(ActionContext context) throws Exception { + super.execute(context); + removeRoutingType(context); + return null; + } + + private void removeRoutingType(final ActionContext context) throws Exception { + performCoreManagement(new AbstractAction.ManagementCallback() { + @Override + public void setUpInvocation(ClientMessage message) throws Exception { + ManagementHelper.putOperationInvocation(message, "broker", "removeRoutingType", name, routingType); + } + + @Override + public void requestSuccessful(ClientMessage reply) throws Exception { + context.out.println("Address " + name + " updated successfully."); + } + + @Override + public void requestFailed(ClientMessage reply) throws Exception { + String errMsg = (String) ManagementHelper.getResult(reply, String.class); + context.err.println("Failed to update address " + name + ". Reason: " + errMsg); + } + }); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRoutingType() { + return routingType; + } + + public void setRoutingType(String routingType) { + this.routingType = routingType; + } +} diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/ShowAddress.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/ShowAddress.java index 013b504586..a736cf2ac5 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/ShowAddress.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/address/ShowAddress.java @@ -24,7 +24,7 @@ import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.cli.commands.AbstractAction; import org.apache.activemq.artemis.cli.commands.ActionContext; -@Command(name = "show", description = "delete a queue") +@Command(name = "show", description = "Get the selected address") public class ShowAddress extends AbstractAction { @Option(name = "--name", description = "The name of this address") @@ -53,7 +53,7 @@ public class ShowAddress extends AbstractAction { @Override public void requestSuccessful(ClientMessage reply) throws Exception { - String result = (String) ManagementHelper.getResult(reply, String.class); + final String result = (String) ManagementHelper.getResult(reply, String.class); context.out.println(result); } diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/CreateQueue.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/CreateQueue.java index 76cea6e947..c2497c9d75 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/CreateQueue.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/CreateQueue.java @@ -48,6 +48,9 @@ public class CreateQueue extends AbstractAction { @Option(name = "--autoCreateAddress", description = "Auto create the address (if it doesn't exist) with default values") boolean autoCreateAddress = false; + @Option(name = "--routingType", description = "The routing type supported by this queue, options are 'anycast' or 'multicast'", required = true) + String routingType; + @Override public Object execute(ActionContext context) throws Exception { super.execute(context); @@ -67,7 +70,7 @@ public class CreateQueue extends AbstractAction { @Override public void setUpInvocation(ClientMessage message) throws Exception { String address = getAddress(); - ManagementHelper.putOperationInvocation(message, "broker", "createQueue", address, getName(), filter, durable, maxConsumers, deleteOnNoConsumers, autoCreateAddress); + ManagementHelper.putOperationInvocation(message, "broker", "createQueue", address, routingType, getName(), filter, durable, maxConsumers, deleteOnNoConsumers, autoCreateAddress); } @Override @@ -114,4 +117,12 @@ public class CreateQueue extends AbstractAction { return name; } + + public void setRoutingType(String routingType) { + this.routingType = routingType; + } + + public String getRoutingType() { + return routingType; + } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java index abd8e9e82b..bec85ce47f 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java @@ -434,9 +434,17 @@ public interface ActiveMQServerControl { // Operations ---------------------------------------------------- - @Operation(desc = "delete an address", impact = MBeanOperationInfo.ACTION) + @Operation(desc = "create an address", impact = MBeanOperationInfo.ACTION) void createAddress(@Parameter(name = "name", desc = "The name of the address") String name, - @Parameter(name = "routingType", desc = "Comma separated list of Routing Typles (anycast/multicast)") String routingTypes) throws Exception; + @Parameter(name = "routingTypes", desc = "Comma separated list of Routing Typles (anycast/multicast)") String routingTypes) throws Exception; + + @Operation(desc = "add the provided routing type to an address", impact = MBeanOperationInfo.ACTION) + void addRoutingType(@Parameter(name = "name", desc = "The name of the address") String name, + @Parameter(name = "routingType", desc = "The routing types to be added to this address, options are 'anycast' or 'multicast'") String routingType) throws Exception; + + @Operation(desc = "remove the provided routing type to an address", impact = MBeanOperationInfo.ACTION) + void removeRoutingType(@Parameter(name = "name", desc = "The name of the address") String name, + @Parameter(name = "routingType", desc = "The routing types to be added to this address, options are 'anycast' or 'multicast'") String routingType) throws Exception; @Operation(desc = "delete an address", impact = MBeanOperationInfo.ACTION) void deleteAddress(@Parameter(name = "name", desc = "The name of the address") String name) throws Exception; @@ -1038,9 +1046,10 @@ public interface ActiveMQServerControl { @Operation(desc = "List the Network Topology", impact = MBeanOperationInfo.INFO) String listNetworkTopology() throws Exception; + @Operation(desc = "Get the selected address", impact = MBeanOperationInfo.INFO) String getAddressInfo(String address) throws ActiveMQAddressDoesNotExistException; @Operation(desc = "Get a list of bindings associated with an address", impact = MBeanOperationInfo.INFO) - String[] listBindingsForAddress(String address) throws Exception; + String listBindingsForAddress(String address) throws Exception; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java index 841aa84cb4..a43f28d97d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java @@ -42,6 +42,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; @@ -568,8 +569,8 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active clearIO(); try { Set set = new HashSet<>(); - for (Object routingType : toList(routingTypes)) { - set.add(RoutingType.valueOf(routingType.toString())); + for (String routingType : toList(routingTypes)) { + set.add(RoutingType.valueOf(routingType)); } server.createAddressInfo(new AddressInfo(new SimpleString(name), set)); } finally { @@ -577,6 +578,32 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active } } + @Override + public void addRoutingType(String name, String routingTypeName) throws Exception { + checkStarted(); + + clearIO(); + try { + final RoutingType routingType = RoutingType.valueOf(routingTypeName); + server.addRoutingType(name, routingType); + } finally { + blockOnIO(); + } + } + + @Override + public void removeRoutingType(String name, String routingTypeName) throws Exception { + checkStarted(); + + clearIO(); + try { + final RoutingType routingType = RoutingType.valueOf(routingTypeName); + server.removeRoutingType(name, routingType); + } finally { + blockOnIO(); + } + } + @Override public void deleteAddress(String name) throws Exception { checkStarted(); @@ -838,7 +865,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active clearIO(); try { - AddressInfo addressInfo = server.getAddressInfo(SimpleString.toSimpleString(address)); + final AddressInfo addressInfo = server.getAddressInfo(SimpleString.toSimpleString(address)); if (addressInfo == null) { throw ActiveMQMessageBundle.BUNDLE.addressDoesNotExist(SimpleString.toSimpleString(address)); } else { @@ -850,15 +877,16 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active } @Override - public String[] listBindingsForAddress(String address) throws Exception { - Bindings bindings = server.getPostOffice().getBindingsForAddress(new SimpleString(address)); - List result = new ArrayList<>(bindings.getBindings().size()); - - int i = 0; - for (Binding binding : bindings.getBindings()) { + public String listBindingsForAddress(String address) throws Exception { + checkStarted(); + clearIO(); + try { + final Bindings bindings = server.getPostOffice().getBindingsForAddress(new SimpleString(address)); + return bindings.getBindings().stream().map(Binding::toManagementString).collect(Collectors.joining(",")); + } finally { + blockOnIO(); } - return (String[]) result.toArray(); } @Override diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/AddressManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/AddressManager.java index ada1d77d7a..6ba205bf85 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/AddressManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/AddressManager.java @@ -18,6 +18,7 @@ package org.apache.activemq.artemis.core.postoffice; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.server.RoutingType; @@ -59,6 +60,9 @@ public interface AddressManager { AddressInfo addAddressInfo(AddressInfo addressInfo); + AddressInfo updateAddressInfoIfPresent(SimpleString addressName, + BiFunction remappingFunction); + AddressInfo addOrUpdateAddressInfo(AddressInfo addressInfo); AddressInfo removeAddressInfo(SimpleString address); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/PostOffice.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/PostOffice.java index dc5f4b4ce7..3c40475aff 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/PostOffice.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/PostOffice.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.server.ActiveMQComponent; @@ -52,6 +53,10 @@ public interface PostOffice extends ActiveMQComponent { AddressInfo getAddressInfo(SimpleString address); + void addRoutingType(SimpleString addressName, RoutingType routingType) throws ActiveMQAddressDoesNotExistException; + + void removeRoutingType(SimpleString addressName, RoutingType routingType) throws Exception; + List listQueuesForAddress(SimpleString address) throws Exception; void addBinding(Binding binding) throws Exception; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java index 16c3021c69..c7df757838 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java @@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; import org.apache.activemq.artemis.api.core.ActiveMQAddressFullException; import org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException; import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException; @@ -446,6 +447,39 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding } } + @Override + public void addRoutingType(SimpleString addressName, RoutingType routingType) throws ActiveMQAddressDoesNotExistException { + synchronized (addressLock) { + final AddressInfo updateAddressInfo = addressManager.updateAddressInfoIfPresent(addressName, (name, addressInfo) -> { + addressInfo.getRoutingTypes().add(routingType); + return addressInfo; + }); + if (updateAddressInfo == null) { + throw ActiveMQMessageBundle.BUNDLE.addressDoesNotExist(addressName); + } + } + } + + @Override + public void removeRoutingType(SimpleString addressName, RoutingType routingType) throws Exception { + synchronized (addressLock) { + if (RoutingType.MULTICAST.equals(routingType)) { + final Bindings bindings = addressManager.getBindingsForRoutingAddress(addressName); + final boolean existsQueueBindings = bindings.getBindings().stream().anyMatch(QueueBinding.class::isInstance); + if (existsQueueBindings) { + throw ActiveMQMessageBundle.BUNDLE.invalidMulticastRoutingTypeDelete(); + } + } + final AddressInfo updateAddressInfo = addressManager.updateAddressInfoIfPresent(addressName, (name, addressInfo) -> { + addressInfo.getRoutingTypes().remove(routingType); + return addressInfo; + }); + if (updateAddressInfo == null) { + throw ActiveMQMessageBundle.BUNDLE.addressDoesNotExist(addressName); + } + } + } + @Override public AddressInfo removeAddressInfo(SimpleString address) throws Exception { synchronized (addressLock) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/SimpleAddressManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/SimpleAddressManager.java index c0e5b2daf6..59f285c1e4 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/SimpleAddressManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/SimpleAddressManager.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.BiFunction; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.postoffice.Address; @@ -219,6 +220,12 @@ public class SimpleAddressManager implements AddressManager { return addressInfoMap.putIfAbsent(addressInfo.getName(), addressInfo); } + @Override + public AddressInfo updateAddressInfoIfPresent(SimpleString addressName, + BiFunction remappingFunction) { + return addressInfoMap.computeIfPresent(addressName, remappingFunction); + } + @Override public AddressInfo addOrUpdateAddressInfo(AddressInfo addressInfo) { AddressInfo from = addAddressInfo(addressInfo); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java index ee8f0efa63..5f533ff937 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java @@ -413,4 +413,7 @@ public interface ActiveMQMessageBundle { @Message(id = 119208, value = "Invalid routing type {0}", format = Message.Format.MESSAGE_FORMAT) IllegalArgumentException invalidRoutingType(String val); + + @Message(id = 119209, value = "Can't remove MULTICAST routing type, queues exists. Please delete queues before removing this routing type.") + IllegalStateException invalidMulticastRoutingTypeDelete(); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java index cc5e51e7c5..65d256a6f2 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java @@ -23,6 +23,7 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.config.BridgeConfiguration; import org.apache.activemq.artemis.core.config.Configuration; @@ -454,6 +455,25 @@ public interface ActiveMQServer extends ActiveMQComponent { void removeClientConnection(String clientId); + /** + * Add the {@code routingType} from the specified {@code address}. + * + * @param address the address name + * @param routingType the routing type to be added + * @throws ActiveMQAddressDoesNotExistException + */ + void addRoutingType(String address, RoutingType routingType) throws ActiveMQAddressDoesNotExistException; + + /** + * Remove the {@code routingType} from the specified {@code address}. + * + * @param address the address name + * @param routingType the routing type to be removed + * @throws ActiveMQAddressDoesNotExistException + * @throws IllegalStateException when a binding already exists and is requested to remove {@link org.apache.activemq.artemis.core.server.RoutingType#MULTICAST}. + */ + void removeRoutingType(String address, RoutingType routingType) throws Exception; + AddressInfo putAddressInfoIfAbsent(AddressInfo addressInfo) throws Exception; void createAddressInfo(AddressInfo addressInfo) throws Exception; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java index dcb4d45423..64fe2b7589 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java @@ -48,6 +48,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; import org.apache.activemq.artemis.api.core.ActiveMQDeleteAddressException; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; @@ -2395,6 +2396,18 @@ public class ActiveMQServerImpl implements ActiveMQServer { } } + @Override + public void addRoutingType(String address, RoutingType routingType) throws ActiveMQAddressDoesNotExistException { + final SimpleString addressName = new SimpleString(address); + postOffice.addRoutingType(addressName,routingType); + } + + @Override + public void removeRoutingType(String address, RoutingType routingType) throws Exception { + final SimpleString addressName = new SimpleString(address); + postOffice.removeRoutingType(addressName,routingType); + } + @Override public AddressInfo putAddressInfoIfAbsent(AddressInfo addressInfo) throws Exception { AddressInfo result = postOffice.addAddressInfo(addressInfo); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/AddressCommandTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/AddressCommandTest.java index 6c373ec311..226cfbc28c 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/AddressCommandTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/AddressCommandTest.java @@ -18,12 +18,15 @@ package org.apache.activemq.artemis.tests.integration.cli; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.EnumSet; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.cli.commands.AbstractAction; import org.apache.activemq.artemis.cli.commands.ActionContext; +import org.apache.activemq.artemis.cli.commands.address.AddRoutingType; import org.apache.activemq.artemis.cli.commands.address.CreateAddress; import org.apache.activemq.artemis.cli.commands.address.DeleteAddress; +import org.apache.activemq.artemis.cli.commands.address.RemoveRoutingType; import org.apache.activemq.artemis.cli.commands.address.ShowAddress; import org.apache.activemq.artemis.core.config.DivertConfiguration; import org.apache.activemq.artemis.core.server.RoutingType; @@ -97,6 +100,20 @@ public class AddressCommandTest extends JMSTestBase { checkExecutionFailure(deleteAddress, "Address Does Not Exist"); } + @Test + public void testFailDeleteAddressWhenExistsQueues() throws Exception { + final String addressName = "address"; + final SimpleString addressSimpleString = new SimpleString(addressName); + final AddressInfo addressInfo = new AddressInfo(addressSimpleString, EnumSet.of(RoutingType.ANYCAST, RoutingType.MULTICAST)); + server.createAddressInfo(addressInfo); + server.createQueue(addressSimpleString, RoutingType.MULTICAST, new SimpleString("queue1"), null, true, false); + + final DeleteAddress deleteAddress = new DeleteAddress(); + deleteAddress.setName(addressName); + deleteAddress.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionFailure(deleteAddress, "Address " + addressName + " has bindings"); + } + @Test public void testShowAddress() throws Exception { String address = "address"; @@ -142,6 +159,79 @@ public class AddressCommandTest extends JMSTestBase { System.out.println(output.toString()); } + @Test + public void testAddRoutingType() throws Exception { + final String addressName = "address"; + final SimpleString address = new SimpleString(addressName); + server.createAddressInfo(new AddressInfo(address, RoutingType.ANYCAST)); + + final AddRoutingType addRoutingType = new AddRoutingType(); + addRoutingType.setName(addressName); + addRoutingType.setRoutingType(RoutingType.MULTICAST.toString()); + addRoutingType.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionPassed(addRoutingType); + + final AddressInfo addressInfo = server.getAddressInfo(address); + assertNotNull(addressInfo); + assertEquals(EnumSet.of(RoutingType.ANYCAST, RoutingType.MULTICAST), addressInfo.getRoutingTypes()); + } + + @Test + public void testFailAddRoutingTypeAddressDoesNotExist() throws Exception { + final String addressName = "address"; + final AddRoutingType addRoutingType = new AddRoutingType(); + addRoutingType.setName(addressName); + addRoutingType.setRoutingType(RoutingType.MULTICAST.toString()); + addRoutingType.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionFailure(addRoutingType, "Address Does Not Exist"); + final AddressInfo addressInfo = server.getAddressInfo(new SimpleString(addressName)); + assertNull(addressInfo); + } + + @Test + public void testRemoveRoutingType() throws Exception { + final String addressName = "address"; + final SimpleString address = new SimpleString(addressName); + server.createAddressInfo(new AddressInfo(address, EnumSet.of(RoutingType.ANYCAST, RoutingType.MULTICAST))); + + final RemoveRoutingType removeRoutingType = new RemoveRoutingType(); + removeRoutingType.setName(addressName); + removeRoutingType.setRoutingType(RoutingType.MULTICAST.toString()); + removeRoutingType.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionPassed(removeRoutingType); + + final AddressInfo addressInfo = server.getAddressInfo(new SimpleString(addressName)); + assertNotNull(addressInfo); + assertEquals(EnumSet.of(RoutingType.ANYCAST), addressInfo.getRoutingTypes()); + } + + @Test + public void testFailRemoveRoutingTypeAddressDoesNotExist() throws Exception { + final String addressName = "address"; + final RemoveRoutingType removeRoutingType = new RemoveRoutingType(); + removeRoutingType.setName(addressName); + removeRoutingType.setRoutingType(RoutingType.MULTICAST.toString()); + removeRoutingType.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionFailure(removeRoutingType, "Address Does Not Exist"); + final AddressInfo addressInfo = server.getAddressInfo(new SimpleString(addressName)); + assertNull(addressInfo); + } + + @Test + public void testFailRemoveMulticastRoutingTypeWhenExistsQueues() throws Exception { + final String addressName = "address"; + final SimpleString addressSimpleString = new SimpleString(addressName); + final AddressInfo addressInfo = new AddressInfo(addressSimpleString, EnumSet.of(RoutingType.ANYCAST, RoutingType.MULTICAST)); + server.createAddressInfo(addressInfo); + server.createQueue(addressSimpleString, RoutingType.MULTICAST, new SimpleString("queue1"), null, true, false); + + final RemoveRoutingType removeRoutingType = new RemoveRoutingType(); + removeRoutingType.setName(addressName); + removeRoutingType.setRoutingType(RoutingType.MULTICAST.toString()); + removeRoutingType.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); + checkExecutionFailure(removeRoutingType, "Can't remove MULTICAST routing type, queues exists. Please delete queues before removing this routing type."); + } + private void checkExecutionPassed(AbstractAction command) throws Exception { String fullMessage = output.toString(); System.out.println("output: " + fullMessage); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/QueueCommandTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/QueueCommandTest.java index 9bddb8c606..b7f1bd62e9 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/QueueCommandTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/QueueCommandTest.java @@ -26,6 +26,7 @@ import org.apache.activemq.artemis.cli.commands.queue.CreateQueue; import org.apache.activemq.artemis.cli.commands.queue.DeleteQueue; import org.apache.activemq.artemis.cli.commands.AbstractAction; import org.apache.activemq.artemis.core.server.Queue; +import org.apache.activemq.artemis.core.server.RoutingType; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.tests.util.JMSTestBase; import org.junit.Before; @@ -50,6 +51,7 @@ public class QueueCommandTest extends JMSTestBase { String queueName = "queue1"; CreateQueue command = new CreateQueue(); command.setName(queueName); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); checkExecutionFailure(command, "AMQ119203: Address Does Not Exist:"); assertFalse(server.queueQuery(new SimpleString(queueName)).isExists()); @@ -61,6 +63,7 @@ public class QueueCommandTest extends JMSTestBase { CreateQueue command = new CreateQueue(); command.setName(queueName); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); checkExecutionPassed(command); assertNotNull(server.getAddressInfo(new SimpleString(queueName))); @@ -79,9 +82,10 @@ public class QueueCommandTest extends JMSTestBase { CreateQueue command = new CreateQueue(); command.setName(queueName); command.setAutoCreateAddress(false); + command.setRoutingType(RoutingType.MULTICAST.name()); command.setAddress(address); - server.createOrUpdateAddressInfo(new AddressInfo(new SimpleString(address))); + server.createOrUpdateAddressInfo(new AddressInfo(new SimpleString(address), RoutingType.MULTICAST)); command.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); checkExecutionPassed(command); @@ -102,6 +106,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); checkExecutionPassed(command); @@ -119,6 +124,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext()); command.execute(new ActionContext(System.in, new PrintStream(output), new PrintStream(error))); checkExecutionFailure(command, "AMQ119019: Queue already exists " + queueName); @@ -132,6 +138,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName.toString()); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext()); DeleteQueue delete = new DeleteQueue(); @@ -162,6 +169,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName.toString()); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext()); server.locateQueue(queueName).addConsumer(new DummyServerConsumer()); @@ -180,6 +188,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName.toString()); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext()); server.locateQueue(queueName).addConsumer(new DummyServerConsumer()); @@ -199,6 +208,7 @@ public class QueueCommandTest extends JMSTestBase { command.setName(queueName.toString()); command.setFilter("color='green'"); command.setAutoCreateAddress(true); + command.setRoutingType(RoutingType.MULTICAST.name()); command.execute(new ActionContext()); assertNotNull(server.getAddressInfo(queueName)); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java index 2831f79179..08e37d2057 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java @@ -58,6 +58,17 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes @Override protected ActiveMQServerControl createManagementControl() throws Exception { return new ActiveMQServerControl() { + + @Override + public void addRoutingType(String name, String routingType) throws Exception { + proxy.invokeOperation("addRoutingType", name, routingType); + } + + @Override + public void removeRoutingType(String name, String routingType) throws Exception { + proxy.invokeOperation("removeRoutingType", name, routingType); + } + @Override public void updateDuplicateIdCache(String address, Object[] ids) { @@ -707,8 +718,8 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes } @Override - public String[] listBindingsForAddress(String address) throws Exception { - return new String[0]; + public String listBindingsForAddress(String address) throws Exception { + return ""; } @Override diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/fakes/FakePostOffice.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/fakes/FakePostOffice.java index 918ff41aa8..a93cc3c254 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/fakes/FakePostOffice.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/fakes/FakePostOffice.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.activemq.artemis.api.core.ActiveMQAddressDoesNotExistException; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.persistence.impl.nullpm.NullStorageManager; @@ -40,6 +41,17 @@ import org.apache.activemq.artemis.core.transaction.Transaction; public class FakePostOffice implements PostOffice { + @Override + public void addRoutingType(SimpleString addressName, + RoutingType routingType) throws ActiveMQAddressDoesNotExistException { + + } + + @Override + public void removeRoutingType(SimpleString addressName, RoutingType routingType) throws Exception { + + } + @Override public boolean isStarted() {