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/04/04 12:54:11 UTC
[isis] branch 2033-IoC_spring updated: ISIS-2033: make SpecLoader's
specs snapshot thread-safe
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch 2033-IoC_spring
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/2033-IoC_spring by this push:
new f1398a0 ISIS-2033: make SpecLoader's specs snapshot thread-safe
f1398a0 is described below
commit f1398a024b07a65049e727ab01401b77f0f896e5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Apr 4 14:54:04 2019 +0200
ISIS-2033: make SpecLoader's specs snapshot thread-safe
Task-Url: https://issues.apache.org/jira/browse/ISIS-2033
---
.../domainobject/DomainObjectAnnotationFacetFactory.java | 2 +-
.../appfeat/ApplicationFeatureRepositoryDefault.java | 2 +-
.../metamodel/services/layout/LayoutServiceDefault.java | 2 +-
.../metamodel/services/metamodel/MetaModelExporter.java | 2 +-
.../services/metamodel/MetaModelServiceDefault.java | 2 +-
.../metamodel/services/swagger/internal/Generation.java | 4 ++--
.../core/metamodel/specloader/SpecificationLoader.java | 11 ++++++-----
.../metamodel/specloader/SpecificationLoaderDefault.java | 14 +++++++++++---
.../specloader/validator/MetaModelValidatorVisiting.java | 2 +-
.../appfeat/ApplicationFeatureRepositoryDefaultTest.java | 2 +-
.../runtime/system/session/IsisSessionFactoryDefault.java | 2 +-
.../server/resources/DomainTypeResourceServerside.java | 2 +-
.../server/resources/HomePageReprRenderer.java | 2 +-
.../incubator/command/IncubatingSpecificationLoader.java | 8 +-------
14 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 7fbf89d..c89112a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -517,7 +517,7 @@ implements MetaModelValidatorRefiner, PostConstructMethodCache, ObjectSpecIdFace
}
final Map<ObjectSpecId, ObjectSpecification> specById = _Maps.newHashMap();
- for (final ObjectSpecification otherSpec : getSpecificationLoader().allSpecifications()) {
+ for (final ObjectSpecification otherSpec : getSpecificationLoader().currentSpecifications()) {
if(thisSpec == otherSpec) {
continue;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
index fa2cf6f..5997123 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
@@ -106,7 +106,7 @@ public class ApplicationFeatureRepositoryDefault implements ApplicationFeatureRe
private Collection<ObjectSpecification> primeMetaModel() {
serviceRegistry.streamServices()
.forEach(service->specificationLoader.loadSpecification(service.getClass()));
- return specificationLoader.allSpecifications();
+ return specificationLoader.currentSpecifications();
}
private void createApplicationFeaturesFor(final Collection<ObjectSpecification> specifications) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
index 6485d20..82945ed 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
@@ -84,7 +84,7 @@ public class LayoutServiceDefault implements LayoutService {
@Override
public byte[] toZip(final Style style) {
- final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
+ final Collection<ObjectSpecification> allSpecs = specificationLoader.currentSpecifications();
final List<ObjectSpecification> domainObjectSpecs = _Lists
.filter(allSpecs, spec ->
!spec.isAbstract() &&
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
index b312bab..67d475f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelExporter.java
@@ -80,7 +80,7 @@ class MetaModelExporter {
// phase 1: create a domainClassType for each ObjectSpecification
// these are added into a map for lookups in phase 2
final Map<ObjectSpecification, DomainClassDto> domainClassByObjectSpec = _Maps.newHashMap();
- for (final ObjectSpecification specification : specificationLoader.allSpecifications()) {
+ for (final ObjectSpecification specification : specificationLoader.currentSpecifications()) {
DomainClassDto domainClassType = asXsdType(specification, config);
domainClassByObjectSpec.put(specification, domainClassType);
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index 1b2b0c5..bfdb765 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -101,7 +101,7 @@ public class MetaModelServiceDefault implements MetaModelService {
@Override
public DomainModel getDomainModel() {
- final Collection<ObjectSpecification> specifications = specificationLoader.allSpecifications();
+ final Collection<ObjectSpecification> specifications = specificationLoader.currentSpecifications();
final List<DomainMember> rows = _Lists.newArrayList();
for (final ObjectSpecification spec : specifications) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Generation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Generation.java
index 1355f48..1cc522b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Generation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/internal/Generation.java
@@ -128,7 +128,7 @@ class Generation {
void appendServicePathsAndDefinitions() {
// (previously we took a protective copy to avoid a concurrent modification exception,
// but this is now done by SpecificationLoader itself)
- for (final ObjectSpecification objectSpec : specificationLoader.allSpecifications()) {
+ for (final ObjectSpecification objectSpec : specificationLoader.currentSpecifications()) {
final DomainServiceFacet domainServiceFacet = objectSpec.getFacet(DomainServiceFacet.class);
if (domainServiceFacet == null) {
@@ -181,7 +181,7 @@ class Generation {
void appendObjectPathsAndDefinitions() {
// (previously we took a protective copy to avoid a concurrent modification exception,
// but this is now done by SpecificationLoader itself)
- for (final ObjectSpecification objectSpec : specificationLoader.allSpecifications()) {
+ for (final ObjectSpecification objectSpec : specificationLoader.currentSpecifications()) {
probe.println("objectSpec %s", objectSpec);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index 027118e..9633f90 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -17,13 +17,13 @@
package org.apache.isis.core.metamodel.specloader;
import java.util.List;
+import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.config.property.ConfigPropertyBoolean;
import org.apache.isis.config.property.ConfigPropertyEnum;
-import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.commons.lang.ClassUtil;
import org.apache.isis.core.metamodel.spec.ObjectSpecId;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -53,15 +53,16 @@ public interface SpecificationLoader {
// -- LOOKUP
/**
- * Returns (a new list holding a copy of) all the loaded specifications.
- *
+ * @ThreadSafe
* <p>
- * A new list is returned to avoid concurrent modification exceptions for if the caller then
+ * Must be implemented thread-safe to avoid concurrent modification exceptions for if the caller
* iterates over all the specifications and performs an activity that might give rise to new
* ObjectSpec's being discovered, eg performing metamodel validation.
* </p>
+ *
+ * @return snapshot of all the (currently) loaded specifications
*/
- List<ObjectSpecification> allSpecifications();
+ List<ObjectSpecification> currentSpecifications();
ObjectSpecification lookupBySpecId(ObjectSpecId objectSpecId);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
index a6ead9c..8a40193 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -2,6 +2,7 @@ package org.apache.isis.core.metamodel.specloader;
import static org.apache.isis.commons.internal.base._With.requires;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
@@ -285,7 +286,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
}
//TODO[2033] don't block on long running code ... 'specSpi.introspectUpTo(upTo);'
- synchronized (this) {
+ synchronized (cache) {
spec = cache.get(typeName);
if (spec != null) {
@@ -308,8 +309,15 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
// -- LOOKUP
@Override
- public List<ObjectSpecification> allSpecifications() {
- return _Lists.newArrayList(allCachedSpecifications());
+ public List<ObjectSpecification> currentSpecifications() {
+
+ final List<ObjectSpecification> defensiveCopy;
+
+ synchronized (cache) {
+ defensiveCopy = _Lists.newArrayList(allCachedSpecifications());
+ }
+
+ return defensiveCopy;
}
@Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java
index 42e2471..7ee773a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java
@@ -67,7 +67,7 @@ public class MetaModelValidatorVisiting extends MetaModelValidatorAbstract {
// all currently known specs
// (previously we took a protective copy to avoid a concurrent modification exception,
// but this is now done by SpecificationLoader itself)
- final Collection<ObjectSpecification> specsToValidate = getSpecificationLoader().allSpecifications();
+ final Collection<ObjectSpecification> specsToValidate = getSpecificationLoader().currentSpecifications();
// don't validate any specs already processed
specsToValidate.removeAll(specsAlreadyValidated);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
index b376ba7..d8737da 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
@@ -269,7 +269,7 @@ public class ApplicationFeatureRepositoryDefaultTest {
allowing(mockServiceRegistry).streamServices();
will(returnValue(_Lists.newArrayList().stream()));
- allowing(mockSpecificationLoader).allSpecifications();
+ allowing(mockSpecificationLoader).currentSpecifications();
will(returnValue(_Lists.newArrayList()));
}});
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
index 2e62f8f..fe2e969 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
@@ -172,7 +172,7 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory {
// (previously we took a protective copy to avoid a concurrent modification exception,
// but this is now done by SpecificationLoader itself)
- for (final ObjectSpecification objSpec : IsisContext.getSpecificationLoader().allSpecifications()) {
+ for (final ObjectSpecification objSpec : IsisContext.getSpecificationLoader().currentSpecifications()) {
final Class<?> correspondingClass = objSpec.getCorrespondingClass();
if(correspondingClass.isEnum()) {
final Object[] enumConstants = correspondingClass.getEnumConstants();
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainTypeResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainTypeResourceServerside.java
index 08ef740..5dbc65f 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainTypeResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainTypeResourceServerside.java
@@ -82,7 +82,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
final RepresentationType representationType = RepresentationType.TYPE_LIST;
init(representationType, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
- final Collection<ObjectSpecification> allSpecifications = getSpecificationLoader().allSpecifications();
+ final Collection<ObjectSpecification> allSpecifications = getSpecificationLoader().currentSpecifications();
final TypeListReprRenderer renderer = new TypeListReprRenderer(getResourceContext(), null, JsonRepresentation.newMap());
renderer.with(allSpecifications).includesSelf();
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
index 174d221..1d048f3 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
@@ -64,7 +64,7 @@ public class HomePageReprRenderer extends ReprRendererAbstract<HomePageReprRende
addLinkToMenuBars();
addLinkToServices(metaModelContext.streamServiceAdapters());
addLinkToVersion();
- addLinkToDomainTypes(((ResourceContext)getRendererContext()).getSpecificationLoader().allSpecifications());
+ addLinkToDomainTypes(((ResourceContext)getRendererContext()).getSpecificationLoader().currentSpecifications());
// inks and extensions
representation.mapPut("extensions", JsonRepresentation.newMap());
diff --git a/example/application/springapp/src/main/java/isis/incubator/command/IncubatingSpecificationLoader.java b/example/application/springapp/src/main/java/isis/incubator/command/IncubatingSpecificationLoader.java
index d477181..242832b 100644
--- a/example/application/springapp/src/main/java/isis/incubator/command/IncubatingSpecificationLoader.java
+++ b/example/application/springapp/src/main/java/isis/incubator/command/IncubatingSpecificationLoader.java
@@ -24,7 +24,7 @@ public class IncubatingSpecificationLoader implements SpecificationLoader {
}
@Override
- public List<ObjectSpecification> allSpecifications() {
+ public List<ObjectSpecification> currentSpecifications() {
// TODO Auto-generated method stub
return null;
}
@@ -47,10 +47,4 @@ public class IncubatingSpecificationLoader implements SpecificationLoader {
return null;
}
- @Override
- public ObjectSpecification loadSpecification(ObjectSpecId objectSpecId, IntrospectionState upTo) {
- // TODO Auto-generated method stub
- return null;
- }
-
}