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 2018/10/03 19:26:21 UTC

[isis] 01/01: ISIS-1974: also processes domain types, introduces notion

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

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

commit 0e19b194cbf7978b70c23028cbd87f684094ce2a
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Oct 3 18:54:15 2018 +0100

    ISIS-1974: also processes domain types, introduces notion
    
    of stub processing vs complete
---
 .../java/org/apache/isis/applib/AppManifest.java   |  27 +++++-
 .../metamodel/specloader/SpecificationLoader.java  | 108 ++++++++++++---------
 .../IsisComponentProvider.java                     |   8 ++
 3 files changed, 98 insertions(+), 45 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java b/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
index 22c4fe4..ba1d991 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
@@ -32,7 +32,6 @@ import java.util.Set;
 import javax.jdo.annotations.PersistenceCapable;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 
 import org.reflections.vfs.SystemDir;
 import org.reflections.vfs.Vfs;
@@ -245,6 +244,32 @@ public interface AppManifest {
             urlTypes.addAll(Arrays.asList(Vfs.DefaultUrlTypes.values()));
 
             return urlTypes;
+
+        }
+
+        private Set<Class<?>> domainObjectTypes;
+        private Set<Class<?>> viewModelTypes;
+        private Set<Class<?>> xmlElementTypes;
+
+        public Set<Class<?>> getDomainObjectTypes() {
+            return domainObjectTypes;
+        }
+        public void setDomainObjectTypes(final Set<Class<?>> domainObjectTypes) {
+            this.domainObjectTypes = domainObjectTypes;
+        }
+
+        public Set<Class<?>> getViewModelTypes() {
+            return viewModelTypes;
+        }
+        public void setViewModelTypes(final Set<Class<?>> viewModelTypes) {
+            this.viewModelTypes = viewModelTypes;
+        }
+
+        public Set<Class<?>> getXmlElementTypes() {
+            return xmlElementTypes;
+        }
+        public void setXmlElementTypes(final Set<Class<?>> xmlElementTypes) {
+            this.xmlElementTypes = xmlElementTypes;
         }
         //endregion
 
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 7e52cf6..2120843 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
@@ -21,7 +21,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
 
