You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/04/23 06:13:47 UTC

[isis] 01/02: ISIS-2619: introduces new DeriveMixinMembersPostProcessor

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

danhaywood pushed a commit to branch ISIS-2619
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 3026c349409c3663c7db7bb5edd4f8ebcc1953e2
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 23 07:04:24 2021 +0100

    ISIS-2619: introduces new DeriveMixinMembersPostProcessor
---
 .../param/DeriveMixinMembersPostProcessor.java     | 65 ++++++++++++++++++
 .../dflt/ProgrammingModelFacetsJava8.java          | 13 ++--
 .../specloader/facetprocessor/FacetProcessor.java  | 78 +++++++++++-----------
 .../facets/TenantedAuthorizationFacetFactory.java  | 14 ++--
 4 files changed, 121 insertions(+), 49 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java
new file mode 100644
index 0000000..8207049
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java
@@ -0,0 +1,65 @@
+/*
+ *  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.core.metamodel.postprocessors.param;
+
+import java.util.stream.Stream;
+
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.context.MetaModelContextAware;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.progmodel.ObjectSpecificationPostProcessor;
+import org.apache.isis.core.metamodel.spec.ActionType;
+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.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.specimpl.ObjectMemberAbstract;
+
+import lombok.Setter;
+import lombok.val;
+
+
+public class DeriveMixinMembersPostProcessor
+implements ObjectSpecificationPostProcessor, MetaModelContextAware {
+
+    @Setter(onMethod = @__(@Override))
+    private MetaModelContext metaModelContext;
+
+    @Override
+    public void postProcess(final ObjectSpecification objectSpecification) {
+
+        // all the actions of this type
+        val actionTypes = metaModelContext.getSystemEnvironment().isPrototyping()
+                ? ActionType.USER_AND_PROTOTYPE
+                : ActionType.USER_ONLY;
+        objectSpecification.streamActions(actionTypes, MixedIn.INCLUDED);
+
+        // and all the collections of this type
+        objectSpecification.streamCollections(MixedIn.INCLUDED);
+
+        // and all the properties of this type
+        objectSpecification.streamProperties(MixedIn.INCLUDED);
+
+    }
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
index 8f55ad8..23ce56c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
@@ -143,6 +143,7 @@ import org.apache.isis.core.metamodel.methods.MemberSupportAnnotationEnforcesSup
 import org.apache.isis.core.metamodel.methods.MethodByClassMap;
 import org.apache.isis.core.metamodel.methods.OrphanedSupportingMethodValidator;
 import org.apache.isis.core.metamodel.postprocessors.param.DeriveFacetsPostProcessor;
+import org.apache.isis.core.metamodel.postprocessors.param.DeriveMixinMembersPostProcessor;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
 import org.apache.isis.core.metamodel.services.title.TitlesAndTranslationsValidator;
 
@@ -236,7 +237,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, DisabledObjectFacetViaMethodFactory.class);
 
         val postConstructMethodsCache = new MethodByClassMap();
-        
+
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, new RecreatableObjectFacetFactory(postConstructMethodsCache));
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, JaxbFacetFactory.class);
 
@@ -256,7 +257,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         // must come after DomainObjectAnnotationFacetFactory & MixinFacetFactory
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, ContributingFacetDerivedFromMixinFacetFactory.class);
 
-        
+
         addFactory(FacetProcessingOrder.F1_LAYOUT, GridFacetFactory.class);
 
         // must come before DomainObjectLayoutFacetFactory
@@ -327,7 +328,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.G1_VALUE_TYPES, OffsetDateTimeValueFacetUsingSemanticsProviderFactory.class);
         addFactory(FacetProcessingOrder.G1_VALUE_TYPES, ZonedDateTimeValueFacetUsingSemanticsProviderFactory.class);
 
-        addFactory(FacetProcessingOrder.Z0_BEFORE_FINALLY, AuthorizationFacetFactory.class);
+        addFactory(FacetProcessingOrder.Z0_BEFORE_FINALLY, AuthorizationFacetFactory.class); // TODO: reimplement as a PostProcessor
 
         // written to not trample over TypeOf if already installed
         addFactory(FacetProcessingOrder.Z1_FINALLY, CollectionFacetFactory.class);
@@ -346,12 +347,14 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.Z1_FINALLY, FacetsFacetAnnotationFactory.class);
 
         // must be after all named facets and description facets have been installed
-        addFactory(FacetProcessingOrder.Z1_FINALLY, TranslationFacetFactory.class);
+        addFactory(FacetProcessingOrder.Z1_FINALLY, TranslationFacetFactory.class); // TODO: reimplement as a PostProcessor
+
 
         addFactory(FacetProcessingOrder.Z1_FINALLY, ViewModelSemanticCheckingFacetFactory.class);
 
+        addPostProcessor(PostProcessingOrder.A0_BEFORE_BUILTIN, DeriveMixinMembersPostProcessor.class);
         addPostProcessor(PostProcessingOrder.A1_BUILTIN, DeriveFacetsPostProcessor.class);
-        
+
         addValidator(new MemberSupportAnnotationEnforcesSupportingMethodValidator());
         addValidator(new OrphanedSupportingMethodValidator());
         addValidator(new TitlesAndTranslationsValidator());
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
index ab133f7..a038a92 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
@@ -80,7 +80,7 @@ public class FacetProcessor {
      * {@link MethodPrefixBasedFacetFactory}.
      *
      */
