@@ -0,0 +1,59 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.controller;

import java.util.Set;
import java.util.function.Supplier;

import org.jboss.as.controller.registry.PlaceholderResource;
import org.jboss.as.controller.registry.Resource;
import org.wildfly.common.function.Functions;

/**
* A simple {@link ChildResourceProvider} containing a predefined set of children.
* @author Paul Ferraro
*/
public class SimpleChildResourceProvider implements ChildResourceProvider {

private final Set<String> children;
private final Supplier<Resource> provider;

public SimpleChildResourceProvider(Set<String> children) {
this(children, Functions.constantSupplier(PlaceholderResource.INSTANCE));
}

public SimpleChildResourceProvider(Set<String> children, Supplier<Resource> provider) {
this.children = children;
this.provider = provider;
}

@Override
public Resource getChild(String name) {
return this.children.contains(name) ? this.provider.get() : null;
}

@Override
public Set<String> getChildren() {
return this.children;
}
}
@@ -0,0 +1,107 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

/**
* Used for iterating over an series of iterables, thus avoiding the need to allocate/populate a new list containing all elements.
* More efficient than the alternative when the number of iterables is arbitrary and small relative to the size of each iterable.
* @author Paul Ferraro
*/
public class CompositeIterable<T> implements Iterable<T> {

private final List<? extends Iterable<? extends T>> iterables;

/**
* Constructs a new composite iterable.
* @param iterables a series of iterables
*/
@SafeVarargs
public CompositeIterable(Iterable<? extends T>... iterables) {
this(Arrays.asList(iterables));
}

/**
* Constructs a new composite iterable.
* @param iterables a series of iterables
*/
public CompositeIterable(List<? extends Iterable<? extends T>> iterables) {
this.iterables = iterables;
}

@Override
public Iterator<T> iterator() {
List<Iterator<? extends T>> iterators = new ArrayList<>(this.iterables.size());
for (Iterable<? extends T> elements : this.iterables) {
iterators.add(elements.iterator());
}
return new CompositeIterator<>(iterators);
}

@Override
public int hashCode() {
int result = 1;
for (Iterable<? extends T> elements : this.iterables) {
for (T element : elements) {
result = 31 * result + ((element != null) ? element.hashCode() : 0);
}
}
return result;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Iterable)) return false;
@SuppressWarnings("unchecked")
Iterator<Object> otherElements = ((Iterable<Object>) object).iterator();
for (Iterable<? extends T> iterable : this.iterables) {
Iterator<? extends T> elements = iterable.iterator();
while (elements.hasNext() && otherElements.hasNext()) {
elements.next().equals(otherElements.next());
}
if (elements.hasNext()) return false;
}
return !otherElements.hasNext();
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append('[');
Iterator<? extends Iterable<? extends T>> iterables = this.iterables.iterator();
while (iterables.hasNext()) {
Iterator<? extends T> elements = iterables.next().iterator();
while (elements.hasNext()) {
if (builder.length() > 1) {
builder.append(',').append(' ');
}
builder.append(elements.next());
}
}
return builder.append(']').toString();
}
}
@@ -0,0 +1,69 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* Iterator that iterates over a series of iterators.
* @author Paul Ferraro
*/
public class CompositeIterator<E> implements Iterator<E> {

private final Iterable<? extends Iterator<? extends E>> iterators;

/**
* Constructs a new composite iterator.
* @param iterables a series of iterators
*/
@SafeVarargs
public CompositeIterator(Iterator<? extends E>... iterators) {
this(Arrays.asList(iterators));
}

/**
* Constructs a new composite iterator.
* @param iterables a series of iterators
*/
public CompositeIterator(Iterable<? extends Iterator<? extends E>> iterators) {
this.iterators = iterators;
}

@Override
public boolean hasNext() {
for (Iterator<? extends E> iterator : this.iterators) {
if (iterator.hasNext()) return true;
}
return false;
}

@Override
public E next() {
for (Iterator<? extends E> iterator : this.iterators) {
if (iterator.hasNext()) return iterator.next();
}
throw new NoSuchElementException();
}
}
@@ -1,6 +1,6 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
@@ -19,185 +19,44 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.security.Permission;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.chrono.Era;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.time.temporal.WeekFields;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneOffsetTransitionRule;
import java.time.zone.ZoneRules;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Currency;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.function.Predicate;

