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/07/02 11:50:48 UTC

[isis] branch master updated: ISIS-2775: Allow mixin actions to be declared on domain services.

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 d8d658b  ISIS-2775: Allow mixin actions to be declared on domain services.
d8d658b is described below

commit d8d658b52475ee55f5591a2cf9862a36a5bfd880
Author: andi-huber <ah...@apache.org>
AuthorDate: Fri Jul 2 13:49:50 2021 +0200

    ISIS-2775: Allow mixin actions to be declared on domain services.
---
 .../isis/applib/services/metamodel/BeanSort.java   | 18 ++++++----
 .../specimpl/ObjectSpecificationAbstract.java      | 17 +++------
 .../{Factories.java => _MixedInMemberFactory.java} | 17 +++++----
 .../DomainModelTest_usingGoodDomain.java           | 27 ++++++++++++++
 .../model/good/ProperServiceWithMixin.java         | 42 ++++++++++++++++++++++
 5 files changed, 93 insertions(+), 28 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/BeanSort.java b/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/BeanSort.java
index e0ca928..b40bcf9 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/BeanSort.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/metamodel/BeanSort.java
@@ -26,7 +26,7 @@ import org.apache.isis.applib.annotation.Programmatic;
 
 /**
  * Top level object classification.
- * 
+ *
  * @since 2.0 {@index}
  */
 public enum BeanSort {
@@ -73,18 +73,22 @@ public enum BeanSort {
      */
     COLLECTION,
     /**
-     * A non concrete type, that is a placeholder for a its concrete implementer. 
+     * A non concrete type, that is a placeholder for a its concrete implementer.
      */
     ABSTRACT,
     /**
-     * Type must not be added to the meta-model, eg. by means of 
+     * Type must not be added to the meta-model, eg. by means of
      * {@link Vetoed}, {@link Profile} or {@link Programmatic}
      */
-    VETOED, 
+    VETOED,
     UNKNOWN;
 
     // -- SIMPLE PREDICATES
 
+    public boolean isManagedBeanContributing() {
+        return this == MANAGED_BEAN_CONTRIBUTING;
+    }
+
     public boolean isManagedBean() {
         return this == MANAGED_BEAN_CONTRIBUTING || this == MANAGED_BEAN_NOT_CONTRIBUTING;
     }
@@ -108,15 +112,15 @@ public enum BeanSort {
     public boolean isEntity() {
         return this == ENTITY;
     }
-    
+
     public boolean isAbstract() {
         return this == ABSTRACT;
     }
-    
+
     public boolean isVetoed() {
         return this == VETOED;
     }
-    
+
     public boolean isUnknown() {
         return this == UNKNOWN;
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index 5d4e679..d6f4a95 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -753,7 +753,7 @@ implements ObjectSpecification {
         specification.streamActions(ActionType.ANY, MixedIn.INCLUDED)
         .filter(_SpecPredicates::isMixedInAssociation)
         .map(ObjectActionDefault.class::cast)
-        .map(Factories.mixedInAssociation(this, mixinType, mixinMethodName))
+        .map(_MixedInMemberFactory.mixedInAssociation(this, mixinType, mixinMethodName))
         .peek(facetProcessor::processMemberOrder)
         .forEach(onNewMixedInAssociation);
 
@@ -762,15 +762,9 @@ implements ObjectSpecification {
 
     // -- mixin actions
     /**
-     * All mixed in actions for this spec.
-     * <p>
-     * If this specification represents a service ({@link #isManagedBean()} or a value or
-     * a mixin, then is a no-op.
+     * Creates all mixed in actions for this spec.
      */
     private void createMixedInActions(final Consumer<ObjectAction> onNewMixedInAction) {
-        if (isManagedBean() || isValue() || isMixin()) {
-            return;
-        }
         val mixinTypes = getIsisBeanTypeRegistry().getMixinTypes();
         if(_NullSafe.isEmpty(mixinTypes)) {
             return;
@@ -780,8 +774,6 @@ implements ObjectSpecification {
         }
     }
 
-
-
     private void forEachMixedInAction(
             final Class<?> mixinType,
             final Consumer<ObjectAction> onNewMixedInAction) {
@@ -804,7 +796,7 @@ implements ObjectSpecification {
         mixinSpec.streamActions(ActionType.ANY, MixedIn.EXCLUDED)
         .filter(_SpecPredicates::isMixedInAction)
         .map(ObjectActionDefault.class::cast)
-        .map(Factories.mixedInAction(this, mixinType, mixinMethodName))
+        .map(_MixedInMemberFactory.mixedInAction(this, mixinType, mixinMethodName))
         .peek(facetProcessor::processMemberOrder)
         .forEach(onNewMixedInAction);
 
@@ -879,7 +871,8 @@ implements ObjectSpecification {
         synchronized (unmodifiableActions) {
             if(!mixedInActionsAdded) {
                 val actions = _Lists.newArrayList(this.objectActions);
-                if (isEntityOrViewModelOrAbstract()) {
+                if (isEntityOrViewModelOrAbstract()
+                        || getBeanSort().isManagedBeanContributing()) {
                     createMixedInActions(actions::add);
                 }
                 sortCacheAndUpdateActions(actions);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/Factories.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/_MixedInMemberFactory.java
similarity index 78%
rename from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/Factories.java
rename to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/_MixedInMemberFactory.java
index 23a9124..d9587ae 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/Factories.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/_MixedInMemberFactory.java
@@ -23,17 +23,16 @@ import java.util.function.Function;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
 import lombok.val;
+import lombok.experimental.UtilityClass;
 
 /** package private utility */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-final class Factories {
+@UtilityClass
+class _MixedInMemberFactory {
 
     // -- MIXINS
 
-    static Function<ObjectActionDefault, ObjectActionMixedIn> mixedInAction(
+    Function<ObjectActionDefault, ObjectActionMixedIn> mixedInAction(
             final ObjectSpecification mixinTypeSpec,
             final Class<?> mixinType,
             final String mixinMethodName) {
@@ -42,8 +41,8 @@ final class Factories {
                 mixinType, mixinMethodName, mixinTypeAction, mixinTypeSpec);
     }
 
-    static Function<ObjectActionDefault, ObjectAssociation> mixedInAssociation(
-            final ObjectSpecification mixedInType,
+    Function<ObjectActionDefault, ObjectAssociation> mixedInAssociation(
+            final ObjectSpecification mixinTypeSpec,
             final Class<?> mixinType,
             final String mixinMethodName) {
 
@@ -51,10 +50,10 @@ final class Factories {
             val returnType = mixinAction.getReturnType();
             if (returnType.isNotCollection()) {
                 return new OneToOneAssociationMixedIn(
-                        mixinAction, mixedInType, mixinType, mixinMethodName);
+                        mixinAction, mixinTypeSpec, mixinType, mixinMethodName);
             }
             return new OneToManyAssociationMixedIn(
-                    mixinAction, mixedInType, mixinType, mixinMethodName);
+                    mixinAction, mixinTypeSpec, mixinType, mixinMethodName);
         };
     }
 
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
index 85de79e..ca1a842 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
@@ -37,6 +37,7 @@ import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.all.named.MemberNamedFacet;
 import org.apache.isis.core.metamodel.facets.members.publish.execution.ExecutionPublishingFacet;
 import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
@@ -47,6 +48,7 @@ import org.apache.isis.core.metamodel.postprocessors.collparam.ActionParameterDe
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.schema.metamodel.v2.DomainClassDto;
 import org.apache.isis.testdomain.conf.Configuration_headless;
@@ -61,12 +63,14 @@ import org.apache.isis.testdomain.model.good.ProperMemberInheritanceInterface;
 import org.apache.isis.testdomain.model.good.ProperMemberInheritance_usingAbstract;
 import org.apache.isis.testdomain.model.good.ProperMemberInheritance_usingInterface;
 import org.apache.isis.testdomain.model.good.ProperMemberSupport;
+import org.apache.isis.testdomain.model.good.ProperServiceWithMixin;
 import org.apache.isis.testing.integtestsupport.applib.validate.DomainModelValidator;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import lombok.val;
 
@@ -397,6 +401,29 @@ class DomainModelTest_usingGoodDomain {
         assertEquals(described, member.getDescription(()->sampleObject));
     }
 
+    @Test
+    void mixinsOnDomainServices_shouldBeAllowed() {
+
+        val objectSpec = specificationLoader.specForTypeElseFail(ProperServiceWithMixin.class);
+
+        val mixinSpec = specificationLoader.specForTypeElseFail(ProperServiceWithMixin.Now.class);
+
+        assertTrue(mixinSpec.isMixin());
+
+        assertEquals(
+                1L,
+                objectSpec.streamRuntimeActions(MixedIn.INCLUDED)
+                .filter(ObjectAction::isMixedIn)
+                .peek(act->{
+                    //System.out.println("act: " + act);
+                    val memberNamedFacet = act.getFacet(MemberNamedFacet.class);
+                    assertNotNull(memberNamedFacet);
+                    assertTrue(memberNamedFacet.getSpecialization().isLeft());
+                })
+                .count());
+
+    }
+
     // -- HELPER
 
     private void assertHasProperty(final ObjectSpecification spec, final String propertyId) {
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithMixin.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithMixin.java
new file mode 100644
index 0000000..27701c5
--- /dev/null
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithMixin.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.testdomain.model.good;
+
+import org.joda.time.LocalDateTime;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.MemberSupport;
+import org.apache.isis.applib.annotation.NatureOfService;
+
+@DomainService(
+        nature = NatureOfService.VIEW,
+        logicalTypeName = "testdomain.ProperServiceWithMixin")
+public class ProperServiceWithMixin {
+
+    @Action
+    public class Now {
+
+        @MemberSupport
+        public LocalDateTime act() {
+            return LocalDateTime.now();
+        }
+    }
+
+}