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 2021/04/30 09:09:30 UTC

[isis] branch master updated: ISIS-2626: SpecLoader: provide a side-effect free MM validation version

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new fa7fa10  ISIS-2626: SpecLoader: provide a side-effect free MM validation version
fa7fa10 is described below

commit fa7fa1088ca20f267d5728c21fda3b4e57758d0b
Author: ahuber@apache.org <ah...@luna>
AuthorDate: Fri Apr 30 11:09:11 2021 +0200

    ISIS-2626: SpecLoader: provide a side-effect free MM validation version
---
 .../org/apache/isis/commons/internal/base/_Lazy.java   |  6 ++++++
 .../isis/commons/internal/base/_Lazy_Simple.java       |  6 ++++++
 .../isis/commons/internal/base/_Lazy_ThreadSafe.java   |  8 ++++++++
 .../commons/internal/base/_Lazy_ThreadSafeAndWeak.java |  6 ++++++
 .../core/metamodel/specloader/SpecificationLoader.java | 16 ++++++++++++++--
 .../specloader/SpecificationLoaderDefault.java         | 14 ++++++++++----
 .../ViewModelSemanticCheckingFacetFactoryTest.java     |  2 +-
 .../session/InteractionFactoryDefault.java             |  2 +-
 ...sionAnnotationFacetFactoryTest_refineMetaModel.java |  2 +-
 .../util/interaction/InteractionTestAbstract.java      |  2 +-
 .../applib/validate/DomainModelValidator.java          |  2 +-
 .../webmodule/IsisRestfulObjectsInteractionFilter.java |  7 +++++--
 .../viewer/integration/WebRequestCycleForIsis.java     | 18 +++++++++++++-----
 13 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy.java
index 63a6ba4..ac967b6 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.commons.internal.base;
 
+import java.util.Optional;
 import java.util.function.Supplier;
 
 /**
@@ -59,6 +60,11 @@ public interface _Lazy<T> extends Supplier<T> {
     public T get();
     
     /**
+     * Optionally returns the value, based on whether this lazy got initialized and holds a memoized value.
+     */
+    public Optional<T> getMemoized();
+    
+    /**
      * Sets the memoized value, if not already memoized. 
      * @param value
      * @throws IllegalStateException if already memoized
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_Simple.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_Simple.java
index 9b24018..bf951c1 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_Simple.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_Simple.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.commons.internal.base;
 
+import java.util.Optional;
 import java.util.function.Supplier;
 
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -58,6 +59,11 @@ final class _Lazy_Simple<T> implements _Lazy<T> {
         memoized = true;
         return value = supplier.get();
     }
+    
+    @Override
+    public Optional<T> getMemoized() {
+        return Optional.ofNullable(value);
+    }
 
     @Override
     public void set(T value) {
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafe.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafe.java
index 0048e61..444bfe3 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafe.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafe.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.commons.internal.base;
 
+import java.util.Optional;
 import java.util.function.Supplier;
 
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -66,6 +67,13 @@ final class _Lazy_ThreadSafe<T> implements _Lazy<T> {
     }
     
     @Override
+    public Optional<T> getMemoized() {
+        synchronized (this) {
+            return Optional.ofNullable(value);
+        }
+    }
+    
+    @Override
     public void set(T value) {
         synchronized (this) {
             if(memoized) {
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafeAndWeak.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafeAndWeak.java
index 9052d7b..7014e62 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafeAndWeak.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Lazy_ThreadSafeAndWeak.java
@@ -20,6 +20,7 @@
 package org.apache.isis.commons.internal.base;
 
 import java.lang.ref.WeakReference;
+import java.util.Optional;
 import java.util.function.Supplier;
 
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -70,6 +71,11 @@ final class _Lazy_ThreadSafeAndWeak<T> implements _Lazy<T> {
     }
     
     @Override
+    public Optional<T> getMemoized() {
+        throw _Exceptions.unsupportedOperation("undecidable for weak references");
+    }
+    
+    @Override
     public void set(T newValue) {
         synchronized (this) {
             weakValueReference = new WeakReference<T>(newValue);
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 0f5bcc9..3ceea19 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
@@ -61,12 +61,24 @@ public interface SpecificationLoader {
     
     /**
      * Returns the collected results of the various {@link MetaModelValidator}s configured with
-     * the {@link ProgrammingModel}.
+     * the {@link ProgrammingModel}. As a side-effect, triggers meta-model validation, if that has 
+     * not happened already. Viewers should call the side-effect free 
+     * {@link #getValidationResult() variant} instead. 
      * 
      * @apiNote Some of the {@link MetaModelValidator}s run during {@link #createMetaModel()}, 
      * others are only triggered when calling this method. 
+     * @see #getValidationResult()
      */