@@ -188,8 +187,24 @@ public class SpecificationLoader implements ApplicationScopedComponent {
 
         state = State.CACHING;
 
-        loadSpecificationsForServices();
-        loadSpecificationsForMixins();
+        // need to completely load services and mixins (synchronously)
+        loadSpecificationsFor(
+                allServiceClasses(),
+                NatureOfService.DOMAIN, IntrospectionStrategy.STUB);
+        loadSpecificationsFor(
+                AppManifest.Registry.instance().getMixinTypes(),
+                null, IntrospectionStrategy.STUB);
+
+        loadSpecificationsFor(
+                AppManifest.Registry.instance().getDomainObjectTypes(),
+                null, IntrospectionStrategy.STUB);
+        loadSpecificationsFor(
+                AppManifest.Registry.instance().getViewModelTypes(),
+                null, IntrospectionStrategy.STUB);
+        loadSpecificationsFor(
+                AppManifest.Registry.instance().getXmlElementTypes(),
+                null, IntrospectionStrategy.STUB);
+
         cacheBySpecId();
 
         state = State.INTROSPECTING;
@@ -218,35 +233,22 @@ public class SpecificationLoader implements ApplicationScopedComponent {
 
     }
 
-    private void loadSpecificationsForServices() {
-        final Properties metadataProperties = new Properties();
-
-        List<Class<?>> classes = allServiceClasses();
-        for (final Class<?> serviceClass : classes) {
-            final DomainService domainService = serviceClass.getAnnotation(DomainService.class);
-            final NatureOfService nature = domainService != null ? domainService.nature() : NatureOfService.DOMAIN;
-            // will 'markAsService'
-            ObjectSpecification objectSpecification = internalLoadSpecification(serviceClass, nature);
-
-            facetProcessorObjectSpecId.process(
-                    serviceClass, metadataProperties,
-                    MethodRemoverConstants.NULL, objectSpecification);
+    private void loadSpecificationsFor(
+            final Collection<Class<?>> domainTypes,
+            final NatureOfService natureOfServiceFallback,
+            final IntrospectionStrategy introspectionStrategy) {
+        if(domainTypes == null || domainTypes.isEmpty()) {
+            return;
         }
-    }
-
-    private void loadSpecificationsForMixins() {
         final Properties metadataProperties = new Properties();
+        for (final Class<?> domainType : domainTypes) {
+
+            ObjectSpecification objectSpecification =
+                    internalLoadSpecification(domainType, natureOfServiceFallback, introspectionStrategy);
 
-        final Set<Class<?>> mixinTypes = AppManifest.Registry.instance().getMixinTypes();
-        if(mixinTypes == null) {
-            return;
-        }
-        for (final Class<?> mixinType : mixinTypes) {
-            ObjectSpecification objectSpecification = internalLoadSpecification(mixinType);
             facetProcessorObjectSpecId.process(
-                    mixinType, metadataProperties,
+                    domainType, metadataProperties,
                     MethodRemoverConstants.NULL, objectSpecification);
-
         }
     }
 
@@ -388,22 +390,26 @@ public class SpecificationLoader implements ApplicationScopedComponent {
         return spec;
     }
 
+    enum IntrospectionStrategy {STUB, COMPLETE}
     private ObjectSpecification internalLoadSpecification(final Class<?> type) {
-        // superclasses tend to be loaded via this method, implicitly.
-        // what can happen is that a subclass domain service, eg a fake one such as FakeLocationLookupService
-        // can be registered first prior to the "real" implementation.  As belt-n-braces, if that superclass is
-        // annotated using @DomainService, then we ensure its own spec is created correctly as a service spec.
-        final DomainService domainServiceIfAny = type.getAnnotation(DomainService.class);
-        final NatureOfService natureOfServiceIfAny = domainServiceIfAny != null ? domainServiceIfAny.nature() : null;
-        return internalLoadSpecification(type, natureOfServiceIfAny);
+        return internalLoadSpecification(type, null, IntrospectionStrategy.COMPLETE);
     }
 
-    private ObjectSpecification internalLoadSpecification(final Class<?> type, final NatureOfService nature) {
+    private ObjectSpecification internalLoadSpecification(
+            final Class<?> type,
+            final NatureOfService natureFallback,
+            final IntrospectionStrategy introspectionStrategy) {
+
         final Class<?> substitutedType = classSubstitutor.getClass(type);
-        return substitutedType != null ? loadSpecificationForSubstitutedClass(substitutedType, nature) : null;
+        return substitutedType != null
+                ? loadSpecificationForSubstitutedClass(substitutedType, natureFallback, introspectionStrategy)
+                : null;
     }
 
-    private ObjectSpecification loadSpecificationForSubstitutedClass(final Class<?> type, final NatureOfService nature) {
+    private ObjectSpecification loadSpecificationForSubstitutedClass(
+            final Class<?> type,
+            final NatureOfService natureFallback,
+            final IntrospectionStrategy introspectionStrategy) {
         Assert.assertNotNull(type);
 
         final String typeName = type.getName();
@@ -412,12 +418,14 @@ public class SpecificationLoader implements ApplicationScopedComponent {
             return spec;
         }
 
-        return loadSpecificationForSubstitutedClassSynchronized(type, nature);
+        return loadSpecificationForSubstitutedClassSynchronized(type, natureFallback, introspectionStrategy);
     }
 
+
     private synchronized ObjectSpecification loadSpecificationForSubstitutedClassSynchronized(
             final Class<?> type,
-            final NatureOfService natureOfService) {
+            final NatureOfService natureOfServiceFallback,
+            final IntrospectionStrategy introspectionStrategy) {
 
         final String typeName = type.getName();
         final ObjectSpecification spec = cache.get(typeName);
@@ -425,13 +433,16 @@ public class SpecificationLoader implements ApplicationScopedComponent {
             // because caller isn't synchronized.
             return spec;
         }
-        final ObjectSpecification specification = createSpecification(type, natureOfService);
+
+        final ObjectSpecification specification = createSpecification(type, natureOfServiceFallback);
 
         // put into the cache prior to introspecting, to prevent
         // infinite loops
         cache.cache(typeName, specification);
 
-        introspectIfRequired(specification);
+        if(introspectionStrategy == IntrospectionStrategy.COMPLETE) {
+            introspectIfRequired(specification);
+        }
 
         return specification;
     }
@@ -466,23 +477,32 @@ public class SpecificationLoader implements ApplicationScopedComponent {
      */
     private ObjectSpecification createSpecification(
             final Class<?> cls,
-            final NatureOfService natureOfServiceIfAny) {
+            final NatureOfService fallback) {
 
         // ... and create the specs
         if (FreeStandingList.class.isAssignableFrom(cls)) {
-            return new ObjectSpecificationOnStandaloneList(servicesInjector,
-                    facetProcessor);
+            return new ObjectSpecificationOnStandaloneList(servicesInjector, facetProcessor);
         } else {
             final ConfigurationServiceInternal configService = servicesInjector.lookupService(
                     ConfigurationServiceInternal.class);
             final FacetedMethodsBuilderContext facetedMethodsBuilderContext =
                     new FacetedMethodsBuilderContext(
                             this, facetProcessor, layoutMetadataReaders, configService);
+
+            final NatureOfService natureOfServiceIfAny = natureOfServiceFrom(cls, fallback);
+
             return new ObjectSpecificationDefault(cls, facetedMethodsBuilderContext,
                     servicesInjector, facetProcessor, natureOfServiceIfAny);
         }
     }
 
+    private NatureOfService natureOfServiceFrom(
+            final Class<?> type,
+            final NatureOfService fallback) {
+        final DomainService domainServiceIfAny = type.getAnnotation(DomainService.class);
+        return domainServiceIfAny != null ? domainServiceIfAny.nature() : fallback;
+    }
+
     private Class<?> loadBuiltIn(final String className) throws ClassNotFoundException {
         final Class<?> builtIn = ClassUtil.getBuiltIn(className);
         if (builtIn != null) {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisComponentProvider.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisComponentProvider.java
index 9773fa9..1e69806 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisComponentProvider.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisComponentProvider.java
@@ -26,6 +26,7 @@ import java.util.Set;
 
 import javax.annotation.Nullable;
 import javax.jdo.annotations.PersistenceCapable;
+import javax.xml.bind.annotation.XmlElement;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
@@ -43,6 +44,7 @@ import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Mixin;
 import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.ViewModel;
 import org.apache.isis.applib.fixturescripts.FixtureScript;
 import org.apache.isis.applib.services.classdiscovery.ClassDiscoveryServiceUsingReflections;
 import org.apache.isis.core.commons.config.IsisConfiguration;
@@ -161,6 +163,9 @@ public abstract class IsisComponentProvider {
                 }))
         );
 
+        final Set<Class<?>> viewModelTypes = reflections.getTypesAnnotatedWith(ViewModel.class);
+        final Set<Class<?>> xmlElementTypes = reflections.getTypesAnnotatedWith(XmlElement.class);
+
         // add in any explicitly registered services...
         domainServiceTypes.addAll(appManifest.getAdditionalServices());
 
@@ -182,6 +187,9 @@ public abstract class IsisComponentProvider {
         registry.setPersistenceCapableTypes(within(packagesWithDotSuffix, persistenceCapableTypes));
         registry.setFixtureScriptTypes(within(packagesWithDotSuffix, fixtureScriptTypes));
         registry.setMixinTypes(within(packagesWithDotSuffix, mixinTypes));
+        registry.setDomainObjectTypes(within(packagesWithDotSuffix, domainObjectTypes));
+        registry.setViewModelTypes(within(packagesWithDotSuffix, viewModelTypes));
+        registry.setXmlElementTypes(within(packagesWithDotSuffix, xmlElementTypes));
     }
 
     static <T> Set<Class<? extends T>> within(