You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/10/03 10:49:40 UTC
[isis] branch v2 updated: ISIS-2158: spec-loading: fixes another
concurrent modification issue
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/v2 by this push:
new 24438df ISIS-2158: spec-loading: fixes another concurrent modification issue
24438df is described below
commit 24438dfeb853a0ceef04e00a3aec4d07210053b0
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Oct 3 12:49:33 2019 +0200
ISIS-2158: spec-loading: fixes another concurrent modification issue
---
.../isis/commons/internal/collections/_Lists.java | 10 ++--
.../commons/internal/collections/_Multimaps.java | 53 +++++++++++++++++++---
.../isis/metamodel/facets/CollectionUtils.java | 2 +-
.../specimpl/ObjectSpecificationAbstract.java | 17 ++-----
4 files changed, 57 insertions(+), 25 deletions(-)
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
index 7e1f99f..8f734ac 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
@@ -150,19 +150,19 @@ public final class _Lists {
// -- COPY ON WRITE LIST
- public static <T> CopyOnWriteArrayList<T> newCopyOnWriteArrayList() {
+ public static <T> CopyOnWriteArrayList<T> newConcurrentList() {
return new CopyOnWriteArrayList<T>();
}
- public static <T> CopyOnWriteArrayList<T> newCopyOnWriteArrayList(@Nullable Collection<T> collection) {
+ public static <T> CopyOnWriteArrayList<T> newConcurrentList(@Nullable Collection<T> collection) {
if(collection==null) {
- return newCopyOnWriteArrayList();
+ return newConcurrentList();
}
return new CopyOnWriteArrayList<T>(collection);
}
- public static <T> CopyOnWriteArrayList<T> newCopyOnWriteArrayList(@Nullable Iterable<T> iterable) {
- return _Collections.collectFromIterable(iterable, _Lists::newCopyOnWriteArrayList,
+ public static <T> CopyOnWriteArrayList<T> newConcurrentList(@Nullable Iterable<T> iterable) {
+ return _Collections.collectFromIterable(iterable, _Lists::newConcurrentList,
()->Collectors.<T, CopyOnWriteArrayList<T>>toCollection(CopyOnWriteArrayList::new) );
}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
index 464df9a..94681af 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
@@ -32,6 +32,7 @@ import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import javax.annotation.Nullable;
@@ -40,6 +41,8 @@ import org.apache.isis.commons.internal.base._Casts;
import static org.apache.isis.commons.internal.base._With.requires;
+import lombok.val;
+
/**
* <h1>- internal use only -</h1>
* <p>
@@ -67,6 +70,8 @@ public class _Multimaps {
* @param value
*/
public void putElement(K key, V value);
+
+ public List<V> getOrElseNew(K key);
}
/**
@@ -82,6 +87,8 @@ public class _Multimaps {
* @param value
*/
public void putElement(K key, V value);
+
+ public Set<V> getOrElseNew(K key);
}
/**
@@ -108,6 +115,8 @@ public class _Multimaps {
* @return null if no such element exists
*/
public V getElement(K1 key, K2 subkey);
+
+ public Map<K2, V> getOrElseNew(K1 key);
}
public static <K, V> ListMultimap<K, V> newListMultimap(
@@ -135,8 +144,13 @@ public class _Multimaps {
@Override
public void putElement(K key, V value) {
- final Collection<V> collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get());
- collection.add(value);
+ getOrElseNew(key).add(value);
+ }
+
+ @Override
+ public List<V> getOrElseNew(K key) {
+ val collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get());
+ return collection;
}
};
@@ -167,8 +181,13 @@ public class _Multimaps {
@Override
public void putElement(K key, V value) {
- final Collection<V> collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get());
- collection.add(value);
+ getOrElseNew(key).add(value);
+ }
+
+ @Override
+ public Set<V> getOrElseNew(K key) {
+ val collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get());
+ return collection;
}
};
@@ -199,8 +218,7 @@ public class _Multimaps {
@Override
public void putElement(K1 key, K2 subkey, V value) {
- final Map<K2, V> elementMap = delegate.computeIfAbsent(key, __->elementMapFactory.get());
- elementMap.put(subkey, value);
+ getOrElseNew(key).put(subkey, value);
}
@Override
@@ -208,6 +226,12 @@ public class _Multimaps {
final Map<K2, V> elementMap = delegate.get(key);
return elementMap!=null ? elementMap.get(subkey) : null;
}
+
+ @Override
+ public Map<K2, V> getOrElseNew(K1 key) {
+ val elementMap = delegate.computeIfAbsent(key, __->elementMapFactory.get());
+ return elementMap;
+ }
};
}
@@ -220,6 +244,13 @@ public class _Multimaps {
public static <K, V> ListMultimap<K, V> newListMultimap(){
return newListMultimap(HashMap<K, List<V>>::new, ArrayList::new);
}
+
+ /**
+ * @return ConcurrentHashMap of CopyOnWriteArrayList (fully concurrent)
+ */
+ public static <K, V> ListMultimap<K, V> newConcurrentListMultimap(){
+ return newListMultimap(ConcurrentHashMap<K, List<V>>::new, CopyOnWriteArrayList::new);
+ }
/**
* @return HashMap of HashSets
@@ -227,6 +258,14 @@ public class _Multimaps {
public static <K, V> SetMultimap<K, V> newSetMultimap(){
return newSetMultimap(HashMap<K, Set<V>>::new, HashSet::new);
}
+
+ /**
+ * @return ConcurrentHashMap of ConcurrentHashMap-key-sets (fully concurrent)
+ */
+ public static <K, V> SetMultimap<K, V> newConcurrentSetMultimap(){
+ return newSetMultimap(ConcurrentHashMap<K, Set<V>>::new, _Sets::newConcurrentHashSet);
+ }
+
/**
* @param keyComparator - if {@code null} uses natural ordering
@@ -250,7 +289,7 @@ public class _Multimaps {
}
/**
- * @return ConcurrentHashMap of HashMaps
+ * @return ConcurrentHashMap of HashMaps (not fully concurrent)
*/
public static <K1, K2, V> MapMultimap<K1, K2, V> newConcurrentMapMultimap(){
return newMapMultimap(ConcurrentHashMap<K1, Map<K2, V>>::new, HashMap::new);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/CollectionUtils.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/CollectionUtils.java
index a3186dc..5e985e7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/CollectionUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/CollectionUtils.java
@@ -66,7 +66,7 @@ public final class CollectionUtils {
private final static Map<Class<?>, Function<Iterable<Object>, Object>> factoriesByType = _With.hashMap(
map-> {
// specific list implementations
- map.put(CopyOnWriteArrayList.class, _Lists::newCopyOnWriteArrayList);
+ map.put(CopyOnWriteArrayList.class, _Lists::newConcurrentList);
map.put(LinkedList.class, _Lists::newLinkedList);
map.put(ArrayList.class, _Lists::newArrayList);
map.put(AbstractList.class, _Lists::newArrayList);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index f16ba31..9c07cf6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -38,7 +37,8 @@ import org.apache.isis.commons.exceptions.UnknownTypeException;
import org.apache.isis.commons.internal.base._NullSafe;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.collections._Multimaps;
+import org.apache.isis.commons.internal.collections._Multimaps.ListMultimap;
import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.commons.internal.ioc.BeanAdapter;
import org.apache.isis.commons.internal.ioc.BeanSort;
@@ -159,15 +159,8 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
private final List<ObjectAction> objectActions = _Lists.newArrayList();
// partitions and caches objectActions by type; updated in sortCacheAndUpdateActions()
- private final Map<ActionType, List<ObjectAction>> objectActionsByType = createObjectActionsByType();
-
- private static Map<ActionType, List<ObjectAction>> createObjectActionsByType() {
- final Map<ActionType, List<ObjectAction>> map = _Maps.newHashMap();
- for (final ActionType type : ActionType.values()) {
- map.put(type, _Lists.<ObjectAction>newArrayList());
- }
- return map;
- }
+ private final ListMultimap<ActionType, ObjectAction> objectActionsByType =
+ _Multimaps.newConcurrentListMultimap();
private final List<ObjectSpecification> interfaces = _Lists.newArrayList();
private final Subclasses directSubclasses = new Subclasses();
@@ -376,7 +369,7 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
this.objectActions.addAll(orderedActions);
for (final ActionType type : ActionType.values()) {
- final List<ObjectAction> objectActionForType = objectActionsByType.get(type);
+ val objectActionForType = objectActionsByType.getOrElseNew(type);
objectActionForType.clear();
objectActions.stream()
.filter(ObjectAction.Predicates.ofType(type))