diff --git a/server/integration/feature-pack/src/main/resources/modules/system/layers/base/org/infinispan/counter/main/module.xml b/server/integration/feature-pack/src/main/resources/modules/system/layers/base/org/infinispan/counter/main/module.xml
index 32eb41341776..0a1205786518 100644
--- a/server/integration/feature-pack/src/main/resources/modules/system/layers/base/org/infinispan/counter/main/module.xml
+++ b/server/integration/feature-pack/src/main/resources/modules/system/layers/base/org/infinispan/counter/main/module.xml
@@ -11,4 +11,4 @@
-
\ No newline at end of file
+
diff --git a/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/SecurityActions.java b/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/SecurityActions.java
index a247c2675380..96b191341986 100644
--- a/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/SecurityActions.java
+++ b/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/SecurityActions.java
@@ -6,12 +6,15 @@
import java.security.PrivilegedExceptionAction;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.cli.interpreter.Interpreter;
import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.counter.EmbeddedCounterManagerFactory;
+import org.infinispan.counter.api.CounterManager;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.interceptors.AsyncInterceptor;
@@ -306,5 +309,9 @@ public static Set getSitesView(DefaultCacheContainer cacheManager) {
GetSitesViewAction action = new GetSitesViewAction(cacheManager);
return doPrivileged(action);
}
+
+ public static Optional findCounterManager(EmbeddedCacheManager cacheManager) {
+ return Optional.ofNullable(doPrivileged((PrivilegedAction) () -> EmbeddedCounterManagerFactory.asCounterManager(cacheManager)));
+ }
}
diff --git a/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/spi/service/CounterServiceName.java b/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/spi/service/CounterServiceName.java
new file mode 100644
index 000000000000..600afc283c76
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/infinispan/server/infinispan/spi/service/CounterServiceName.java
@@ -0,0 +1,16 @@
+package org.infinispan.server.infinispan.spi.service;
+
+import org.jboss.msc.service.ServiceName;
+
+/**
+ * Enumeration of service name factories for services associated with a counter.
+ *
+ * @author Vladimir Blagojevic
+ */
+public class CounterServiceName {
+
+ public static ServiceName getServiceName(String container, String counterName) {
+ return CacheContainerServiceName.CACHE_CONTAINER.getServiceName(container).append(counterName);
+ }
+
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Attribute.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Attribute.java
index 96deedb231bd..82b59279f47f 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Attribute.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Attribute.java
@@ -90,6 +90,7 @@ public enum Attribute {
INDEX(ModelKeys.INDEX),
INITIAL_CLUSTER_SIZE(ModelKeys.INITIAL_CLUSTER_SIZE),
INITIAL_CLUSTER_TIMEOUT(ModelKeys.INITIAL_CLUSTER_TIMEOUT),
+ INITIAL_VALUE(ModelKeys.INITIAL_VALUE),
INTERVAL(ModelKeys.INTERVAL),
ISOLATION(ModelKeys.ISOLATION),
JNDI_NAME(ModelKeys.JNDI_NAME),
@@ -100,6 +101,7 @@ public enum Attribute {
LISTENER_EXECUTOR(ModelKeys.LISTENER_EXECUTOR),
LOCK_TIMEOUT(ModelKeys.LOCK_TIMEOUT),
LOCKING(ModelKeys.LOCKING),
+ LOWER_BOUND(ModelKeys.LOWER_BOUND),
MACHINE(ModelKeys.MACHINE),
MAPPER(ModelKeys.MAPPER),
MARSHALLER(ModelKeys.MARSHALLER),
@@ -120,6 +122,7 @@ public enum Attribute {
MODULE(ModelKeys.MODULE),
NAME(ModelKeys.NAME),
NAMESPACE(XMLConstants.XMLNS_ATTRIBUTE),
+ NUM_OWNERS(ModelKeys.NUM_OWNERS),
NOTIFICATIONS(ModelKeys.NOTIFICATIONS),
OUTBOUND_SOCKET_BINDING(ModelKeys.OUTBOUND_SOCKET_BINDING),
OWNERS(ModelKeys.OWNERS),
@@ -140,6 +143,7 @@ public enum Attribute {
READ_ONLY(ModelKeys.READ_ONLY),
REALM(ModelKeys.REALM),
RELATIVE_TO(ModelKeys.RELATIVE_TO),
+ RELIABILITY(ModelKeys.RELIABILITY),
REMOTE_CACHE(ModelKeys.REMOTE_CACHE),
@Deprecated
REMOTE_COMMAND_EXECUTOR(ModelKeys.REMOTE_COMMAND_EXECUTOR),
@@ -168,6 +172,7 @@ public enum Attribute {
STATISTICS_AVAILABLE(ModelKeys.STATISTICS_AVAILABLE),
STRICT_PEER_TO_PEER(ModelKeys.STRICT_PEER_TO_PEER),
STOP_TIMEOUT(ModelKeys.STOP_TIMEOUT),
+ STORAGE(ModelKeys.STORAGE),
STRATEGY(ModelKeys.STRATEGY),
STRIPING(ModelKeys.STRIPING),
TAKE_BACKUP_OFFLINE_AFTER_FAILURES(ModelKeys.TAKE_BACKUP_OFFLINE_AFTER_FAILURES),
@@ -179,6 +184,8 @@ public enum Attribute {
TOTAL_ORDER_EXECUTOR(ModelKeys.TOTAL_ORDER_EXECUTOR),
TYPE(ModelKeys.TYPE),
USERNAME(ModelKeys.USERNAME),
+ UPPER_BOUND(ModelKeys.UPPER_BOUND),
+ VALUE(ModelKeys.VALUE),
WAIT_TIME(ModelKeys.WAIT_TIME),
WHEN_SPLIT(ModelKeys.WHEN_SPLIT),
;
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerCountersResource.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerCountersResource.java
new file mode 100644
index 000000000000..653f99bab598
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerCountersResource.java
@@ -0,0 +1,64 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.infinispan.counter.configuration.CounterManagerConfigurationBuilder;
+import org.infinispan.counter.configuration.Reliability;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.registry.AttributeAccess;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.as.controller.services.path.ResolvePathHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * CacheContainerCountersResource
+ *
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class CacheContainerCountersResource extends SimpleResourceDefinition {
+ static final PathElement PATH = PathElement.pathElement(ModelKeys.COUNTERS, ModelKeys.COUNTERS_NAME);
+
+ //attributes
+ static final SimpleAttributeDefinition RELIABILITY = new SimpleAttributeDefinitionBuilder(ModelKeys.RELIABILITY,
+ ModelType.STRING, false)
+ .setXmlName(Attribute.RELIABILITY.getLocalName())
+ .setAllowExpression(false)
+ .setAllowedValues(Reliability.AVAILABLE.toString(), Reliability.CONSISTENT.toString())
+ .setDefaultValue(new ModelNode().set(CounterManagerConfigurationBuilder.defaultConfiguration().reliability().toString()))
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .build();
+
+ static final SimpleAttributeDefinition NUM_OWNERS = new SimpleAttributeDefinitionBuilder(ModelKeys.NUM_OWNERS,
+ ModelType.LONG, false)
+ .setXmlName(Attribute.NUM_OWNERS.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .setDefaultValue(new ModelNode().set(CounterManagerConfigurationBuilder.defaultConfiguration().numOwners()))
+ .build();
+
+ private final boolean runtimeRegistration;
+
+ CacheContainerCountersResource(ResolvePathHandler resolvePathHandler, boolean runtimeRegistration) {
+ super(PATH, new InfinispanResourceDescriptionResolver(ModelKeys.CACHE_CONTAINER, ModelKeys.COUNTERS),
+ CacheConfigOperationHandlers.CONTAINER_CONFIGURATIONS_ADD, ReloadRequiredRemoveStepHandler.INSTANCE);
+ this.runtimeRegistration = runtimeRegistration;
+ }
+
+ @Override
+ public void registerChildren(ManagementResourceRegistration rr) {
+ rr.registerSubModel(new StrongCounterResource(runtimeRegistration));
+ rr.registerSubModel(new WeakCounterResource(runtimeRegistration));
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+ if (runtimeRegistration) {
+ CountersMetricsHandler.INSTANCE.registerMetrics(resourceRegistration);
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerResource.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerResource.java
index a09f8521fec2..5289ec8579c7 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerResource.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CacheContainerResource.java
@@ -403,5 +403,6 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
resourceRegistration.registerSubModel(new InvalidationCacheResource(resolvePathHandler, runtimeRegistration));
resourceRegistration.registerSubModel(new ReplicatedCacheResource(resolvePathHandler, runtimeRegistration));
resourceRegistration.registerSubModel(new DistributedCacheResource(resolvePathHandler, runtimeRegistration));
+ resourceRegistration.registerSubModel(new CacheContainerCountersResource(resolvePathHandler, runtimeRegistration));
}
}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterAddHandler.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterAddHandler.java
new file mode 100644
index 000000000000..6f66d7f2d3e3
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterAddHandler.java
@@ -0,0 +1,164 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.infinispan.counter.api.CounterConfiguration;
+import org.infinispan.counter.api.CounterConfiguration.Builder;
+import org.infinispan.counter.api.CounterType;
+import org.infinispan.counter.api.Storage;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.server.infinispan.spi.service.CacheContainerServiceName;
+import org.infinispan.server.infinispan.spi.service.CounterServiceName;
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.Service;
+import org.jboss.msc.service.ServiceBuilder;
+import org.jboss.msc.service.ServiceController;
+import org.jboss.msc.service.ServiceTarget;
+import org.jboss.msc.value.InjectedValue;
+
+/**
+ * Add operation handler for /subsystem=infinispan/cache-container=clustered/counter=*
+ *
+ * @author Vladimir Blagojevic
+ *
+ */
+public class CounterAddHandler extends AbstractAddStepHandler implements RestartableServiceHandler{
+
+ CounterAddHandler() {
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model)
+ throws OperationFailedException {
+
+ super.performRuntime(context, operation, model);
+
+ this.installRuntimeServices(context, operation, model, null);
+ }
+
+ @Override
+ public Collection> installRuntimeServices(OperationContext context, ModelNode operation,
+ ModelNode containerModel, ModelNode cacheModel) throws OperationFailedException {
+
+ String counterName = getCounterName(operation);
+ String containerName = getContainerName(operation);
+ String counterType = getCounterType(operation);
+
+ Builder b = getBuilder(containerModel, counterType);
+ processModelNode(context, containerModel, b);
+ String name = CounterResource.COUNTER_NAME.resolveModelAttribute(context, containerModel).asString();
+ if (!counterName.equals(name)) {
+ throw new OperationFailedException("Counter node name and node's name attribute should be the same");
+ }
+
+ // wire counter service for this counter
+ Collection> controllers = new ArrayList<>(1);
+ ServiceController> service = this.installCounterService(context.getServiceTarget(),
+ containerName, counterName, b.build());
+ controllers.add(service);
+
+ return controllers;
+ }
+
+ @Override
+ public void removeRuntimeServices(OperationContext context, ModelNode operation, ModelNode containerModel,
+ ModelNode cacheModel) throws OperationFailedException {
+
+ String counterName = getCounterName(operation);
+ String containerName = getContainerName(operation);
+
+ context.removeService(CounterServiceName.getServiceName(containerName, counterName));
+ }
+
+ private ServiceController> installCounterService(ServiceTarget target, String containerName,
+ String configurationName, CounterConfiguration configuration) {
+ final InjectedValue container = new InjectedValue<>();
+ final CounterConfigurationDependencies dependencies = new CounterConfigurationDependencies(container);
+ final Service> service = new CounterService(configuration, configurationName, dependencies);
+ final ServiceBuilder> builder = target.addService(CounterServiceName.getServiceName(containerName, configurationName), service)
+ .addDependency(CacheContainerServiceName.CACHE_CONTAINER.getServiceName(containerName), EmbeddedCacheManager.class, container);
+ return builder.install();
+ }
+
+ @Override
+ protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
+ this.populate(operation, model);
+ }
+
+ void populate(ModelNode fromModel, ModelNode toModel) throws OperationFailedException {
+ for (AttributeDefinition attr : CounterResource.ATTRIBUTES) {
+ attr.validateAndSet(fromModel, toModel);
+ }
+ }
+
+ private String getCounterName(ModelNode operation) {
+ PathAddress counterAddress = getCounterAddressFromOperation(operation);
+ return counterAddress.getLastElement().getValue();
+ }
+
+ private String getContainerName(ModelNode operation) {
+ PathAddress containerAddress = getCacheContainerAddressFromOperation(operation);
+ return containerAddress.getLastElement().getValue();
+ }
+
+ private PathAddress getCacheContainerAddressFromOperation(ModelNode operation) {
+ PathAddress counterAddress = getCounterAddressFromOperation(operation);
+ return counterAddress.subAddress(0, counterAddress.size() - 2);
+ }
+
+ private String getCounterType(ModelNode operation) {
+ PathAddress counterAddress = getCounterAddressFromOperation(operation);
+ int size = counterAddress.size();
+ PathAddress subAddress = counterAddress.subAddress(size - 1, size);
+ return subAddress.getLastElement().getKey();
+ }
+
+ private PathAddress getCounterAddressFromOperation(ModelNode operation) {
+ return PathAddress.pathAddress(operation.get(OP_ADDR));
+ }
+
+ private Builder getBuilder(ModelNode counter, String counterType) {
+ boolean isWeakCounter = ModelKeys.WEAK_COUNTER.equals(counterType);
+ if (isWeakCounter) {
+ return CounterConfiguration.builder(CounterType.WEAK);
+ } else {
+ ModelNode lowerBoundModel = counter.get(ModelKeys.LOWER_BOUND);
+ ModelNode upperBoundModel = counter.get(ModelKeys.UPPER_BOUND);
+ boolean isBounded = lowerBoundModel.isDefined() || upperBoundModel.isDefined();
+ return isBounded ? CounterConfiguration.builder(CounterType.BOUNDED_STRONG)
+ : CounterConfiguration.builder(CounterType.UNBOUNDED_STRONG);
+ }
+ }
+
+ void processModelNode(OperationContext context, ModelNode counter,
+ CounterConfiguration.Builder builder) throws OperationFailedException {
+
+ long initialValue = CounterResource.INITIAL_VALUE.resolveModelAttribute(context, counter).asLong();
+ String storageType = CounterResource.STORAGE.resolveModelAttribute(context, counter).asString();
+
+ builder.initialValue(initialValue);
+ builder.storage(Storage.valueOf(storageType));
+ }
+
+ private static class CounterConfigurationDependencies implements CounterService.Dependencies {
+
+ private InjectedValue container;
+ public CounterConfigurationDependencies(InjectedValue container) {
+ this.container = container;
+ }
+
+ @Override
+ public EmbeddedCacheManager getCacheContainer() {
+ return this.container.getValue();
+ }
+
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterMetricsHandler.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterMetricsHandler.java
new file mode 100644
index 000000000000..d193156af83a
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterMetricsHandler.java
@@ -0,0 +1,84 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+
+import org.infinispan.counter.EmbeddedCounterManagerFactory;
+import org.infinispan.counter.api.CounterManager;
+import org.infinispan.counter.api.StrongCounter;
+import org.infinispan.counter.api.WeakCounter;
+import org.infinispan.server.infinispan.spi.service.CacheContainerServiceName;
+import org.jboss.as.clustering.infinispan.DefaultCacheContainer;
+import org.jboss.as.controller.AbstractRuntimeOnlyHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+import org.jboss.msc.service.ServiceController;
+
+/**
+ * Reflects runtime Counter attributes
+ *
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class CounterMetricsHandler extends AbstractRuntimeOnlyHandler {
+
+ public static final CounterMetricsHandler INSTANCE = new CounterMetricsHandler();
+
+ private static final int CACHE_CONTAINER_INDEX = 1;
+ private static final int COUNTER_INDEX = 3;
+
+ @Override
+ protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException {
+
+ final ModelNode result = new ModelNode();
+ final PathAddress address = PathAddress.pathAddress(operation.require(OP_ADDR));
+ final String cacheContainerName = address.getElement(CACHE_CONTAINER_INDEX).getValue();
+ final String counterType = address.getElement(COUNTER_INDEX).getKey();
+ final String counterName = address.getElement(COUNTER_INDEX).getValue();
+ final ServiceController> controller = context.getServiceRegistry(false)
+ .getService(CacheContainerServiceName.CACHE_CONTAINER.getServiceName(cacheContainerName));
+
+ Long value = null;
+ if (controller != null) {
+ DefaultCacheContainer cacheManager = (DefaultCacheContainer) controller.getValue();
+ CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(cacheManager);
+ if (ModelKeys.STRONG_COUNTER.equals(counterType)) {
+ StrongCounter sc = counterManager.getStrongCounter(counterName);
+ value = sc.sync().getValue();
+ } else {
+ WeakCounter wc = counterManager.getWeakCounter(counterName);
+ value = wc.sync().getValue();
+ }
+ result.set(value);
+ }
+ context.getResult().set(result);
+ }
+
+ public void registerMetrics(ManagementResourceRegistration container) {
+ for (CounterMetrics metric : CounterMetrics.values()) {
+ container.registerMetric(metric.definition, this);
+ }
+ }
+
+ public enum CounterMetrics {
+
+ VALUE(MetricKeys.VALUE, ModelType.LONG);
+
+ final AttributeDefinition definition;
+
+ CounterMetrics(String attributeName, ModelType type) {
+ this.definition = new SimpleAttributeDefinitionBuilder(attributeName, type).setAllowNull(false)
+ .setStorageRuntime().build();
+ }
+
+ @Override
+ public final String toString() {
+ return definition.getName();
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterResource.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterResource.java
new file mode 100644
index 000000000000..9502128811a2
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterResource.java
@@ -0,0 +1,235 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import static org.jboss.as.controller.PathAddress.pathAddress;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+
+import java.util.Optional;
+
+import org.infinispan.counter.api.CounterManager;
+import org.infinispan.counter.api.Storage;
+import org.infinispan.counter.api.StrongCounter;
+import org.infinispan.counter.api.WeakCounter;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.server.infinispan.SecurityActions;
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.AbstractRemoveStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationDefinition;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.descriptions.ResourceDescriptionResolver;
+import org.jboss.as.controller.registry.AttributeAccess;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Resource description for the addressable resource
+ * /subsystem=infinispan/cache-container=X/counter=COUNTERS
+ *
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class CounterResource extends SimpleResourceDefinition {
+
+ //attributes
+ static final SimpleAttributeDefinition COUNTER_NAME = new SimpleAttributeDefinitionBuilder(ModelKeys.NAME,
+ ModelType.STRING, false)
+ .setXmlName(Attribute.NAME.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .build();
+
+ static final SimpleAttributeDefinition STORAGE = new SimpleAttributeDefinitionBuilder(ModelKeys.STORAGE,
+ ModelType.STRING, false)
+ .setXmlName(Attribute.STORAGE.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .setAllowedValues(Storage.VOLATILE.toString(), Storage.PERSISTENT.toString())
+ .setDefaultValue(new ModelNode().set(Storage.VOLATILE.toString()))
+ .build();
+
+ static final SimpleAttributeDefinition INITIAL_VALUE = new SimpleAttributeDefinitionBuilder(ModelKeys.INITIAL_VALUE,
+ ModelType.LONG, true)
+ .setXmlName(Attribute.INITIAL_VALUE.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .setDefaultValue(new ModelNode().set(0))
+ .build();
+
+ static final AttributeDefinition[] ATTRIBUTES = { COUNTER_NAME, STORAGE, INITIAL_VALUE };
+
+ // operations
+
+ private static final OperationDefinition COUNTER_RESET = buildOperation("counter-reset").build();
+ private static final OperationDefinition COUNTER_INCREASE = buildOperation("counter-increase").build();
+ private static final OperationDefinition COUNTER_DECREASE = buildOperation("counter-decrease").build();
+
+ private final boolean runtimeRegistration;
+
+ public CounterResource(PathElement pathElement, ResourceDescriptionResolver descriptionResolver,
+ AbstractAddStepHandler addHandler, OperationStepHandler removeHandler, boolean runtimeRegistration) {
+ super(pathElement, descriptionResolver, addHandler, removeHandler);
+ this.runtimeRegistration = runtimeRegistration;
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+ for (AttributeDefinition attr : ATTRIBUTES) {
+ resourceRegistration.registerReadOnlyAttribute(attr, null);
+ }
+
+ if (runtimeRegistration) {
+ CounterMetricsHandler.INSTANCE.registerMetrics(resourceRegistration);
+ }
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ if (runtimeRegistration) {
+ resourceRegistration.registerOperationHandler(CounterResource.COUNTER_RESET, CounterResetCommand.INSTANCE);
+ resourceRegistration.registerOperationHandler(CounterResource.COUNTER_INCREASE,
+ CounterIncreaseCommand.INSTANCE);
+ resourceRegistration.registerOperationHandler(CounterResource.COUNTER_DECREASE,
+ CounterDecreaseCommand.INSTANCE);
+ }
+ }
+
+ private static SimpleOperationDefinitionBuilder buildOperation(String name) {
+ return new SimpleOperationDefinitionBuilder(name, new InfinispanResourceDescriptionResolver(ModelKeys.COUNTERS))
+ .setRuntimeOnly();
+ }
+
+ private static PathElement counterElement(ModelNode operation) {
+ final PathAddress address = pathAddress(operation.require(OP_ADDR));
+ final PathElement counterElement = address.getElement(address.size() - 1);
+ return counterElement;
+ }
+
+ private static String counterName(ModelNode operation) {
+ PathElement counterElement = counterElement(operation);
+ return counterElement.getValue();
+ }
+
+ private static String counterType(ModelNode operation) {
+ PathElement counterElement = counterElement(operation);
+ return counterElement.getKey();
+ }
+
+ private static OperationFailedException counterManagerNotFound() {
+ return new OperationFailedException("CounterManager not found in server.");
+ }
+
+ public static class CounterRemoveHandler extends AbstractRemoveStepHandler {
+
+ private final CounterAddHandler handler;
+
+ public CounterRemoveHandler() {
+ handler = new CounterAddHandler();
+ }
+
+ @Override
+ protected void performRuntime(final OperationContext context, final ModelNode operation, final ModelNode model) throws OperationFailedException {
+ handler.removeRuntimeServices(context, operation, null, null);
+ }
+
+ @Override
+ protected void recoverServices(final OperationContext context, final ModelNode operation, final ModelNode model) throws OperationFailedException {
+ handler.performRuntime(context, operation, model);
+ }
+ }
+
+ private static class CounterResetCommand extends BaseCounterManagerCommand {
+ private static final CounterResetCommand INSTANCE = new CounterResetCommand();
+
+ @Override
+ protected ModelNode invoke(CounterManager counterManager, ModelNode operation)
+ throws Exception {
+ final String counterName = counterName(operation);
+ final String counterType = counterType(operation);
+ if (counterManager.isDefined(counterName)) {
+ boolean isStrongCounter = ModelKeys.STRONG_COUNTER.equals(counterType);
+ if (isStrongCounter) {
+ StrongCounter strongCounter = counterManager.getStrongCounter(counterName);
+ strongCounter.sync().reset();
+ } else {
+ WeakCounter weakCounter = counterManager.getWeakCounter(counterName);
+ weakCounter.sync().reset();
+ }
+ }
+ return new ModelNode();
+ }
+ }
+
+ private static class CounterIncreaseCommand extends BaseCounterManagerCommand {
+ private static final CounterIncreaseCommand INSTANCE = new CounterIncreaseCommand();
+
+ @Override
+ protected ModelNode invoke(CounterManager counterManager, ModelNode operation)
+ throws Exception {
+ final String counterName = counterName(operation);
+ final String counterType = counterType(operation);
+ if (counterManager.isDefined(counterName)) {
+ boolean isStrongCounter = ModelKeys.STRONG_COUNTER.equals(counterType);
+ if (isStrongCounter) {
+ StrongCounter strongCounter = counterManager.getStrongCounter(counterName);
+ strongCounter.sync().incrementAndGet();
+ } else {
+ WeakCounter weakCounter = counterManager.getWeakCounter(counterName);
+ weakCounter.sync().increment();
+ }
+ }
+ return new ModelNode();
+ }
+ }
+
+ private static class CounterDecreaseCommand extends BaseCounterManagerCommand {
+ private static final CounterDecreaseCommand INSTANCE = new CounterDecreaseCommand();
+
+ @Override
+ protected ModelNode invoke(CounterManager counterManager, ModelNode operation)
+ throws Exception {
+ final String counterName = counterName(operation);
+ final String counterType = counterType(operation);
+ if (counterManager.isDefined(counterName)) {
+ boolean isStrongCounter = ModelKeys.STRONG_COUNTER.equals(counterType);
+ if (isStrongCounter) {
+ StrongCounter strongCounter = counterManager.getStrongCounter(counterName);
+ strongCounter.sync().decrementAndGet();
+ } else {
+ WeakCounter weakCounter = counterManager.getWeakCounter(counterName);
+ weakCounter.sync().decrement();
+ }
+ }
+ return new ModelNode();
+ }
+ }
+
+ private static abstract class BaseCounterManagerCommand extends CacheContainerCommands {
+
+ BaseCounterManagerCommand() {
+ //path to container from counter address has two elements
+ super(2);
+ }
+
+ abstract ModelNode invoke(CounterManager counterManager, ModelNode operation)
+ throws Exception;
+
+ @Override
+ protected final ModelNode invokeCommand(EmbeddedCacheManager cacheManager, OperationContext context,
+ ModelNode operation) throws Exception {
+ Optional optCounterManager = SecurityActions.findCounterManager(cacheManager);
+ CounterManager counterManager = optCounterManager.orElseThrow(CounterResource::counterManagerNotFound);
+ return invoke(counterManager, operation);
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterService.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterService.java
new file mode 100644
index 000000000000..a9519aea79f4
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CounterService.java
@@ -0,0 +1,74 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.infinispan.counter.EmbeddedCounterManagerFactory;
+import org.infinispan.counter.api.CounterConfiguration;
+import org.infinispan.counter.api.CounterManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.jboss.logging.Logger;
+import org.jboss.msc.service.Service;
+import org.jboss.msc.service.StartContext;
+import org.jboss.msc.service.StopContext;
+
+/**
+ * @author Vladimir Blagojevic
+ *
+ */
+public class CounterService implements Service {
+
+ private static final Logger log = Logger.getLogger(CounterService.class.getPackage().getName());
+
+ private final Dependencies dependencies;
+ private final String counterConfigurationName;
+ private final CounterConfiguration counterConfiguration;
+
+ public interface Dependencies {
+ EmbeddedCacheManager getCacheContainer();
+ }
+
+ public CounterService(CounterConfiguration configuration, String configurationName, Dependencies dependencies) {
+ this.counterConfiguration = configuration;
+ this.counterConfigurationName = configurationName;
+ this.dependencies = dependencies;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.msc.value.Value#getValue()
+ */
+ @Override
+ public CounterConfiguration getValue() {
+ return this.counterConfiguration;
+ }
+
+ @Override
+ public void start(StartContext context) {
+ EmbeddedCacheManager container = this.dependencies.getCacheContainer();
+ CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(container);
+
+ //define counter
+ counterManager.defineCounter(counterConfigurationName, counterConfiguration);
+
+ //but also instantiate the counter as well
+ switch (counterConfiguration.type()) {
+ case BOUNDED_STRONG:
+ case UNBOUNDED_STRONG: {
+ counterManager.getStrongCounter(counterConfigurationName);
+ break;
+ }
+ case WEAK: {
+ counterManager.getWeakCounter(counterConfigurationName);
+ break;
+ }
+ default: {
+ log.warn("Unknown counter type " + counterConfiguration.type() + " did not get instantiated");
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void stop(StopContext context) {
+ // intentionally empty as we don't do anything on service stop
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CountersMetricsHandler.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CountersMetricsHandler.java
new file mode 100644
index 000000000000..4c76fcc9d0a7
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/CountersMetricsHandler.java
@@ -0,0 +1,90 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+
+import org.infinispan.counter.configuration.CounterManagerConfiguration;
+import org.infinispan.counter.configuration.CounterManagerConfigurationBuilder;
+import org.infinispan.factories.GlobalComponentRegistry;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.server.infinispan.SecurityActions;
+import org.infinispan.server.infinispan.spi.service.CacheContainerServiceName;
+import org.jboss.as.clustering.infinispan.DefaultCacheContainer;
+import org.jboss.as.controller.AbstractRuntimeOnlyHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+import org.jboss.msc.service.ServiceController;
+
+/**
+ * Reflects runtime Counter attributes
+ *
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class CountersMetricsHandler extends AbstractRuntimeOnlyHandler {
+
+ public static final CountersMetricsHandler INSTANCE = new CountersMetricsHandler();
+
+ private static final int CACHE_CONTAINER_INDEX = 1;
+
+ @Override
+ protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException {
+ ModelNode attributeRead = operation.require(NAME);
+ final ModelNode result = new ModelNode();
+ final PathAddress address = PathAddress.pathAddress(operation.require(OP_ADDR));
+ final String cacheContainerName = address.getElement(CACHE_CONTAINER_INDEX).getValue();
+ final ServiceController> controller = context.getServiceRegistry(false)
+ .getService(CacheContainerServiceName.CACHE_CONTAINER.getServiceName(cacheContainerName));
+
+ String attribute = attributeRead.asString();
+ if (controller != null) {
+ DefaultCacheContainer cacheManager = (DefaultCacheContainer) controller.getValue();
+ CounterManagerConfiguration counterManagerConfiguration = extractCounterManagerConfiguration(cacheManager);
+
+ //we only have two attributes in CounterManagerConfiguration
+ if (CounterConfigurationMetrics.NUM_OF_OWNERS.toString().equals(attribute)) {
+ result.set(counterManagerConfiguration.numOwners());
+ } else if (CounterConfigurationMetrics.RELIABILITY.toString().equals(attribute)) {
+ result.set(counterManagerConfiguration.reliability().name());
+ }
+ }
+ context.getResult().set(result);
+ }
+
+ public void registerMetrics(ManagementResourceRegistration container) {
+ for (CounterConfigurationMetrics metric : CounterConfigurationMetrics.values()) {
+ container.registerMetric(metric.definition, this);
+ }
+ }
+
+ private CounterManagerConfiguration extractCounterManagerConfiguration(EmbeddedCacheManager cacheManager) {
+ GlobalComponentRegistry globalComponentRegistry = SecurityActions.getGlobalComponentRegistry(cacheManager);
+ CounterManagerConfiguration config = globalComponentRegistry.getGlobalConfiguration()
+ .module(CounterManagerConfiguration.class);
+ return config == null ? CounterManagerConfigurationBuilder.defaultConfiguration() : config;
+ }
+
+ public enum CounterConfigurationMetrics {
+
+ NUM_OF_OWNERS(MetricKeys.NUM_OF_OWNERS, ModelType.LONG),
+ RELIABILITY(MetricKeys.RELIABILITY, ModelType.STRING);
+
+ final AttributeDefinition definition;
+
+ CounterConfigurationMetrics(String attributeName, ModelType type) {
+ this.definition = new SimpleAttributeDefinitionBuilder(attributeName, type).setAllowNull(false)
+ .setStorageRuntime().build();
+ }
+
+ @Override
+ public final String toString() {
+ return definition.getName();
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Element.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Element.java
index caa38fc3b63e..e1602db8efb7 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Element.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/Element.java
@@ -118,6 +118,11 @@ public enum Element {
REPLICATION_QUEUE_THREAD_POOL(ModelKeys.REPLICATION_QUEUE_THREAD_POOL),
STATE_TRANSFER_THREAD_POOL(ModelKeys.STATE_TRANSFER_THREAD_POOL),
TRANSPORT_THREAD_POOL(ModelKeys.TRANSPORT_THREAD_POOL),
+ COUNTERS(ModelKeys.COUNTERS),
+ STRONG_COUNTER(ModelKeys.STRONG_COUNTER),
+ WEAK_COUNTER(ModelKeys.WEAK_COUNTER),
+ LOWER_BOUND(ModelKeys.LOWER_BOUND),
+ UPPER_BOUND(ModelKeys.UPPER_BOUND),
;
private final String name;
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLReader.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLReader.java
index 07a8005bdf86..38c7ad3348f8 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLReader.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLReader.java
@@ -349,15 +349,183 @@ private void parseContainer(XMLExtendedStreamReader reader, PathAddress subsyste
break;
}
}
+ case COUNTERS: {
+ if (namespace.since(Namespace.INFINISPAN_SERVER_9_2)) {
+ PathAddress countersAddress = containerAddress.append(CacheContainerCountersResource.PATH);
+ operations.put(countersAddress, Util.getEmptyOperation(ADD, countersAddress.toModelNode()));
+ this.parseCounters(reader, countersAddress, operations);
+ break;
+ }
+ }
+ default: {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+ }
+
+ private void parseCounters(XMLExtendedStreamReader reader, PathAddress countersAddress,
+ Map operations) throws XMLStreamException {
+
+ ModelNode counters = operations.get(countersAddress);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String value = reader.getAttributeValue(i);
+ Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
+ switch (attribute) {
+ case NUM_OWNERS: {
+ CacheContainerCountersResource.NUM_OWNERS.parseAndSetParameter(value, counters, reader);
+ break;
+ }
+ case RELIABILITY: {
+ CacheContainerCountersResource.RELIABILITY.parseAndSetParameter(value, counters, reader);
+ break;
+ }
+ default: {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+ }
+
+ while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
+ Element element = Element.forName(reader.getLocalName());
+ switch (element) {
+ case STRONG_COUNTER: {
+ parseStrongCounterElement(reader, countersAddress, operations);
+ break;
+ }
+ case WEAK_COUNTER: {
+ parseWeakCounterElement(reader, countersAddress, operations);
+ break;
+ }
+ default: {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+ }
+
+ private void parseStrongCounterElement(XMLExtendedStreamReader reader,
+ PathAddress countersConfigurationAddress, Map operations)
+ throws XMLStreamException {
+
+ PathAddress strongCounterAddress = countersConfigurationAddress;
+ ModelNode counter = Util.createAddOperation(strongCounterAddress);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String value = reader.getAttributeValue(i);
+ Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
+ switch (attribute) {
+ case INITIAL_VALUE: {
+ StrongCounterResource.INITIAL_VALUE.parseAndSetParameter(value, counter, reader);
+ break;
+ }
+ case NAME: {
+ StrongCounterResource.COUNTER_NAME.parseAndSetParameter(value, counter, reader);
+ strongCounterAddress = strongCounterAddress.append(StrongCounterResource.PATH.getKey(),
+ value);
+ counter.get(OP_ADDR).set(strongCounterAddress.toModelNode());
+ break;
+ }
+ case STORAGE: {
+ StrongCounterResource.STORAGE.parseAndSetParameter(value, counter, reader);
+ break;
+ }
+ default: {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+ }
+ while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
+ Element e = Element.forName(reader.getLocalName());
+ switch (e) {
+ case LOWER_BOUND: {
+ parseCounterBound(reader, e, counter);
+ break;
+ }
+ case UPPER_BOUND: {
+ parseCounterBound(reader, e, counter);
+ break;
+ }
default: {
throw ParseUtils.unexpectedElement(reader);
}
}
}
+ operations.put(strongCounterAddress, counter);
+
+ }
+
+ private void parseWeakCounterElement(XMLExtendedStreamReader reader,
+ PathAddress countersConfigurationAddress, Map operations)
+ throws XMLStreamException {
+
+ PathAddress weakCountersAddress = countersConfigurationAddress;
+ ModelNode counter = Util.createAddOperation(weakCountersAddress);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String value = reader.getAttributeValue(i);
+ Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
+ switch (attribute) {
+ case INITIAL_VALUE: {
+ WeakCounterResource.INITIAL_VALUE.parseAndSetParameter(value,
+ counter, reader);
+ break;
+ }
+ case NAME: {
+ WeakCounterResource.COUNTER_NAME.parseAndSetParameter(value,
+ counter, reader);
+ weakCountersAddress = weakCountersAddress.append(WeakCounterResource.PATH.getKey(),
+ value);
+ counter.get(OP_ADDR).set(weakCountersAddress.toModelNode());
+ break;
+ }
+ case STORAGE: {
+ WeakCounterResource.STORAGE.parseAndSetParameter(value,
+ counter, reader);
+ break;
+ }
+ case CONCURRENCY_LEVEL: {
+ WeakCounterResource.CONCURRENCY_LEVEL.parseAndSetParameter(value,
+ counter, reader);
+ break;
+ }
+ default: {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+ }
+ if (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ operations.put(weakCountersAddress, counter);
+ }
+
+ private void parseCounterBound(XMLExtendedStreamReader reader, Element element, ModelNode counter)
+ throws XMLStreamException {
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String value = reader.getAttributeValue(i);
+ Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
+ switch (attribute) {
+ case VALUE: {
+ if (element.equals(Element.LOWER_BOUND)) {
+ StrongCounterResource.LOWER_BOUND.parseAndSetParameter(value, counter, reader);
+ }
+ if (element.equals(Element.UPPER_BOUND)) {
+ StrongCounterResource.UPPER_BOUND.parseAndSetParameter(value, counter, reader);
+ }
+ break;
+ }
+ default: {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+ }
+ if (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
}
- private void parseGlobalState(XMLExtendedStreamReader reader, PathAddress containerAddress,
+ private void parseGlobalState(XMLExtendedStreamReader reader, PathAddress containerAddress,
Map operations) throws XMLStreamException {
PathAddress globalStateAddress = containerAddress.append(ModelKeys.GLOBAL_STATE, ModelKeys.GLOBAL_STATE_NAME);
ModelNode globalState = Util.createAddOperation(globalStateAddress);
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLWriter.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLWriter.java
index 309c06228d5f..7be1a9a5e130 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLWriter.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLWriter.java
@@ -165,6 +165,9 @@ public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingCon
processCacheConfiguration(writer, container, configurations, ModelKeys.REPLICATED_CACHE);
processCacheConfiguration(writer, container, configurations, ModelKeys.DISTRIBUTED_CACHE);
+ // counters
+ processCounterConfigurations(writer, container);
+
writer.writeEndElement();
}
}
@@ -204,7 +207,69 @@ private static void writeScheduledThreadPoolElements(Element element, ScheduledT
}
}
- private void processCacheConfiguration(XMLExtendedStreamWriter writer, ModelNode container, ModelNode configurations, String cacheType)
+ private void processCounterConfigurations(XMLExtendedStreamWriter writer, ModelNode container)
+ throws XMLStreamException {
+
+ if (container.hasDefined(ModelKeys.COUNTERS)) {
+ writer.writeStartElement(Element.COUNTERS.getLocalName());
+
+ //counters element and its attributes
+ ModelNode counterRoot = container.get(ModelKeys.COUNTERS);
+ this.writeOptional(writer, Attribute.RELIABILITY, counterRoot, ModelKeys.RELIABILITY);
+ this.writeOptional(writer, Attribute.NUM_OWNERS, counterRoot, ModelKeys.NUM_OWNERS);
+
+ //all counters configurations
+ ModelNode counterConfigurations = counterRoot.get(ModelKeys.COUNTERS_NAME);
+ processStrongCounterConfigurations(writer, counterConfigurations.get(ModelKeys.STRONG_COUNTER));
+ processWeakCounterConfigurations(writer, counterConfigurations.get(ModelKeys.WEAK_COUNTER));
+ writer.writeEndElement();
+ }
+ }
+
+ private void processWeakCounterConfigurations(XMLExtendedStreamWriter writer, ModelNode configurations) throws XMLStreamException {
+ if (configurations != null && configurations.isDefined()) {
+ for (Property e : configurations.asPropertyList()) {
+ processWeakCounterConfiguration(writer, e.getValue());
+ }
+ }
+ }
+
+ private void processStrongCounterConfigurations(XMLExtendedStreamWriter writer, ModelNode configurations) throws XMLStreamException {
+ if (configurations != null && configurations.isDefined()) {
+ for (Property e : configurations.asPropertyList()) {
+ processStrongCounterConfiguration(writer, e.getValue());
+ }
+ }
+ }
+
+ private void processWeakCounterConfiguration(XMLExtendedStreamWriter writer, ModelNode weakConfiguration) throws XMLStreamException {
+ writer.writeStartElement(Element.WEAK_COUNTER.getLocalName());
+ this.writeRequired(writer, Attribute.NAME, weakConfiguration, ModelKeys.NAME);
+ this.writeOptional(writer, Attribute.INITIAL_VALUE, weakConfiguration, ModelKeys.INITIAL_VALUE);
+ this.writeOptional(writer, Attribute.STORAGE, weakConfiguration, ModelKeys.STORAGE);
+ this.writeOptional(writer, Attribute.CONCURRENCY_LEVEL, weakConfiguration, ModelKeys.CONCURRENCY_LEVEL);
+ writer.writeEndElement();
+ }
+
+ private void processStrongCounterConfiguration(XMLExtendedStreamWriter writer, ModelNode strongConfiguration) throws XMLStreamException {
+ writer.writeStartElement(Element.STRONG_COUNTER.getLocalName());
+ this.writeRequired(writer, Attribute.NAME, strongConfiguration, ModelKeys.NAME);
+ this.writeOptional(writer, Attribute.INITIAL_VALUE, strongConfiguration, ModelKeys.INITIAL_VALUE);
+ this.writeOptional(writer, Attribute.STORAGE, strongConfiguration, ModelKeys.STORAGE);
+ if (strongConfiguration.hasDefined(ModelKeys.LOWER_BOUND)) {
+ writer.writeStartElement(Element.LOWER_BOUND.getLocalName());
+ this.writeRequired(writer, Attribute.VALUE, strongConfiguration, ModelKeys.LOWER_BOUND);
+ writer.writeEndElement();
+ }
+ if (strongConfiguration.hasDefined(ModelKeys.UPPER_BOUND)) {
+ writer.writeStartElement(Element.UPPER_BOUND.getLocalName());
+ this.writeRequired(writer, Attribute.VALUE, strongConfiguration, ModelKeys.UPPER_BOUND);
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ }
+
+ private void processCacheConfiguration(XMLExtendedStreamWriter writer, ModelNode container, ModelNode configurations, String cacheType)
throws XMLStreamException {
String cacheConfigurationType = cacheType + ModelKeys.CONFIGURATION_SUFFIX;
Map> configurationMappings = new HashMap<>();
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/MetricKeys.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/MetricKeys.java
index aba67d91d2d0..fc487277ddeb 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/MetricKeys.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/MetricKeys.java
@@ -101,4 +101,9 @@ public class MetricKeys {
public static final String NUMBER_OF_NODES = "number-of-nodes";
public static final String CACHE_HEALTH = "cache-health";
public static final String LOG_TAIL = "log-tail";
+
+ // Counter
+ public static final String VALUE="value";
+ public static final String NUM_OF_OWNERS = "num-owners";
+ public static final String RELIABILITY = "reliability";
}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/ModelKeys.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/ModelKeys.java
index a7f3827f0827..0c5368dc9af5 100644
--- a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/ModelKeys.java
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/ModelKeys.java
@@ -81,6 +81,8 @@ public class ModelKeys {
static final String CONFIGURATIONS_NAME = "CONFIGURATIONS";
static final String CONNECTION_POOL = "connection-pool";
static final String CONNECTION_TIMEOUT = "connection-timeout";
+ static final String COUNTERS = "counters";
+ static final String COUNTERS_NAME = "COUNTERS";
static final String CREATE_ON_START = "create-on-start";
static final String CUSTOM_ROLE_MAPPER = "custom-role-mapper";
static final String DATA_COLUMN = "data-column";
@@ -126,6 +128,7 @@ public class ModelKeys {
static final String INDEXING_PROPERTIES = "indexing-properties";
static final String INITIAL_CLUSTER_SIZE = "initial-cluster-size";
static final String INITIAL_CLUSTER_TIMEOUT = "initial-cluster-timeout";
+ static final String INITIAL_VALUE = "initial-value";
static final String INTERVAL = "interval";
static final String INVALIDATION_CACHE = "invalidation-cache";
static final String INVALIDATION_CACHE_CONFIGURATION = INVALIDATION_CACHE + CONFIGURATION_SUFFIX;
@@ -152,6 +155,7 @@ public class ModelKeys {
static final String LOCK_TIMEOUT = "lock-timeout";
static final String LOCKING = "locking";
static final String LOCKING_NAME = "LOCKING";
+ static final String LOWER_BOUND = "lower-bound";
static final String MACHINE = "machine";
static final String MAPPER = "mapper";
static final String MARSHALLER = "marshaller";
@@ -175,6 +179,7 @@ public class ModelKeys {
static final String MODULES = "modules";
static final String MODULES_NAME = "MODULES";
static final String NAME = "name";
+ static final String NUM_OWNERS = "num_owners";
static final String NOTIFICATIONS = "notifications";
static final String OBJECT_NAME = "OBJECT";
static final String OFF_HEAP_NAME = "OFF-HEAP";
@@ -188,6 +193,7 @@ public class ModelKeys {
static final String PERMISSIONS = "permissions";
static final String PERSISTENCE = "persistence";
static final String PERSISTENT_LOCATION = "persistent-location";
+ static final String RELIABILITY = "reliability";
static final String PLAIN = "plain";
static final String PREFIX = "prefix";
static final String PRELOAD = "preload";
@@ -244,6 +250,7 @@ public class ModelKeys {
static final String STATISTICS = "statistics";
static final String STATISTICS_AVAILABLE = "statistics-available";
static final String STOP_TIMEOUT = "stop-timeout";
+ static final String STORAGE = "storage";
static final String STORE = "store";
static final String STORE_NAME = "STORE";
static final String STRICT_PEER_TO_PEER = "strict-peer-to-peer";
@@ -268,6 +275,7 @@ public class ModelKeys {
static final String TYPE = "type";
static final String TX_INTERNAL_ID = "internal-id";
static final String USERNAME = "username";
+ static final String UPPER_BOUND = "upper-bound";
static final String VALUE = "value";
static final String WAIT = "wait";
static final String WAIT_TIME = "wait-time";
@@ -285,4 +293,6 @@ public class ModelKeys {
static final String TRANSPORT_THREAD_POOL = "transport-thread-pool";
static final String READ_BATCH = "read-batch";
static final String WRITE_THREADS = "write-threads";
+ static final String STRONG_COUNTER = "strong-counter";
+ static final String WEAK_COUNTER = "weak-counter";
}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterAddHandler.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterAddHandler.java
new file mode 100644
index 000000000000..8317b217dae7
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterAddHandler.java
@@ -0,0 +1,48 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.infinispan.counter.api.CounterConfiguration;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * Add operation handler for /subsystem=infinispan/cache-container=clustered/counter=*
+ *
+ * @author Vladimir Blagojevic
+ *
+ */
+public class StrongCounterAddHandler extends CounterAddHandler {
+
+ /**
+ *
+ */
+ @Override
+ void populate(ModelNode fromModel, ModelNode toModel) throws OperationFailedException {
+ super.populate(fromModel, toModel);
+ for (AttributeDefinition attr : StrongCounterResource.STRONG_ATTRIBUTES) {
+ attr.validateAndSet(fromModel, toModel);
+ }
+ }
+
+ /**
+ * Implementation of abstract method processModelNode
+ *
+ */
+ @Override
+ void processModelNode(OperationContext context, ModelNode counter,
+ CounterConfiguration.Builder builder) throws OperationFailedException {
+ super.processModelNode(context, counter, builder);
+
+ ModelNode upperBoundModel = counter.get(ModelKeys.UPPER_BOUND);
+ ModelNode lowerBoundModel = counter.get(ModelKeys.LOWER_BOUND);
+ if (lowerBoundModel.isDefined()) {
+ Long lowerBound = StrongCounterResource.LOWER_BOUND.resolveModelAttribute(context, counter).asLong();
+ builder.lowerBound(lowerBound);
+ }
+ if (upperBoundModel.isDefined()) {
+ Long upperBound = StrongCounterResource.UPPER_BOUND.resolveModelAttribute(context, counter).asLong();
+ builder.upperBound(upperBound);
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterResource.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterResource.java
new file mode 100644
index 000000000000..643365e55049
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/StrongCounterResource.java
@@ -0,0 +1,53 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.registry.AttributeAccess;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Resource description for the addressable resource
+ * /subsystem=infinispan/cache-container=X/counter=*
+ *
+ *
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class StrongCounterResource extends CounterResource {
+
+ public static final PathElement PATH = PathElement.pathElement(ModelKeys.STRONG_COUNTER);
+
+ static final SimpleAttributeDefinition LOWER_BOUND =
+ new SimpleAttributeDefinitionBuilder(ModelKeys.LOWER_BOUND, ModelType.LONG, true)
+ .setXmlName(Attribute.LOWER_BOUND.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .build();
+
+ static final SimpleAttributeDefinition UPPER_BOUND =
+ new SimpleAttributeDefinitionBuilder(ModelKeys.UPPER_BOUND, ModelType.LONG, true)
+ .setXmlName(Attribute.UPPER_BOUND.getLocalName())
+ .setAllowExpression(false)
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
+ .build();
+
+ static final SimpleAttributeDefinition[] STRONG_ATTRIBUTES = { LOWER_BOUND, UPPER_BOUND };
+
+ public StrongCounterResource(boolean runtimeRegistration) {
+ super(StrongCounterResource.PATH,
+ new InfinispanResourceDescriptionResolver(ModelKeys.COUNTERS),
+ new StrongCounterAddHandler(), new CounterRemoveHandler(), runtimeRegistration);
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+
+ for (AttributeDefinition attr : STRONG_ATTRIBUTES) {
+ resourceRegistration.registerReadOnlyAttribute(attr, null);
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterAddHandler.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterAddHandler.java
new file mode 100644
index 000000000000..6eb572e7be76
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterAddHandler.java
@@ -0,0 +1,37 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.infinispan.counter.api.CounterConfiguration;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * Add operation handler for /subsystem=infinispan/cache-container=clustered/counter=*
+ *
+ * @author Vladimir Blagojevic
+ *
+ */
+public class WeakCounterAddHandler extends CounterAddHandler {
+
+ @Override
+ void populate(ModelNode fromModel, ModelNode toModel) throws OperationFailedException {
+ super.populate(fromModel, toModel);
+ for (AttributeDefinition attr : WeakCounterResource.WEAK_ATTRIBUTES) {
+ attr.validateAndSet(fromModel, toModel);
+ }
+ }
+
+ /**
+ * Implementation of abstract method processModelNode
+ *
+ */
+ @Override
+ void processModelNode(OperationContext context, ModelNode counter,
+ CounterConfiguration.Builder builder) throws OperationFailedException {
+ super.processModelNode(context, counter, builder);
+
+ Integer concurrency = WeakCounterResource.CONCURRENCY_LEVEL.resolveModelAttribute(context, counter).asInt();
+ builder.concurrencyLevel(concurrency);
+ }
+}
diff --git a/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterResource.java b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterResource.java
new file mode 100644
index 000000000000..c24d1717ca58
--- /dev/null
+++ b/server/integration/infinispan/src/main/java/org/jboss/as/clustering/infinispan/subsystem/WeakCounterResource.java
@@ -0,0 +1,46 @@
+package org.jboss.as.clustering.infinispan.subsystem;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.registry.AttributeAccess;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Resource description for the addressable resource
+ * /subsystem=infinispan/cache-container=X/counter=*
+ *
+ * @author Pedro Ruivo
+ * @author Vladimir Blagojevic
+ * @since 9.2
+ */
+public class WeakCounterResource extends CounterResource {
+
+ public static final PathElement PATH = PathElement.pathElement(ModelKeys.WEAK_COUNTER);
+
+ static final SimpleAttributeDefinition CONCURRENCY_LEVEL = new SimpleAttributeDefinitionBuilder(ModelKeys.CONCURRENCY_LEVEL,
+ ModelType.INT, true)
+ .setXmlName(Attribute.CONCURRENCY_LEVEL.getLocalName())
+ .setAllowExpression(false)
+ .setDefaultValue(new ModelNode().set(64))
+ .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES).build();
+
+ static final AttributeDefinition[] WEAK_ATTRIBUTES = { CONCURRENCY_LEVEL };
+
+ public WeakCounterResource(boolean runtimeRegistration) {
+ super(WeakCounterResource.PATH, new InfinispanResourceDescriptionResolver(ModelKeys.COUNTERS),
+ new WeakCounterAddHandler(), new CounterRemoveHandler(), runtimeRegistration);
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+
+ for (AttributeDefinition attr : WEAK_ATTRIBUTES) {
+ resourceRegistration.registerReadOnlyAttribute(attr, null);
+ }
+ }
+}
diff --git a/server/integration/infinispan/src/main/resources/org/jboss/as/clustering/infinispan/subsystem/LocalDescriptions.properties b/server/integration/infinispan/src/main/resources/org/jboss/as/clustering/infinispan/subsystem/LocalDescriptions.properties
index 60e3cdf3a489..d420e239489f 100644
--- a/server/integration/infinispan/src/main/resources/org/jboss/as/clustering/infinispan/subsystem/LocalDescriptions.properties
+++ b/server/integration/infinispan/src/main/resources/org/jboss/as/clustering/infinispan/subsystem/LocalDescriptions.properties
@@ -639,3 +639,52 @@ datagrid-infinispan.cache-container.health.number-of-nodes=Number of nodes in th
datagrid-infinispan.cache-container.health.add=Add Health Check API
datagrid-infinispan.cache-container.health.remove=Removed Health Check API
datagrid-infinispan.cache-container.health.log-tail=Last 10 lines of the log file
+
+# counters
+datagrid-infinispan.counter = A cluster counter
+datagrid-infinispan.cache-container.counter = A cluster counter
+
+datagrid-infinispan.cache-container.configurations.counters = Cluster counters
+datagrid-infinispan.cache-container.configurations.counters.add = Add new counter
+datagrid-infinispan.cache-container.configurations.counters.remove = Remove counter
+
+datagrid-infinispan.cache-container.counters.num-owners = "Number of counter copies to keep cluster-wide"
+datagrid-infinispan.cache-container.counters.reliability = "Counter update behavior in a network partition"
+
+datagrid-infinispan.cache-container.counters = Cluster counters
+datagrid-infinispan.cache-container.counters.add = Add new counter
+datagrid-infinispan.cache-container.counters.remove = Remove counter
+
+datagrid-infinispan.cache-container.counters.name=The counter's name
+datagrid-infinispan.cache-container.counters.type=The counter's type (weak, strong bounded or strong unbounded)
+datagrid-infinispan.cache-container.counters.storage=The counter's storage mode (volatile or persistent)
+datagrid-infinispan.cache-container.counters.initial-value=The counter's initial value
+datagrid-infinispan.cache-container.counters.upper-bound=The counter's upper-bound, if strong and bounded
+datagrid-infinispan.cache-container.counters.lower-bound=The counter's lower-bound, if strong and bounded
+datagrid-infinispan.cache-container.counters.concurrency-level=The counter's concurrency-level, if weak
+datagrid-infinispan.cache-container.counters.value=The counter's value
+datagrid-infinispan.cache-container.counters.counter-reset=Resets the counter value to initial value
+datagrid-infinispan.cache-container.counters.counter-increase=Increase the counter value by 1
+datagrid-infinispan.cache-container.counters.counter-decrease=Decrease the counter value by 1
+datagrid-infinispan.cache-container.counters.counter-set=Set counter value
+datagrid-infinispan.cache-container.counters.strong-counter="A strong counter"
+datagrid-infinispan.cache-container.counters.weak-counter="A weak counter"
+
+datagrid-infinispan.counters = Cluster counters
+datagrid-infinispan.counters.add = Add new counter
+datagrid-infinispan.counters.remove = Remove counter
+
+datagrid-infinispan.counters.name=The counter's name
+datagrid-infinispan.counters.type=The counter's type (weak, strong bounded or strong unbounded)
+datagrid-infinispan.counters.storage=The counter's storage mode (volatile or persistent)
+datagrid-infinispan.counters.initial-value=The counter's initial value
+datagrid-infinispan.counters.upper-bound=The counter's upper-bound, if strong and bounded
+datagrid-infinispan.counters.lower-bound=The counter's lower-bound, if strong and bounded
+datagrid-infinispan.counters.concurrency-level=The counter's concurrency-level, if weak
+datagrid-infinispan.counters.value=The counter's value
+datagrid-infinispan.counters.counter-reset=Resets the counter value to initial value
+datagrid-infinispan.counters.counter-increase=Increase the counter value by 1
+datagrid-infinispan.counters.counter-decrease=Decrease the counter value by 1
+datagrid-infinispan.counters.counter-set=Set counter value
+datagrid-infinispan.counters.strong-counter="A strong counter"
+datagrid-infinispan.counters.weak-counter="A weak counter"
diff --git a/server/integration/infinispan/src/main/resources/schema/jboss-infinispan-core_9_2.xsd b/server/integration/infinispan/src/main/resources/schema/jboss-infinispan-core_9_2.xsd
index fe366d9fad4d..63c2798f1298 100644
--- a/server/integration/infinispan/src/main/resources/schema/jboss-infinispan-core_9_2.xsd
+++ b/server/integration/infinispan/src/main/resources/schema/jboss-infinispan-core_9_2.xsd
@@ -143,6 +143,11 @@
+
+
+ Defines counters.
+
+
@@ -371,6 +376,121 @@
+
+
+
+
+
+ Defines strong counter
+
+
+
+
+
+
+ Defines strong counter
+
+
+
+
+
+
+ Sets the number of counter’s copies to keep
+ cluster-wide. It must be positive and its default value is 2.
+
+
+
+
+
+ Sets the counter’s update behavior in a network
+ partition. Default value is AVAILABLE
+
+
+
+
+
+
+
+
+
+
+
+ The lower bound for this
+ strong counter
+
+
+
+
+
+ The upper bound for this
+ strong counter
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets the number of concurrent
+ updates. Its value
+ must be positive and the default value is 64.
+
+
+
+
+
+
+
+
+
+
+ Counter name
+
+
+
+
+ Counter initial value. Default is 0
+ (zero)
+
+
+
+
+
+ Sets the counter’s behavior when the
+ cluster is shutdown and restarted. Default value is
+ VOLATILE.
+
+
+
+
+
+
+
+
+ Counter lower bound
+
+
+
+
+
+
+
+ Counter upper bound
+
+
+
+
@@ -1712,6 +1832,43 @@
+
+
+
+
+ All partitions are able to read and update the
+ counter’s value.
+
+
+
+
+ Only the primary partition (majority of nodes)
+ will be able to read and update the counter’s value. The remaining
+ partitions can only read its value.
+
+
+
+
+
+
+
+
+
+ The counter’s value is only available in memory.
+ The value will be lost when a cluster is shutdown.
+
+
+
+
+
+ The counter’s value is stored in a private and
+ local persistent store. The value is kept when the cluster is
+ shutdown and restored after a restart.
+
+
+
+
+
diff --git a/server/integration/infinispan/src/main/resources/subsystem-templates/infinispan-core.xml b/server/integration/infinispan/src/main/resources/subsystem-templates/infinispan-core.xml
index ec0ce4182f21..2a1c6500eb75 100644
--- a/server/integration/infinispan/src/main/resources/subsystem-templates/infinispan-core.xml
+++ b/server/integration/infinispan/src/main/resources/subsystem-templates/infinispan-core.xml
@@ -122,6 +122,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/server/integration/infinispan/src/test/java/org/jboss/as/clustering/infinispan/subsystem/SubsystemParsingTestCase.java b/server/integration/infinispan/src/test/java/org/jboss/as/clustering/infinispan/subsystem/SubsystemParsingTestCase.java
index f3ca4d1c270a..f5cd275a3e26 100644
--- a/server/integration/infinispan/src/test/java/org/jboss/as/clustering/infinispan/subsystem/SubsystemParsingTestCase.java
+++ b/server/integration/infinispan/src/test/java/org/jboss/as/clustering/infinispan/subsystem/SubsystemParsingTestCase.java
@@ -77,7 +77,7 @@ public static Collection