/**
* Determines whether a given object is immutable.
* Tests for immutability.
* @author Paul Ferraro
*/
public enum Immutability implements Predicate<Object> {

OBJECT() {
// Singleton immutable objects detectable via reference equality test
private final Set<Object> immutableObjects = createIdentitySet(Arrays.asList(
null,
Collections.emptyEnumeration(),
Collections.emptyIterator(),
Collections.emptyList(),
Collections.emptyListIterator(),
Collections.emptyMap(),
Collections.emptyNavigableMap(),
Collections.emptyNavigableSet(),
Collections.emptySet(),
Collections.emptySortedMap(),
Collections.emptySortedSet()
));

@Override
public boolean test(Object object) {
return this.immutableObjects.contains(object);
}
},
CLASS() {
// Concrete immutable classes detectable via reference equality test
private final Set<Class<?>> immutableClasses = createIdentitySet(Arrays.asList(
BigDecimal.class,
BigInteger.class,
Boolean.class,
Byte.class,
Character.class,
Class.class,
Currency.class,
DateTimeFormatter.class,
DecimalStyle.class,
Double.class,
Duration.class,
File.class,
Float.class,
Inet4Address.class,
Inet6Address.class,
InetSocketAddress.class,
Instant.class,
Integer.class,
Locale.class,
LocalDate.class,
LocalDateTime.class,
LocalTime.class,
Long.class,
MathContext.class,
MonthDay.class,
Period.class,
Short.class,
StackTraceElement.class,
String.class,
URI.class,
URL.class,
UUID.class,
ValueRange.class,
WeekFields.class,
Year.class,
YearMonth.class,
ZoneOffset.class,
ZoneOffsetTransition.class,
ZoneOffsetTransitionRule.class,
ZoneRules.class,
ZonedDateTime.class
));

@Override
public boolean test(Object object) {
return this.immutableClasses.contains(object.getClass());
}
},
ABSTRACT_CLASS() {
// Interfaces and abstract classes documented to be immutable, but only detectable via instanceof tests
private final List<Class<?>> immutableClasses = Arrays.asList(
Chronology.class,
ChronoLocalDate.class,
Clock.class,
Enum.class, // In theory, one could implement a mutable enum, but that would just be weird.
Era.class,
Path.class,
Permission.class,
TemporalField.class,
TemporalUnit.class,
TimeZone.class, // Strictly speaking, this class is mutable, although in practice it is never mutated.
ZoneId.class
);

@Override
public boolean test(Object object) {
for (Class<?> immutableClass : this.immutableClasses) {
if (immutableClass.isInstance(object)) return true;
public interface Immutability extends Predicate<Object> {

@Override
default Immutability and(Predicate<? super Object> immutability) {
return new Immutability() {
@Override
public boolean test(Object object) {
return Immutability.this.test(object) && immutability.test(object);
}
return false;
}
},
COLLECTION() {
@Override
public boolean test(Object object) {
return COLLECTION_INSTANCE.test(object);
}
},
ANNOTATION() {
@Override
public boolean test(Object object) {
return object.getClass().isAnnotationPresent(net.jcip.annotations.Immutable.class);
}
},
;
};
}

public static final Predicate<Object> INSTANCE = object -> {
// These are not an expensive predicates, so there is little to gain from parallel computation
for (Predicate<Object> predicate : EnumSet.allOf(Immutability.class)) {
if (predicate.test(object)) return true;
}
return false;
};
static final Predicate<Object> COLLECTION_INSTANCE = new CollectionImmutability(INSTANCE);
@Override
default Immutability negate() {
return new Immutability() {
@Override
public boolean test(Object object) {
return !Immutability.this.test(object);
}
};
}

static <T> Set<T> createIdentitySet(Collection<T> list) {
Set<T> result = Collections.newSetFromMap(new IdentityHashMap<>(list.size()));
result.addAll(list);
return Collections.unmodifiableSet(result);
@Override
default Immutability or(Predicate<? super Object> immutability) {
return new Immutability() {
@Override
public boolean test(Object object) {
return Immutability.this.test(object) || immutability.test(object);
}
};
}
}
}
@@ -0,0 +1,45 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.immutable;

import java.lang.annotation.Annotation;

import org.wildfly.clustering.ee.Immutability;

/**
* Detects the presence of a specific annotation.
* @author Paul Ferraro
*/
public class AnnotationImmutability implements Immutability {

private final Class<? extends Annotation> annotationClass;

public AnnotationImmutability(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}

@Override
public boolean test(Object object) {
return object.getClass().isAnnotationPresent(this.annotationClass);
}
}
@@ -20,59 +20,74 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;
package org.wildfly.clustering.ee.immutable;

import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import org.wildfly.clustering.ee.Immutability;

/**
* Tests the immutability of {@link Collections} wrappers.
* N.B. Strictly speaking, an unmodifiable collection is not necessarily immutable since the collection can still be modified through a reference to the delegate collection.
* Were this the case, the immutability test would also run against the delegate collection - and fail, forcing replication.
* @author Paul Ferraro
*/
public class CollectionImmutability implements Predicate<Object> {
public class CollectionImmutability implements Immutability {

private final List<Class<?>> unmodifiableClasses = Arrays.asList(
private final List<Class<?>> unmodifiableCollectionClasses = Arrays.asList(
Collections.singleton(null).getClass(),
Collections.singletonList(null).getClass(),
Collections.singletonMap(null, null).getClass(),
Collections.unmodifiableCollection(Collections.emptyList()).getClass(),
Collections.unmodifiableList(Collections.emptyList()).getClass(),
Collections.unmodifiableMap(Collections.emptyMap()).getClass(),
Collections.unmodifiableNavigableMap(Collections.emptyNavigableMap()).getClass(),
Collections.unmodifiableNavigableSet(Collections.emptyNavigableSet()).getClass(),
Collections.unmodifiableSet(Collections.emptySet()).getClass(),
Collections.unmodifiableSortedMap(Collections.emptySortedMap()).getClass(),
Collections.unmodifiableSortedSet(Collections.emptySortedSet()).getClass());

private final Predicate<Object> elementImmutability;
private final List<Class<?>> unmodifiableMapClasses = Arrays.asList(
Collections.singletonMap(null, null).getClass(),
Collections.unmodifiableMap(Collections.emptyMap()).getClass(),
Collections.unmodifiableNavigableMap(Collections.emptyNavigableMap()).getClass(),
Collections.unmodifiableSortedMap(Collections.emptySortedMap()).getClass());

private final Immutability elementImmutability;

public CollectionImmutability(Predicate<Object> elementImmutability) {
public CollectionImmutability(Immutability elementImmutability) {
this.elementImmutability = elementImmutability;
}

@Override
public boolean test(Object object) {
for (Class<?> unmodifiableClass : this.unmodifiableClasses) {
if (unmodifiableClass.isInstance(object)) {
// An unmodifiable set should be immutable.
if (object instanceof Set) return true;
for (Class<?> unmodifiableCollectionClass : this.unmodifiableCollectionClasses) {
if (unmodifiableCollectionClass.isInstance(object)) {
// An unmodifiable collection is immutable if its members are immutable.
// An unmodifiable map should be immutable if its values are immutable.
Collection<?> collection = (object instanceof Map) ? ((Map<?, ?>) object).values() : (Collection<?>) object;
// This is not an expensive predicate, so there is little to gain from parallel computation
for (Object element : collection) {
for (Object element : (Collection<?>) object) {
if (!this.elementImmutability.test(element)) return false;
}
return true;
}
}
for (Class<?> unmodifiableMapClass : this.unmodifiableMapClasses) {
if (unmodifiableMapClass.isInstance(object)) {
// An unmodifiable map is immutable if its entries are immutable.
for (Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
if (!this.test(entry)) return false;
}
return true;
}
}
if (object instanceof AbstractMap.SimpleImmutableEntry) {
return this.test((Map.Entry<?, ?>) object);
}
return false;
}

// An unmodifiable map entry is immutable if its key and value are immutable.
private boolean test(Map.Entry<?, ?> entry) {
return this.elementImmutability.test(entry.getKey()) && this.elementImmutability.test(entry.getValue());
}
}
@@ -0,0 +1,56 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.immutable;

import java.util.Arrays;

import org.wildfly.clustering.ee.Immutability;

/**
* Decorates a series of immutability predicates to additionally test for collection immutability.
* @author Paul Ferraro
*/
public class CompositeImmutability implements Immutability {

private final Iterable<? extends Immutability> immutabilities;
private final Immutability collectionImmutability;

public CompositeImmutability(Immutability... predicates) {
this(Arrays.asList(predicates));
}

public CompositeImmutability(Iterable<? extends Immutability> immutabilities) {
this.immutabilities = immutabilities;
this.collectionImmutability = new CollectionImmutability(this);
}

@Override
public boolean test(Object object) {
for (Immutability immutability : this.immutabilities) {
if (immutability.test(object)) {
return true;
}
}
return this.collectionImmutability.test(object);
}
}
@@ -0,0 +1,155 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.ee.immutable;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.security.Permission;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.chrono.Era;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.time.temporal.WeekFields;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneOffsetTransitionRule;
import java.time.zone.ZoneRules;
import java.util.Arrays;
import java.util.Collections;
import java.util.Currency;
import java.util.Locale;
import java.util.TimeZone;
import java.util.UUID;

import org.wildfly.clustering.ee.Immutability;

/**
* Default set of immutability tests.
* @author Paul Ferraro
*/
public enum DefaultImmutability implements Immutability {

// Singleton immutable objects detectable via reference equality test
OBJECT(new IdentityImmutability(Arrays.asList(
Collections.emptyEnumeration(),
Collections.emptyIterator(),
Collections.emptyList(),
Collections.emptyListIterator(),
Collections.emptyMap(),
Collections.emptyNavigableMap(),
Collections.emptyNavigableSet(),
Collections.emptySet(),
Collections.emptySortedMap(),
Collections.emptySortedSet()))),
// Concrete immutable classes detectable via reference equality test
CLASS(new SimpleImmutability(Arrays.asList(
BigDecimal.class,
BigInteger.class,
Boolean.class,
Byte.class,
Character.class,
Class.class,
Currency.class,
DateTimeFormatter.class,
DecimalStyle.class,
Double.class,
Duration.class,
File.class,
Float.class,
Inet4Address.class,
Inet6Address.class,
InetSocketAddress.class,
Instant.class,
Integer.class,
Locale.class,
LocalDate.class,
LocalDateTime.class,
LocalTime.class,
Long.class,
MathContext.class,
MonthDay.class,
Period.class,
Short.class,
StackTraceElement.class,
String.class,
URI.class,
URL.class,
UUID.class,
ValueRange.class,
WeekFields.class,
Year.class,
YearMonth.class,
ZoneOffset.class,
ZoneOffsetTransition.class,
ZoneOffsetTransitionRule.class,
ZoneRules.class,
ZonedDateTime.class))),
// Interfaces and abstract classes documented to be immutable, but only detectable via instanceof tests
ABSTRACT_CLASS(new InstanceOfImmutability(Arrays.asList(
Chronology.class,
ChronoLocalDate.class,
Clock.class,
Enum.class, // In theory, one could implement a mutable enum, but that would just be weird.
Era.class,
Path.class,
Permission.class,
TemporalField.class,
TemporalUnit.class,
TimeZone.class, // Strictly speaking, this class is mutable, although in practice it is never mutated.
ZoneId.class))),
ANNOTATION(new AnnotationImmutability(net.jcip.annotations.Immutable.class)),
;
private final Immutability immutability;

DefaultImmutability(Immutability immutability) {
this.immutability = immutability;
}

@Override
public boolean test(Object object) {
return this.immutability.test(object);
}
}
@@ -0,0 +1,51 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.immutable;

import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;

import org.wildfly.clustering.ee.Immutability;

/**
* Test for immutability using object identity.
* @author Paul Ferraro
*/
public class IdentityImmutability implements Immutability {

private final Set<Object> immutableObjects;

public IdentityImmutability(Collection<Object> objects) {
this.immutableObjects = !objects.isEmpty() ? Collections.newSetFromMap(new IdentityHashMap<>(objects.size())) : Collections.emptySet();
for (Object object : objects) {
this.immutableObjects.add(object);
}
}

@Override
public boolean test(Object object) {
return (object == null) || this.immutableObjects.contains(object);
}
}
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.immutable;

import org.wildfly.clustering.ee.Immutability;

/**
* Test for immutability using instanceof checks.
* @author Paul Ferraro
*/
public class InstanceOfImmutability implements Immutability {

private final Iterable<Class<?>> immutableClasses;

public InstanceOfImmutability(Iterable<Class<?>> immutableClasses) {
this.immutableClasses = immutableClasses;
}

@Override
public boolean test(Object object) {
for (Class<?> immutableClass : this.immutableClasses) {
if (immutableClass.isInstance(object)) return true;
}
return false;
}
}
@@ -0,0 +1,73 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee.immutable;

import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.function.Function;

import org.wildfly.clustering.ee.Immutability;

/**
* Immutability implementation based on a pre-defined set immutable classes.
* @author Paul Ferraro
*/
public class SimpleImmutability implements Immutability {

private final Set<Class<?>> immutableClasses;

public SimpleImmutability(ClassLoader loader, Collection<String> immutableClassNames) {
this(immutableClassNames, new Function<String, Class<?>>() {
@Override
public Class<?> apply(String className) {
try {
return loader.loadClass(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(className, e);
}
}
});
}

public SimpleImmutability(Collection<Class<?>> immutableClasses) {
this(immutableClasses, Function.identity());
}

private <T> SimpleImmutability(Collection<T> immutables, Function<T, Class<?>> operator) {
this.immutableClasses = !immutables.isEmpty() ? Collections.newSetFromMap(new IdentityHashMap<>(immutables.size())) : Collections.emptySet();
for (T immutable : immutables) {
this.immutableClasses.add(operator.apply(immutable));
}
}

public SimpleImmutability(Set<Class<?>> classes) {
this.immutableClasses = classes;
}

@Override
public boolean test(Object object) {
return (object == null) || this.immutableClasses.contains(object.getClass());
}
}
@@ -0,0 +1,61 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.junit.Assert;
import org.junit.Test;

/**
* Unit test for {@link CompositeIterable}.
* @author Paul Ferraro
*/
public class CompositeIterableTestCase {

@Test
public void test() {
Iterable<Integer> expected = IntStream.range(0, 10).mapToObj(Integer::valueOf).collect(Collectors.toList());

test(expected, new CompositeIterable<>(Arrays.asList(0, 1, 2, 3, 4), Arrays.asList(5, 6, 7, 8, 9)));
test(expected, new CompositeIterable<>(Arrays.asList(0, 1), Arrays.asList(2, 3), Arrays.asList(4, 5), Arrays.asList(6, 7), Arrays.asList(8, 9)));
test(expected, new CompositeIterable<>(Collections.emptyList(), expected, Collections.emptyList()));
}

static void test(Iterable<Integer> expected, Iterable<Integer> subject) {
Assert.assertEquals(expected.hashCode(), subject.hashCode());
Assert.assertEquals(expected.toString(), subject.toString());

Iterator<Integer> subjectIterator = subject.iterator();
Iterator<Integer> expectedIterator = expected.iterator();
while (expectedIterator.hasNext()) {
Assert.assertTrue(subjectIterator.hasNext());
Assert.assertEquals(expectedIterator.next(), subjectIterator.next());
}
Assert.assertFalse(subjectIterator.hasNext());
}
}
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.clustering.ee;
package org.wildfly.clustering.ee.immutable;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -53,10 +53,12 @@
import java.time.zone.ZoneOffsetTransitionRule;
import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
import java.time.zone.ZoneRules;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.Currency;
import java.util.Date;
import java.util.EnumSet;
import java.util.Locale;
import java.util.TimeZone;
import java.util.TreeMap;
@@ -65,23 +67,23 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;

import org.junit.Test;
import org.wildfly.clustering.ee.Immutability;

/**
* Unit test for {@link Immutability}
* Unit test for {@link DefaultImmutability}
*
* @author Paul Ferraro
*/
public class ImmutabilityTestCase {

@Test
public void test() throws Exception {
this.test(Immutability.INSTANCE);
this.test(new CompositeImmutability(EnumSet.allOf(DefaultImmutability.class)));
}

protected void test(Predicate<Object> immutability) throws Exception {
protected void test(Immutability immutability) throws Exception {
assertFalse(immutability.test(new Object()));
assertFalse(immutability.test(new Date()));
assertFalse(immutability.test(new AtomicInteger()));
@@ -151,6 +153,7 @@ protected void test(Predicate<Object> immutability) throws Exception {
assertTrue(immutability.test(Collections.singleton(new JCIPImmutableObject())));
assertTrue(immutability.test(Collections.singletonList(new JCIPImmutableObject())));
assertTrue(immutability.test(Collections.singletonMap("1", new JCIPImmutableObject())));
assertTrue(immutability.test(new AbstractMap.SimpleImmutableEntry<>("1", new JCIPImmutableObject())));

assertTrue(immutability.test(Collections.unmodifiableCollection(Arrays.asList("1", "2"))));
assertTrue(immutability.test(Collections.unmodifiableList(Arrays.asList("1", "2"))));
@@ -164,6 +167,7 @@ protected void test(Predicate<Object> immutability) throws Exception {
Object mutableObject = new AtomicInteger();
assertFalse(immutability.test(Collections.singletonList(mutableObject)));
assertFalse(immutability.test(Collections.singletonMap("1", mutableObject)));
assertFalse(immutability.test(new AbstractMap.SimpleImmutableEntry<>("1", mutableObject)));
}

@net.jcip.annotations.Immutable
@@ -21,7 +21,7 @@
*/
package org.wildfly.clustering.ejb.infinispan;

import java.util.Date;
import java.time.Instant;

/**
* The cache entry for a bean.
@@ -35,6 +35,6 @@
G getGroupId();
String getBeanName();

Date getLastAccessedTime();
void setLastAccessedTime(Date time);
Instant getLastAccessedTime();
void setLastAccessedTime(Instant time);
}
@@ -114,16 +114,22 @@ public void close() {
@Override
public void run() {
InfinispanEjbLogger.ROOT_LOGGER.tracef("Expiring stateful session bean %s", this.id);
boolean removed = false;
try (Batch batch = BeanExpirationScheduler.this.batcher.createBatch()) {
try {
BeanExpirationScheduler.this.remover.remove(this.id, BeanExpirationScheduler.this.expiration.getRemoveListener());
removed = BeanExpirationScheduler.this.remover.remove(this.id, BeanExpirationScheduler.this.expiration.getRemoveListener());
} catch (Throwable e) {
InfinispanEjbLogger.ROOT_LOGGER.failedToExpireBean(e, this.id);
batch.discard();
}
} finally {
synchronized (this) {
BeanExpirationScheduler.this.expirationFutures.remove(this.id);
if (removed) {
BeanExpirationScheduler.this.expirationFutures.remove(this.id);
} else {
// If bean failed to expire, likely due to a lock timeout, just reschedule it
BeanExpirationScheduler.this.schedule(this.id);
}
}
}
}
@@ -29,5 +29,11 @@
* @author Paul Ferraro
*/
public interface BeanRemover<K, V> {
void remove(K id, RemoveListener<V> listener);
/**
* Removes the specified bean, triggering the specified listener
* @param id a bean identifier
* @param listener a removal listener
* @return true, if the bean was (or was already) removed, false otherwise
*/
boolean remove(K id, RemoveListener<V> listener);
}
@@ -43,15 +43,17 @@ public ExpiredBeanRemover(BeanFactory<I, T> factory) {
}

@Override
public void remove(I id, RemoveListener<T> listener) {
public boolean remove(I id, RemoveListener<T> listener) {
BeanEntry<I> entry = this.factory.findValue(id);
@SuppressWarnings("resource")
Bean<I, T> bean = (entry != null) ? this.factory.createBean(id, entry) : null;
if (bean != null) {
if (bean.isExpired()) {
InfinispanEjbLogger.ROOT_LOGGER.tracef("Removing expired bean %s", id);
this.factory.remove(id, listener);
return this.factory.remove(id, listener);
}
return false;
}
return true;
}
}
@@ -190,8 +190,15 @@ public void stop() {
}

@Override
public boolean isRemotable(Throwable throwable) {
return !(throwable instanceof CacheException);
public boolean isRemotable(final Throwable throwable) {
Throwable subject = throwable;
while (subject != null) {
if (subject instanceof CacheException) {
return false;
}
subject = subject.getCause();
}
return true;
}

@Override
@@ -22,7 +22,7 @@
package org.wildfly.clustering.ejb.infinispan.bean;

import java.time.Duration;
import java.util.Date;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicBoolean;

import org.wildfly.clustering.ee.Mutator;
@@ -76,10 +76,10 @@ public I getGroupId() {

@Override
public boolean isExpired() {
if (this.timeout == null) return false;
Date lastAccessedTime = this.entry.getLastAccessedTime();
long timeout = this.timeout.toMillis();
return (lastAccessedTime != null) && (timeout > 0) ? ((System.currentTimeMillis() - lastAccessedTime.getTime()) >= timeout) : false;
if ((this.timeout == null) || this.timeout.isNegative()) return false;
if (this.timeout.isZero()) return true;
Instant lastAccessedTime = this.entry.getLastAccessedTime();
return (lastAccessedTime != null) ? !lastAccessedTime.plus(this.timeout).isAfter(Instant.now()) : false;
}

@Override
@@ -110,8 +110,8 @@ public boolean release() {
@Override
public void close() {
if (this.valid.get()) {
Date lastAccessedTime = this.entry.getLastAccessedTime();
this.entry.setLastAccessedTime(new Date());
Instant lastAccessedTime = this.entry.getLastAccessedTime();
this.entry.setLastAccessedTime(Instant.now());
if (lastAccessedTime != null) {
this.mutator.mutate();
}
@@ -23,7 +23,7 @@

import org.wildfly.clustering.ejb.infinispan.BeanEntry;

import java.util.Date;
import java.time.Instant;

/**
* The cache entry for a bean.
@@ -36,7 +36,7 @@

private final String beanName;
private final I groupId;
private volatile Date lastAccessedTime;
private volatile Instant lastAccessedTime;

public InfinispanBeanEntry(String beanName, I groupId) {
this.beanName = beanName;
@@ -54,12 +54,12 @@ public I getGroupId() {
}

@Override
public Date getLastAccessedTime() {
public Instant getLastAccessedTime() {
return this.lastAccessedTime;
}

@Override
public void setLastAccessedTime(Date time) {
public void setLastAccessedTime(Instant time) {
this.lastAccessedTime = time;
}
}
@@ -24,7 +24,7 @@
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Date;
import java.time.Instant;

import org.jboss.ejb.client.SessionID;
import org.kohsuke.MetaInfServices;
@@ -41,16 +41,16 @@
public void writeObject(ObjectOutput output, InfinispanBeanEntry<SessionID> entry) throws IOException {
output.writeUTF(entry.getBeanName());
SessionIDSerializer.INSTANCE.write(output, entry.getGroupId());
Date lastAccessedTime = entry.getLastAccessedTime();
output.writeLong((lastAccessedTime != null) ? lastAccessedTime.getTime() : 0);
Instant lastAccessedTime = entry.getLastAccessedTime();
output.writeLong((lastAccessedTime != null) ? lastAccessedTime.toEpochMilli() : 0L);
}

@Override
public InfinispanBeanEntry<SessionID> readObject(ObjectInput input) throws IOException, ClassNotFoundException {
InfinispanBeanEntry<SessionID> entry = new InfinispanBeanEntry<>(input.readUTF(), SessionIDSerializer.INSTANCE.read(input));
long time = input.readLong();
if (time > 0) {
entry.setLastAccessedTime(new Date(time));
long lastAccessedTime = input.readLong();
if (lastAccessedTime > 0L) {
entry.setLastAccessedTime(Instant.ofEpochMilli(lastAccessedTime));
}
return entry;
}
@@ -102,7 +102,7 @@ public InfinispanBeanFactory(String beanName, BeanGroupFactory<I, T> groupFactor
}

@Override
public void remove(I id, RemoveListener<T> listener) {
public boolean remove(I id, RemoveListener<T> listener) {
BeanEntry<I> entry = this.cache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).remove(this.createKey(id));
if (entry != null) {
I groupId = entry.getGroupId();
@@ -116,5 +116,6 @@ public void remove(I id, RemoveListener<T> listener) {
}
}
}
return true;
}
}
@@ -22,7 +22,10 @@
package org.wildfly.clustering.ejb.infinispan.group;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
@@ -139,19 +142,33 @@ public void passivated(CacheEntryPassivatedEvent<BeanGroupKey<I>, BeanGroupEntry
if (event.isPre()) {
BeanGroupEntry<I, T> entry = event.getValue();
try (BeanGroup<I, T> group = new InfinispanBeanGroup<>(event.getKey().getId(), entry, this.context, Mutator.PASSIVE, this)) {
for (I beanId : group.getBeans()) {
BeanKey<I> beanKey = new InfinispanBeanKey<>(beanId);
BeanEntry<I> beanEntry = this.beanCache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD).get(beanKey);
if ((beanEntry != null) && this.beanFilter.test(new AbstractMap.SimpleImmutableEntry<>(beanKey, beanEntry))) {
InfinispanEjbLogger.ROOT_LOGGER.tracef("Passivating bean %s", beanKey);
this.passiveCount.incrementAndGet();
group.prePassivate(beanId, this.passivationListener);
// Cascade evict to bean entry
this.beanCache.evict(beanKey);
Set<I> beans = group.getBeans();
List<I> notified = new ArrayList<>(beans.size());
try {
for (I beanId : beans) {
BeanKey<I> beanKey = new InfinispanBeanKey<>(beanId);
BeanEntry<I> beanEntry = this.beanCache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD).get(beanKey);
if ((beanEntry != null) && this.beanFilter.test(new AbstractMap.SimpleImmutableEntry<>(beanKey, beanEntry))) {
InfinispanEjbLogger.ROOT_LOGGER.tracef("Passivating bean %s", beanKey);
group.prePassivate(beanId, this.passivationListener);
notified.add(beanId);
// Cascade evict to bean entry
this.beanCache.evict(beanKey);
}
}
this.passiveCount.addAndGet(notified.size());
} catch (RuntimeException | Error e) {
// Restore state of pre-passivated beans
for (I beanId : notified) {
try {
group.postActivate(beanId, this.passivationListener);
} catch (RuntimeException | Error t) {
InfinispanEjbLogger.ROOT_LOGGER.warn(e.getLocalizedMessage(), e);
}
}
// Abort passivation if any beans failed to pre-passivate
throw e;
}
} catch (Exception e) {
InfinispanEjbLogger.ROOT_LOGGER.warn(e.getLocalizedMessage(), e);
}
}
}
@@ -167,11 +184,13 @@ public void activated(CacheEntryActivatedEvent<BeanGroupKey<I>, BeanGroupEntry<I
if ((beanEntry != null) && this.beanFilter.test(new AbstractMap.SimpleImmutableEntry<>(beanKey, beanEntry))) {
InfinispanEjbLogger.ROOT_LOGGER.tracef("Activating bean %s", beanKey);
this.passiveCount.decrementAndGet();
group.postActivate(beanId, this.passivationListener);
try {
group.postActivate(beanId, this.passivationListener);
} catch (RuntimeException | Error e) {
InfinispanEjbLogger.ROOT_LOGGER.warn(e.getLocalizedMessage(), e);
}
}
}
} catch (Exception e) {
InfinispanEjbLogger.ROOT_LOGGER.warn(e.getLocalizedMessage(), e);
}
}
}
@@ -73,6 +73,7 @@ public void testExpire() throws InterruptedException {

when(config.getTimeout()).thenReturn(Duration.ofMillis(1L));
when(config.getRemoveListener()).thenReturn(listener);
when(remover.remove(beanId, listener)).thenReturn(true);

try (Scheduler<String> scheduler = new BeanExpirationScheduler<>(batcher, remover, config)) {
scheduler.schedule(beanId);
@@ -96,6 +97,7 @@ public void testCancel() throws InterruptedException {

when(config.getTimeout()).thenReturn(Duration.ofMinutes(1L));
when(config.getRemoveListener()).thenReturn(listener);
when(remover.remove(beanId, listener)).thenReturn(true);

try (Scheduler<String> scheduler = new BeanExpirationScheduler<>(batcher, remover, config)) {
scheduler.schedule(beanId);
@@ -29,7 +29,7 @@
import static org.mockito.Mockito.when;

import java.time.Duration;
import java.util.Date;
import java.time.Instant;

import org.junit.After;
import org.junit.Assert;
@@ -93,11 +93,11 @@ public void isExpired() {
when(this.entry.getLastAccessedTime()).thenReturn(null);
Assert.assertFalse(this.bean.isExpired());

long now = System.currentTimeMillis();
when(this.entry.getLastAccessedTime()).thenReturn(new Date(now));
Instant now = Instant.now();
when(this.entry.getLastAccessedTime()).thenReturn(now);
Assert.assertFalse(this.bean.isExpired());

when(this.entry.getLastAccessedTime()).thenReturn(new Date(now - this.timeout.toMillis() - 1));
when(this.entry.getLastAccessedTime()).thenReturn(now.minus(this.timeout));
Assert.assertTrue(this.bean.isExpired());
}

@@ -123,18 +123,18 @@ public void close() {

this.bean.close();

verify(this.entry).setLastAccessedTime(ArgumentMatchers.<Date>any());
verify(this.entry).setLastAccessedTime(ArgumentMatchers.<Instant>any());
verify(this.mutator, never()).mutate();
verify(this.group, never()).close();

reset(this.entry, this.mutator, this.group);

when(this.entry.getLastAccessedTime()).thenReturn(new Date());
when(this.entry.getLastAccessedTime()).thenReturn(Instant.now());
when(this.group.isCloseable()).thenReturn(true);

this.bean.close();

verify(this.entry).setLastAccessedTime(ArgumentMatchers.<Date>any());
verify(this.entry).setLastAccessedTime(ArgumentMatchers.<Instant>any());
verify(this.mutator).mutate();
verify(this.group).close();
}
@@ -0,0 +1,52 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.ChildResourceDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class CacheComponentRuntimeResourceDefinition extends ChildResourceDefinition<ManagementResourceRegistration> {

static final PathElement WILDCARD_PATH = pathElement(PathElement.WILDCARD_VALUE);

static final PathElement pathElement(String name) {
return PathElement.pathElement("component", name);
}

CacheComponentRuntimeResourceDefinition(PathElement path) {
this(path, path);
}

CacheComponentRuntimeResourceDefinition(PathElement path, PathElement resolverPath) {
super(new Parameters(path, InfinispanExtension.SUBSYSTEM_RESOLVER.createChildResolver(resolverPath)).setRuntime());
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
return parent.registerSubModel(this);
}
}
@@ -34,6 +34,7 @@
import org.infinispan.configuration.cache.LockingConfiguration;
import org.infinispan.configuration.cache.MemoryConfiguration;
import org.infinispan.configuration.cache.PersistenceConfiguration;
import org.infinispan.configuration.cache.StorageType;
import org.infinispan.configuration.cache.TransactionConfiguration;
import org.infinispan.distribution.group.Grouper;
import org.jboss.as.clustering.controller.CapabilityServiceNameProvider;
@@ -81,9 +82,11 @@
String containerName = address.getParent().getLastElement().getValue();
String cacheName = address.getLastElement().getValue();
this.configurator = new ConfigurationServiceConfigurator(this.getServiceName(), containerName, cacheName, this.andThen(builder -> {
GroupsConfigurationBuilder groupsBuilder = builder.clustering().hash().groups().enabled();
for (Grouper<?> grouper : this.module.get().loadService(Grouper.class)) {
groupsBuilder.addGrouper(grouper);
if (builder.memory().storageType() == StorageType.OBJECT) {
GroupsConfigurationBuilder groupsBuilder = builder.clustering().hash().groups().enabled();
for (Grouper<?> grouper : this.module.get().loadService(Grouper.class)) {
groupsBuilder.addGrouper(grouper);
}
}
})).require(this);
}
@@ -35,33 +35,33 @@
*/
public enum CacheContainerMetric implements Metric<EmbeddedCacheManager> {

CACHE_MANAGER_STATUS(MetricKeys.CACHE_MANAGER_STATUS, ModelType.STRING) {
CACHE_MANAGER_STATUS("cache-manager-status", ModelType.STRING) {
@Override
public ModelNode execute(EmbeddedCacheManager manager) {
return new ModelNode(manager.getStatus().toString());
}
},
CLUSTER_NAME(MetricKeys.CLUSTER_NAME, ModelType.STRING) {
CLUSTER_NAME("cluster-name", ModelType.STRING) {
@Override
public ModelNode execute(EmbeddedCacheManager manager) {
String clusterName = manager.getClusterName();
return (clusterName != null) ? new ModelNode(clusterName) : null;
}
},
COORDINATOR_ADDRESS(MetricKeys.COORDINATOR_ADDRESS, ModelType.STRING) {
COORDINATOR_ADDRESS("coordinator-address", ModelType.STRING) {
@Override
public ModelNode execute(EmbeddedCacheManager manager) {
Address address = manager.getCoordinator();
return (address != null) ? new ModelNode(address.toString()) : null;
}
},
IS_COORDINATOR(MetricKeys.IS_COORDINATOR, ModelType.BOOLEAN) {
IS_COORDINATOR("is-coordinator", ModelType.BOOLEAN) {
@Override
public ModelNode execute(EmbeddedCacheManager manager) {
return new ModelNode(manager.isCoordinator());
}
},
LOCAL_ADDRESS(MetricKeys.LOCAL_ADDRESS, ModelType.STRING) {
LOCAL_ADDRESS("local-address", ModelType.STRING) {
@Override
public ModelNode execute(EmbeddedCacheManager manager) {
Address address = manager.getAddress();
@@ -0,0 +1,60 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import java.util.Collections;
import java.util.Map;

import org.jboss.as.clustering.controller.ChildResourceProvider;
import org.jboss.as.clustering.controller.ComplexResource;
import org.jboss.as.controller.registry.Resource;
import org.wildfly.clustering.Registrar;
import org.wildfly.clustering.Registration;

/**
* @author Paul Ferraro
*/
public class CacheContainerResource extends ComplexResource implements Registrar<String> {

private static final String CHILD_TYPE = CacheRuntimeResourceDefinition.WILDCARD_PATH.getKey();

public CacheContainerResource(Resource resource) {
this(resource, Collections.singletonMap(CHILD_TYPE, new CacheRuntimeResourceProvider()));
}

private CacheContainerResource(Resource resource, Map<String, ChildResourceProvider> providers) {
super(resource, providers, CacheContainerResource::new);
}

@Override
public Registration register(String cache) {
ChildResourceProvider handler = this.apply(CHILD_TYPE);
handler.getChildren().add(cache);
return new Registration() {
@Override
public void close() {
handler.getChildren().remove(cache);
}
};
}
}
@@ -288,6 +288,8 @@ public ModelNode transformOperation(ModelNode operation) {
ReplicatedCacheResourceDefinition.buildTransformation(version, builder);
InvalidationCacheResourceDefinition.buildTransformation(version, builder);
LocalCacheResourceDefinition.buildTransformation(version, builder);

CacheRuntimeResourceDefinition.buildTransformation(version, builder);
}

CacheContainerResourceDefinition() {
@@ -308,6 +310,7 @@ public ManagementResourceRegistration register(ManagementResourceRegistration pa
.addRequiredChildren(EnumSet.complementOf(EnumSet.of(ThreadPoolResourceDefinition.CLIENT)))
.addRequiredChildren(ScheduledThreadPoolResourceDefinition.class)
.addRequiredSingletonChildren(NoTransportResourceDefinition.PATH)
.setResourceTransformation(CacheContainerResource::new)
;
ResourceServiceHandler handler = new CacheContainerServiceHandler();
new SimpleResourceRegistration(descriptor, handler).register(registration);
@@ -336,6 +339,7 @@ public void execute(OperationContext context, ModelNode legacyOperation) throws

if (registration.isRuntimeOnlyRegistrationValid()) {
new MetricHandler<>(new CacheContainerMetricExecutor(), CacheContainerMetric.class).register(registration);
new CacheRuntimeResourceDefinition().register(registration);
}

new JGroupsTransportResourceDefinition().register(registration);
@@ -27,6 +27,8 @@
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -58,6 +60,8 @@
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.wildfly.clustering.Registrar;
import org.wildfly.clustering.Registration;
import org.wildfly.clustering.infinispan.spi.CacheContainer;
import org.wildfly.clustering.infinispan.spi.InfinispanRequirement;
import org.wildfly.clustering.service.FunctionalService;
@@ -70,10 +74,13 @@
@Listener
public class CacheContainerServiceConfigurator extends CapabilityServiceNameProvider implements ResourceServiceConfigurator, Function<EmbeddedCacheManager, CacheContainer>, Supplier<EmbeddedCacheManager>, Consumer<EmbeddedCacheManager> {

private final Map<String, Registration> registrations = new ConcurrentHashMap<>();
private final List<ServiceName> aliases = new LinkedList<>();
private final String name;
private final SupplierDependency<GlobalConfiguration> configuration;

private volatile Registrar<String> registrar;

public CacheContainerServiceConfigurator(PathAddress address) {
super(CONTAINER, address);
this.name = address.getLastElement().getValue();
@@ -121,6 +128,7 @@ public CacheContainerServiceConfigurator configure(OperationContext context, Mod
for (ModelNode alias : ModelNodes.optionalList(ALIASES.resolveModelAttribute(context, model)).orElse(Collections.emptyList())) {
this.aliases.add(InfinispanRequirement.CONTAINER.getServiceName(context.getCapabilityServiceSupport(), alias.asString()));
}
this.registrar = (CacheContainerResource) context.readResource(PathAddress.EMPTY_ADDRESS);
return this;
}

@@ -137,11 +145,16 @@ public CacheContainerServiceConfigurator configure(OperationContext context, Mod

@CacheStarted
public void cacheStarted(CacheStartedEvent event) {
InfinispanLogger.ROOT_LOGGER.cacheStarted(event.getCacheName(), this.name);
String cacheName = event.getCacheName();
InfinispanLogger.ROOT_LOGGER.cacheStarted(cacheName, this.name);
this.registrations.put(cacheName, this.registrar.register(cacheName));
}

@CacheStopped
public void cacheStopped(CacheStoppedEvent event) {
InfinispanLogger.ROOT_LOGGER.cacheStopped(event.getCacheName(), this.name);
String cacheName = event.getCacheName();
try (Registration registration = this.registrations.remove(cacheName)) {
InfinispanLogger.ROOT_LOGGER.cacheStopped(cacheName, this.name);
}
}
}
@@ -39,111 +39,111 @@
*/
public enum CacheMetric implements Metric<Cache<?, ?>> {

ACTIVATIONS(MetricKeys.ACTIVATIONS, ModelType.LONG) {
ACTIVATIONS("activations", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
ActivationManager manager = cache.getAdvancedCache().getComponentRegistry().getComponent(ActivationManager.class);
return new ModelNode((manager != null) ? manager.getActivationCount() : 0);
}
},
AVERAGE_READ_TIME(MetricKeys.AVERAGE_READ_TIME, ModelType.LONG) {
AVERAGE_READ_TIME("average-read-time", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getAverageReadTime() : 0);
}
},
AVERAGE_WRITE_TIME(MetricKeys.AVERAGE_WRITE_TIME, ModelType.LONG) {
AVERAGE_WRITE_TIME("average-write-time", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getAverageWriteTime() : 0);
}
},
CACHE_STATUS(MetricKeys.CACHE_STATUS, ModelType.STRING) {
CACHE_STATUS("cache-status", ModelType.STRING) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
return new ModelNode(cache.getStatus().toString());
}
},
ELAPSED_TIME(MetricKeys.ELAPSED_TIME, ModelType.LONG) {
ELAPSED_TIME("elapsed-time", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getTimeSinceStart() : 0);
}
},
HIT_RATIO(MetricKeys.HIT_RATIO, ModelType.DOUBLE) {
HIT_RATIO("hit-ratio", ModelType.DOUBLE) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getHitRatio() : 0);
}
},
HITS(MetricKeys.HITS, ModelType.LONG) {
HITS("hits", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getHits() : 0);
}
},
INVALIDATIONS(MetricKeys.INVALIDATIONS, ModelType.LONG) {
INVALIDATIONS("invalidations", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
InvalidationInterceptor interceptor = findInterceptor(cache, InvalidationInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getInvalidations() : 0);
}
},
MISSES(MetricKeys.MISSES, ModelType.LONG) {
MISSES("misses", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getMisses() : 0);
}
},
NUMBER_OF_ENTRIES(MetricKeys.NUMBER_OF_ENTRIES, ModelType.INT) {
NUMBER_OF_ENTRIES("number-of-entries", ModelType.INT) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getNumberOfEntries() : 0);
}
},
PASSIVATIONS(MetricKeys.PASSIVATIONS, ModelType.LONG) {
PASSIVATIONS("passivations", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
PassivationManager manager = cache.getAdvancedCache().getComponentRegistry().getComponent(PassivationManager.class);
return new ModelNode((manager != null) ? manager.getPassivations() : 0);
}
},
READ_WRITE_RATIO(MetricKeys.READ_WRITE_RATIO, ModelType.DOUBLE) {
READ_WRITE_RATIO("read-write-ratio", ModelType.DOUBLE) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getReadWriteRatio() : 0);
}
},
REMOVE_HITS(MetricKeys.REMOVE_HITS, ModelType.LONG) {
REMOVE_HITS("remove-hits", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getRemoveHits() : 0);
}
},
REMOVE_MISSES(MetricKeys.REMOVE_MISSES, ModelType.LONG) {
REMOVE_MISSES("remove-misses", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getRemoveMisses() : 0);
}
},
STORES(MetricKeys.STORES, ModelType.LONG) {
STORES("stores", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
return new ModelNode((interceptor != null) ? interceptor.getStores() : 0);
}
},
TIME_SINCE_RESET(MetricKeys.TIME_SINCE_RESET, ModelType.LONG) {
TIME_SINCE_RESET("time-since-reset", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = findInterceptor(cache, CacheMgmtInterceptor.class);
@@ -0,0 +1,64 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.ChildResourceDefinition;
import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder;

/**
* @author Paul Ferraro
*/
public class CacheRuntimeResourceDefinition extends ChildResourceDefinition<ManagementResourceRegistration> {

static final PathElement WILDCARD_PATH = PathElement.pathElement("cache");

static void buildTransformation(ModelVersion version, ResourceTransformationDescriptionBuilder parent) {
if (InfinispanModel.VERSION_10_0_0.requiresTransformation(version)) {
parent.discardChildResource(WILDCARD_PATH);
}
}

CacheRuntimeResourceDefinition() {
super(new Parameters(WILDCARD_PATH, InfinispanExtension.SUBSYSTEM_RESOLVER.createChildResolver(WILDCARD_PATH)).setRuntime());
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = parent.registerSubModel(this);

new MetricHandler<>(new CacheMetricExecutor(), CacheMetric.class).register(registration);
new MetricHandler<>(new ClusteredCacheMetricExecutor(), ClusteredCacheMetric.class).register(registration);

new LockingRuntimeResourceDefinition().register(registration);
new MemoryRuntimeResourceDefinition().register(registration);
new PartitionHandlingRuntimeResourceDefinition().register(registration);
new PersistenceRuntimeResourceDefinition().register(registration);
new TransactionRuntimeResourceDefinition().register(registration);

return registration;
}
}
@@ -0,0 +1,51 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;

import org.jboss.as.clustering.controller.ChildResourceProvider;
import org.jboss.as.clustering.controller.ComplexResource;
import org.jboss.as.clustering.controller.SimpleChildResourceProvider;
import org.jboss.as.controller.registry.PlaceholderResource;
import org.wildfly.common.function.Functions;

/**
* @author Paul Ferraro
*/
public class CacheRuntimeResourceProvider extends SimpleChildResourceProvider {

private static final ChildResourceProvider CHILD_PROVIDER = new SimpleChildResourceProvider(Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
LockingRuntimeResourceDefinition.PATH.getValue(),
MemoryRuntimeResourceDefinition.PATH.getValue(),
PersistenceRuntimeResourceDefinition.PATH.getValue(),
PartitionHandlingRuntimeResourceDefinition.PATH.getValue(),
TransactionRuntimeResourceDefinition.PATH.getValue()))));

public CacheRuntimeResourceProvider() {
super(ConcurrentHashMap.newKeySet(), Functions.constantSupplier(new ComplexResource(PlaceholderResource.INSTANCE, Collections.singletonMap(CacheComponentRuntimeResourceDefinition.WILDCARD_PATH.getKey(), CHILD_PROVIDER))));
}
}
@@ -34,25 +34,25 @@
*/
public enum ClusteredCacheMetric implements Metric<RpcManagerImpl> {

AVERAGE_REPLICATION_TIME(MetricKeys.AVERAGE_REPLICATION_TIME, ModelType.LONG) {
AVERAGE_REPLICATION_TIME("average-replication-time", ModelType.LONG) {
@Override
public ModelNode execute(RpcManagerImpl manager) {
return new ModelNode(manager.getAverageReplicationTime());
}
},
REPLICATION_COUNT(MetricKeys.REPLICATION_COUNT, ModelType.LONG) {
REPLICATION_COUNT("replication-count", ModelType.LONG) {
@Override
public ModelNode execute(RpcManagerImpl manager) {
return new ModelNode(manager.getReplicationCount());
}
},
REPLICATION_FAILURES(MetricKeys.REPLICATION_FAILURES, ModelType.LONG) {
REPLICATION_FAILURES("replication-failures", ModelType.LONG) {
@Override
public ModelNode execute(RpcManagerImpl manager) {
return new ModelNode(manager.getReplicationFailures());
}
},
SUCCESS_RATIO(MetricKeys.SUCCESS_RATIO, ModelType.DOUBLE) {
SUCCESS_RATIO("success-ratio", ModelType.DOUBLE) {
@Override
public ModelNode execute(RpcManagerImpl manager) {
return new ModelNode(manager.getSuccessRatio());
@@ -44,6 +44,7 @@ public ModelNode execute(OperationContext context, Metric<RpcManagerImpl> metric

Cache<?, ?> cache = new PassiveServiceSupplier<Cache<?, ?>>(context.getServiceRegistry(true), InfinispanCacheRequirement.CACHE.getServiceName(context, containerName, cacheName)).get();

return (cache != null) ? metric.execute((RpcManagerImpl) cache.getAdvancedCache().getRpcManager()) : null;
RpcManagerImpl manager = (cache != null) ? (RpcManagerImpl) cache.getAdvancedCache().getRpcManager() : null;
return (manager != null) ? metric.execute(manager) : null;
}
}
@@ -32,7 +32,7 @@
*/
public enum EvictionMetric implements Metric<Cache<?, ?>> {

EVICTIONS(MetricKeys.EVICTIONS, ModelType.LONG) {
EVICTIONS("evictions", ModelType.LONG) {
@Override
public ModelNode execute(Cache<?, ?> cache) {
CacheMgmtInterceptor interceptor = CacheMetric.findInterceptor(cache, CacheMgmtInterceptor.class);
@@ -40,8 +40,9 @@
VERSION_7_0_0(7, 0, 0), // WildFly 13
VERSION_8_0_0(8, 0, 0), // WildFly 14-15, EAP 7.2
VERSION_9_0_0(9, 0, 0), // WildFly 16
VERSION_10_0_0(10, 0, 0), // WildFly 17
;
static final InfinispanModel CURRENT = VERSION_9_0_0;
static final InfinispanModel CURRENT = VERSION_10_0_0;

private final ModelVersion version;

@@ -35,19 +35,19 @@
*/
public enum LockingMetric implements Metric<DefaultLockManager> {

CURRENT_CONCURRENCY_LEVEL(MetricKeys.CURRENT_CONCURRENCY_LEVEL, ModelType.INT) {
CURRENT_CONCURRENCY_LEVEL("current-concurrency-level", ModelType.INT) {
@Override
public ModelNode execute(DefaultLockManager manager) {
return new ModelNode(manager.getConcurrencyLevel());
}
},
NUMBER_OF_LOCKS_AVAILABLE(MetricKeys.NUMBER_OF_LOCKS_AVAILABLE, ModelType.INT) {
NUMBER_OF_LOCKS_AVAILABLE("number-of-locks-available", ModelType.INT) {
@Override
public ModelNode execute(DefaultLockManager manager) {
return new ModelNode(manager.getNumberOfLocksAvailable());
}
},
NUMBER_OF_LOCKS_HELD(MetricKeys.NUMBER_OF_LOCKS_HELD, ModelType.INT) {
NUMBER_OF_LOCKS_HELD("number-of-locks-held", ModelType.INT) {
@Override
public ModelNode execute(DefaultLockManager manager) {
return new ModelNode(manager.getNumberOfLocksHeld());
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class LockingRuntimeResourceDefinition extends CacheComponentRuntimeResourceDefinition {

static final PathElement PATH = pathElement("locking");

LockingRuntimeResourceDefinition() {
super(PATH);
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = super.register(parent);
new MetricHandler<>(new LockingMetricExecutor(), LockingMetric.class).register(registration);
return registration;
}
}
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class MemoryRuntimeResourceDefinition extends CacheComponentRuntimeResourceDefinition {

static final PathElement PATH = pathElement("memory");

MemoryRuntimeResourceDefinition() {
super(PATH, MemoryResourceDefinition.WILDCARD_PATH);
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = super.register(parent);
new MetricHandler<>(new EvictionMetricExecutor(), EvictionMetric.class).register(registration);
return registration;
}
}

This file was deleted.

@@ -0,0 +1,48 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.clustering.controller.OperationHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class PartitionHandlingRuntimeResourceDefinition extends CacheComponentRuntimeResourceDefinition {

static final PathElement PATH = pathElement("partition-handling");

PartitionHandlingRuntimeResourceDefinition() {
super(PATH);
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = super.register(parent);
new MetricHandler<>(new PartitionHandlingMetricExecutor(), PartitionHandlingMetric.class).register(registration);
new OperationHandler<>(new PartitionHandlingOperationExecutor(), PartitionHandlingOperation.class).register(registration);
return registration;
}
}
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class PersistenceRuntimeResourceDefinition extends CacheComponentRuntimeResourceDefinition {

static final PathElement PATH = pathElement("persistence");

PersistenceRuntimeResourceDefinition() {
super(PATH, StoreResourceDefinition.WILDCARD_PATH);
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = super.register(parent);
new MetricHandler<>(new StoreMetricExecutor(), StoreMetric.class).register(registration);
return registration;
}
}
@@ -35,13 +35,13 @@
*/
public enum StoreMetric implements Metric<CacheLoaderInterceptor<?, ?>> {

CACHE_LOADER_LOADS(MetricKeys.CACHE_LOADER_LOADS, ModelType.LONG) {
CACHE_LOADER_LOADS("cache-loader-loads", ModelType.LONG) {
@Override
public ModelNode execute(CacheLoaderInterceptor<?, ?> interceptor) {
return new ModelNode(interceptor.getCacheLoaderLoads());
}
},
CACHE_LOADER_MISSES(MetricKeys.CACHE_LOADER_MISSES, ModelType.LONG) {
CACHE_LOADER_MISSES("cache-loader-misses", ModelType.LONG) {
@Override
public ModelNode execute(CacheLoaderInterceptor<?, ?> interceptor) {
return new ModelNode(interceptor.getCacheLoaderMisses());
@@ -35,19 +35,19 @@
*/
public enum TransactionMetric implements Metric<TxInterceptor<?, ?>> {

COMMITS(MetricKeys.COMMITS, ModelType.LONG) {
COMMITS("commits", ModelType.LONG) {
@Override
public ModelNode execute(TxInterceptor<?, ?> interceptor) {
return new ModelNode(interceptor.getCommits());
}
},
PREPARES(MetricKeys.PREPARES, ModelType.LONG) {
PREPARES("prepares", ModelType.LONG) {
@Override
public ModelNode execute(TxInterceptor<?, ?> interceptor) {
return new ModelNode(interceptor.getPrepares());
}
},
ROLLBACKS(MetricKeys.ROLLBACKS, ModelType.LONG) {
ROLLBACKS("rollbacks", ModelType.LONG) {
@Override
public ModelNode execute(TxInterceptor<?, ?> interceptor) {
return new ModelNode(interceptor.getRollbacks());
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.infinispan.subsystem;

import org.jboss.as.clustering.controller.MetricHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.ManagementResourceRegistration;

/**
* @author Paul Ferraro
*/
public class TransactionRuntimeResourceDefinition extends CacheComponentRuntimeResourceDefinition {

static final PathElement PATH = pathElement("transaction");

TransactionRuntimeResourceDefinition() {
super(PATH);
}

@Override
public ManagementResourceRegistration register(ManagementResourceRegistration parent) {
ManagementResourceRegistration registration = super.register(parent);
new MetricHandler<>(new TransactionMetricExecutor(), TransactionMetric.class).register(registration);
return registration;
}
}
@@ -59,7 +59,7 @@
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
<replicated-cache name="dist">
<replicated-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</replicated-cache>
@@ -26,6 +26,7 @@
import static org.jboss.as.clustering.jgroups.subsystem.AbstractProtocolResourceDefinition.Attribute.PROPERTIES;
import static org.jboss.as.clustering.jgroups.subsystem.AbstractProtocolResourceDefinition.Attribute.STATISTICS_ENABLED;

import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashMap;
@@ -130,4 +131,14 @@ public final P createProtocol(ProtocolStackConfiguration stackConfiguration) {
throw new IllegalArgumentException(e);
}
}

void setValue(P protocol, String propertyName, Object propertyValue) {
PrivilegedAction<P> action = new PrivilegedAction<P>() {
@Override
public P run() {
return protocol.setValue(propertyName, propertyValue);
}
};
WildFlySecurityManager.doUnchecked(action);
}
}
@@ -36,9 +36,10 @@
VERSION_4_0_0(4, 0, 0), // WildFly 10, EAP 7.0
VERSION_4_1_0(4, 1, 0), // WildFly 10.1
VERSION_5_0_0(5, 0, 0), // WildFly 11, EAP 7.1
VERSION_6_0_0(6, 0, 0), // WildFly 12-15, EAP 7.2
VERSION_6_0_0(6, 0, 0), // WildFly 12-16, EAP 7.2
VERSION_7_0_0(7, 0, 0), // WildFly 17
;
static final JGroupsModel CURRENT = VERSION_6_0_0;
static final JGroupsModel CURRENT = VERSION_7_0_0;

private final ModelVersion version;