-    ValidationFailures getValidationResult();
+    ValidationFailures getOrAssessValidationResult();
+
+    /**
+     * Optionally returns the collected results of the various {@link MetaModelValidator}s configured with
+     * the {@link ProgrammingModel}, based on whether the <i>Application<i> is yet fully initialized. 
+     * 
+     * @apiNote This is the side-effect free variant of {@link #getOrAssessValidationResult()}
+     * @see #getOrAssessValidationResult() 
+     */
+    Optional<ValidationFailures> getValidationResult();
     
     void addValidationFailure(ValidationFailure validationFailure);
 
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 c143e0b..886249f 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
@@ -20,6 +20,7 @@ package org.apache.isis.core.metamodel.specloader;
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Optional;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -302,7 +303,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         }
         
         log.info(" - running remaining validators");
-        _Blackhole.consume(getValidationResult()); // as a side effect memoizes the validation result
+        _Blackhole.consume(getOrAssessValidationResult()); // as a side effect memoizes the validation result
 
         stopWatch.stop();
         log.info("Metamodel created in " + (long)stopWatch.getMillis() + " ms.");
@@ -313,7 +314,12 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
     }
 
     @Override
-    public ValidationFailures getValidationResult() {
+    public Optional<ValidationFailures> getValidationResult() {
+        return validationResult.getMemoized();
+    }
+    
+    @Override
+    public ValidationFailures getOrAssessValidationResult() {
         return validationResult.get();
     }
 
@@ -404,12 +410,12 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
             validationResult.clear(); // invalidate
             // potentially triggers a call to the method we are currently in, 
             // which adds more entries to the validationQueue
-            getValidationResult(); 
+            getOrAssessValidationResult(); 
         }
         
         // only after things have settled we offer feedback to the user (interface) 
         
-        final ValidationFailures validationFailures = getValidationResult();
+        final ValidationFailures validationFailures = getOrAssessValidationResult();
         if(validationFailures.hasFailures()) {
             throw _Exceptions.illegalState(String.join("\n", validationFailures.getMessages("[%d] %s")));
         }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactoryTest.java