-    private final _Lazy<Set<String>> methodPrefixes = 
+    private final _Lazy<Set<String>> methodPrefixes =
             _Lazy.threadSafe(this::init_methodPrefixes);
 
     /**
@@ -111,13 +111,13 @@ public class FacetProcessor {
      * Lazily initialized, then cached. The lists remain in the same order that
      * the factories were {@link #registerFactory(FacetFactory) registered}.
      */
-    private final _Lazy<ListMultimap<FeatureType, FacetFactory>> factoryListByFeatureType = 
+    private final _Lazy<ListMultimap<FeatureType, FacetFactory>> factoryListByFeatureType =
             _Lazy.threadSafe(this::init_factoriesByFeatureType);
-    
+
     // -- LIFECYCLE
-    
+
     public void init() {
-        cleanUp(); 
+        cleanUp();
         programmingModel.streamFactories()
         .forEach(this::registerFactory);
     }
@@ -131,7 +131,7 @@ public class FacetProcessor {
         factories.clear();
         factoryByFactoryType.clear();
     }
-    
+
     private void registerFactory(FacetFactory factory) {
         factoryByFactoryType.put(factory.getClass(), factory);
         factories.add(factory);
@@ -155,11 +155,11 @@ public class FacetProcessor {
      * {@link PropertyOrCollectionIdentifyingFacetFactory}s.
      */
     public void findAssociationCandidateAccessors(
-            Stream<Method> methods, 
+            Stream<Method> methods,
             Consumer<Method> onCandidate) {
-        
+
         val factories = propertyOrCollectionIdentifyingFactories.get();
-        
+
         methods.forEach(method->{
             for (val facetFactory : factories) {
                 if (facetFactory.isPropertyOrCollectionAccessorCandidate(method)) {
@@ -178,9 +178,9 @@ public class FacetProcessor {
      * Intended to be called after {@link #findAndRemovePropertyAccessors(MethodRemover, java.util.List)} once only reference properties remain.
      */
     public void findAndRemovePropertyAccessors(
-            MethodRemover methodRemover, 
+            MethodRemover methodRemover,
             List<Method> methodListToAppendTo) {
-        
+
         for (val facetFactory : propertyOrCollectionIdentifyingFactories.get()) {
             facetFactory.findAndRemovePropertyAccessors(methodRemover, methodListToAppendTo);
         }
@@ -195,9 +195,9 @@ public class FacetProcessor {
      *      List)
      */
     public void findAndRemoveCollectionAccessors(
-            MethodRemover methodRemover, 
+            MethodRemover methodRemover,
             List<Method> methodListToAppendTo) {
-        
+
         for (val facetFactory : propertyOrCollectionIdentifyingFactories.get()) {
             facetFactory.findAndRemoveCollectionAccessors(methodRemover, methodListToAppendTo);
         }
@@ -247,11 +247,11 @@ public class FacetProcessor {
 
     private List<ObjectSpecIdFacetFactory> objectSpecIfFacetFactoryList = null;
 
-    
+
     private List<ObjectSpecIdFacetFactory> getObjectSpecIfFacetFactoryList() {
         if(objectSpecIfFacetFactoryList == null) {
             val facetFactories = _Lists.<ObjectSpecIdFacetFactory>newArrayList();
-            
+
             factoryListByFeatureType.get().getOrElseEmpty(FeatureType.OBJECT)
             .forEach(facetFactory->{
                 if (facetFactory instanceof ObjectSpecIdFacetFactory) {
@@ -259,7 +259,7 @@ public class FacetProcessor {
                     facetFactories.add(objectSpecIdFacetFactory);
                 }
             });
-            
+
             objectSpecIfFacetFactoryList = Collections.unmodifiableList(facetFactories);
         }
         return objectSpecIfFacetFactoryList;
@@ -284,12 +284,12 @@ public class FacetProcessor {
             Class<?> cls,
             MethodRemover methodRemover,
             FacetHolder facetHolder) {
-        
+
         val ctx = new ProcessClassContext(
-                cls, 
-                removerElseNoopRemover(methodRemover), 
+                cls,
+                removerElseNoopRemover(methodRemover),
                 facetHolder);
-        
+
         factoryListByFeatureType.get().getOrElseEmpty(FeatureType.OBJECT)
         .forEach(facetFactory->facetFactory.process(ctx));
     }
@@ -315,7 +315,7 @@ public class FacetProcessor {
      *            - what type of feature the method represents (property,
      *            action, collection etc)
      * @param isMixinMain
-     *            - Whether we are currently processing a mixin type AND this context's method 
+     *            - Whether we are currently processing a mixin type AND this context's method
      *            can be identified as the main method of the processed mixin class. (since 2.0)
      */
     public void process(
@@ -323,24 +323,26 @@ public class FacetProcessor {
             Method method,
             MethodRemover methodRemover,
             FacetedMethod facetedMethod,
-            FeatureType featureType, 
+            FeatureType featureType,
             boolean isMixinMain) {
-        
+
         facetedMethod.setMetaModelContext(metaModelContext);
-        
+
         val processMethodContext =
                 new ProcessMethodContext(
-                        cls, 
-                        featureType, 
-                        method, 
+                        cls,
+                        featureType,
+                        method,
                         removerElseNoopRemover(methodRemover), facetedMethod, isMixinMain);
-        
-        factoryListByFeatureType.get().getOrElseEmpty(featureType)
-        .forEach(facetFactory->facetFactory.process(processMethodContext));
+
+        for (FacetFactory facetFactory : factoryListByFeatureType.get().getOrElseEmpty(featureType)) {
+
+            facetFactory.process(processMethodContext);
+        }
     }
 
     public void processMemberOrder(ObjectMember facetHolder) {
-        
+
     }
 
     /**
@@ -367,9 +369,9 @@ public class FacetProcessor {
             int paramNum,
             MethodRemover methodRemover,
             FacetedMethodParameter facetedMethodParameter) {
-        
+
         facetedMethodParameter.setMetaModelContext(metaModelContext);
-        
+
         for (val featureType : FeatureType.PARAMETERS_ONLY) {
             processParams(introspectedClass, method, paramNum, methodRemover, facetedMethodParameter, featureType);
         }
@@ -382,12 +384,12 @@ public class FacetProcessor {
             MethodRemover methodRemover,
             FacetedMethodParameter facetedMethodParameter,
             FeatureType featureType) {
-        
+
         facetedMethodParameter.setMetaModelContext(metaModelContext);
-        
+
         val processParameterContext =
                 new ProcessParameterContext(introspectedClass, method, paramNum, methodRemover, facetedMethodParameter);
-        
+
         factoryListByFeatureType.get().getOrElseEmpty(featureType)
         .forEach(facetFactory->facetFactory.processParams(processParameterContext));
     }
@@ -399,7 +401,7 @@ public class FacetProcessor {
         methodFilteringFactories.clear();
         propertyOrCollectionIdentifyingFactories.clear();
     }
-    
+
     // -- INITIALIZERS
 
     private ListMultimap<FeatureType, FacetFactory> init_factoriesByFeatureType() {
@@ -443,7 +445,7 @@ public class FacetProcessor {
         }
         return propertyOrCollectionIdentifyingFactories;
     }
-    
+
     // -- HELPER
 
     private static MethodRemover removerElseNoopRemover(MethodRemover methodRemover) {
diff --git a/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java b/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
index a60e300..d08b5ba 100644
--- a/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
+++ b/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
@@ -33,6 +33,7 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.extensions.secman.api.tenancy.ApplicationTenancyEvaluator;
 import org.apache.isis.extensions.secman.api.user.ApplicationUserRepository;
 
@@ -78,35 +79,36 @@ public class TenantedAuthorizationFacetFactory extends FacetFactoryAbstract {
         FacetUtil.addFacet(createFacet(cls, facetHolder));
     }
 
-    
+
     public static class QueryResultsCacheProviderHolder {
         @Inject @Getter private Provider<QueryResultsCache> queryResultsCacheProvider;
     }
-    
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private TenantedAuthorizationFacetDefault createFacet(
-            final Class<?> cls, 
+            final Class<?> cls,
             final FacetHolder holder) {
 
         val serviceRegistry = super.getServiceRegistry();
 
+        final boolean mixinClass = serviceRegistry.lookupService(SpecificationLoader.class).map(x -> x.loadSpecification(cls)).map(x -> x.isMixin()).isPresent();
         val evaluators = serviceRegistry
                 .select(ApplicationTenancyEvaluator.class)
                 .stream()
-                .filter(applicationTenancyEvaluator->applicationTenancyEvaluator.handles(cls))
+                .filter(applicationTenancyEvaluator-> mixinClass || applicationTenancyEvaluator.handles(cls))
                 .collect(Collectors.<ApplicationTenancyEvaluator>toList());
 
         if(evaluators.isEmpty()) {
             return null;
         }
-        
+
         val applicationUserRepository =
                 serviceRegistry.lookupService(ApplicationUserRepository.class).orElse(null);
         val queryResultsCacheProvider =
                 super.getServiceInjector()
                 .injectServicesInto(new QueryResultsCacheProviderHolder())
                 .getQueryResultsCacheProvider();
-        val userService = 
+        val userService =
                 serviceRegistry.lookupService(UserService.class).orElse(null);
 
         return new TenantedAuthorizationFacetDefault(