index 1a9ed7e..69cf9eb 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactoryTest.java
@@ -154,7 +154,7 @@ public class ViewModelSemanticCheckingFacetFactoryTest {
         ((MetaModelContextAware)holder).setMetaModelContext(metaModelContext);
         facetFactory.process(new FacetFactory.ProcessClassContext(cls, null, holder));
         
-        return metaModelContext.getSpecificationLoader().getValidationResult();
+        return metaModelContext.getSpecificationLoader().getOrAssessValidationResult();
     }
 
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
index ba6b67f..87d78db 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
@@ -134,7 +134,7 @@ implements
         taskList.await();
 
         { // log any validation failures, experimental code however, not sure how to best propagate failures
-            val validationResult = specificationLoader.getValidationResult();
+            val validationResult = specificationLoader.getOrAssessValidationResult();
             if(validationResult.getNumberOfFailures()==0) {
                 log.info("Validation PASSED");
             } else {
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
index e85bd74..d6ed273 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
@@ -287,7 +287,7 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
     private ValidationFailures processThenValidate(ObjectSpecification spec) {
         val specLoader = metaModelContext.getSpecificationLoader();
         specLoader.specForType(spec.getCorrespondingClass()).get(); // fail if empty
-        return specLoader.getValidationResult();
+        return specLoader.getOrAssessValidationResult();
     }
 
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
index 7647f10..5af73fe 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
@@ -108,7 +108,7 @@ public abstract class InteractionTestAbstract extends IsisIntegrationTestAbstrac
 
     protected void assertMetamodelValid() {
         val specLoader = objectManager.getMetaModelContext().getSpecificationLoader(); 
-        assertEquals(Collections.<String>emptyList(), specLoader.getValidationResult().getMessages());    
+        assertEquals(Collections.<String>emptyList(), specLoader.getOrAssessValidationResult().getMessages());    
     }
     
     protected void assertComponentWiseEquals(Object a, Object b) {
diff --git a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/validate/DomainModelValidator.java b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/validate/DomainModelValidator.java
index 7da2d20..6555c36 100644
--- a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/validate/DomainModelValidator.java
+++ b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/validate/DomainModelValidator.java
@@ -74,7 +74,7 @@ public class DomainModelValidator {
             }
         }
 
-        this.validationFailures = specificationLoader.getValidationResult();
+        this.validationFailures = specificationLoader.getOrAssessValidationResult();
     }
 
 
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
index bbb8372..72e4ec2 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
@@ -46,6 +46,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.factory._InstanceUtil;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
@@ -412,10 +413,12 @@ public class IsisRestfulObjectsInteractionFilter implements Filter {
 
 
     private static void ensureMetamodelIsValid(SpecificationLoader specificationLoader) {
-        val validationResult = specificationLoader.getValidationResult();
+        // using side-effect free access to MM validation result
+        val validationResult = specificationLoader.getValidationResult()
+        .orElseThrow(()->_Exceptions.illegalState("Application is not fully initilized yet."));
         if(validationResult.hasFailures()) {
             throw new MetaModelInvalidException(validationResult.getAsLineNumberedString());
-        }
+        }   
     }
 
 
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/WebRequestCycleForIsis.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/WebRequestCycleForIsis.java
index 41fe163..c488d62 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/WebRequestCycleForIsis.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/WebRequestCycleForIsis.java
@@ -172,7 +172,9 @@ public class WebRequestCycleForIsis implements IRequestCycleListener {
             
         } else if(handler instanceof RenderPageRequestHandler) {
 
-            val validationResult = getCommonContext().getSpecificationLoader().getValidationResult();
+            // using side-effect free access to MM validation result
+            val validationResult = getCommonContext().getSpecificationLoader().getValidationResult()
+            .orElseThrow(()->_Exceptions.illegalState("Application is not fully initilized yet."));
 
             if(validationResult.hasFailures()) {
                 RenderPageRequestHandler requestHandler = (RenderPageRequestHandler) handler;
@@ -272,8 +274,11 @@ public class WebRequestCycleForIsis implements IRequestCycleListener {
 
         log.debug("onException {}", ex.getClass().getSimpleName());
 
-        val validationResult = getCommonContext().getSpecificationLoader().getValidationResult();
-        if(validationResult.hasFailures()) {
+        // using side-effect free access to MM validation result
+        val validationResult = getCommonContext().getSpecificationLoader().getValidationResult()
+                .orElse(null);
+        if(validationResult!=null
+                && validationResult.hasFailures()) {
             val mmvErrorPage = new MmvErrorPage(validationResult.getMessages("[%d] %s"));
             return new RenderPageRequestHandler(new PageProvider(mmvErrorPage), RedirectPolicy.ALWAYS_REDIRECT);
         }
@@ -385,8 +390,11 @@ public class WebRequestCycleForIsis implements IRequestCycleListener {
             return null; 
         } 
         
-        val validationResult = commmonContext.getSpecificationLoader().getValidationResult();
-        if(validationResult.hasFailures()) {
+        // using side-effect free access to MM validation result
+        val validationResult = getCommonContext().getSpecificationLoader().getValidationResult()
+                .orElse(null);
+        if(validationResult!=null
+                && validationResult.hasFailures()) {
             return new MmvErrorPage(validationResult.getMessages("[%d] %s"));
         }