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 2018/12/20 23:35:28 UTC

[isis] branch 2033-IoC updated: ISIS-2033: fixes ServiceRegistry#validate

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

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


The following commit(s) were added to refs/heads/2033-IoC by this push:
     new 1ac707d  ISIS-2033: fixes ServiceRegistry#validate
1ac707d is described below

commit 1ac707d4b5b9df9cbddedf3ffa09de2321b9c6c8
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Dec 21 00:35:22 2018 +0100

    ISIS-2033: fixes ServiceRegistry#validate
    
    by properly iterating over discovered beans
    
    also simplify weld testing with a BeanListBuilder
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2033
---
 .../applib/services/registry/ServiceRegistry.java  |   4 +
 .../org/apache/isis/config/IsisConfiguration.java  |   3 +
 .../services/registry/ServiceRegistryDefault.java  |  81 +++++++++++---
 .../isis/core/metamodel/BeansForTesting.java       | 121 +++++++++++++++++++++
 .../services/ServicesInjectorDefaultTest.java      |  30 ++---
 .../ServicesInjectorDefaultTest_usingFields.java   |  31 ++----
 ...rvicesInjectorDefaultTest_validateServices.java |  79 +++++---------
 ...InjectorDefaultTest_validateServices_happy.java |  68 ++++++++++++
 8 files changed, 312 insertions(+), 105 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java b/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
index 7394627..4689998 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
@@ -122,6 +122,10 @@ public interface ServiceRegistry {
      */
     boolean isRegisteredServiceInstance(Object pojo);
 
+    /**
+     * Verify domain service Ids are unique.
+     * @throws IllegalStateException - if validation fails
+     */
     void validateServices();
 
 
diff --git a/core/config/src/main/java/org/apache/isis/config/IsisConfiguration.java b/core/config/src/main/java/org/apache/isis/config/IsisConfiguration.java
index a20e87c..e9980be 100644
--- a/core/config/src/main/java/org/apache/isis/config/IsisConfiguration.java
+++ b/core/config/src/main/java/org/apache/isis/config/IsisConfiguration.java
@@ -25,6 +25,8 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.stream.Stream;
 
+import javax.enterprise.context.ApplicationScoped;
+
 import org.apache.isis.applib.AppManifest;
 import org.apache.isis.applib.Module;
 import org.apache.isis.applib.PropertyResource;
@@ -50,6 +52,7 @@ import static org.apache.isis.config.internal._Config.getConfiguration;
  * Thus the {@link IsisConfiguration} held by different components may vary, but
  * with each being a possible superset of the previous.
  */
+@ApplicationScoped
 public interface IsisConfiguration {
     
     /**
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
index fd4c78e..b6a76a4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.core.metamodel.services.registry;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -34,14 +35,20 @@ import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.enterprise.util.AnnotationLiteral;
 
+import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.cdi._CDI;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.collections._Multimaps;
+import org.apache.isis.commons.internal.collections._Multimaps.ListMultimap;
 import org.apache.isis.commons.internal.collections._Multimaps.SetMultimap;
 import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.core.metamodel.services.ServiceUtil;
+
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
 
 import lombok.val;
 
@@ -72,6 +79,7 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
     
     @Override
     public Stream<Object> streamServices() {
+        
         if(registeredServiceInstances.isEmpty()) {
          
             BeanManager beanManager = _CDI.getBeanManager();
@@ -80,9 +88,14 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
             for (Bean<?> bean : beans) {
                 
                 val type = bean.getBeanClass();
+                val debug = type.getName().startsWith("org.apache.isis.");
                 
-                if(bean.getBeanClass().getName().startsWith("org.apache.isis.")) {
+                if(debug) {
                     System.out.println("!!! " + bean);    
+                } 
+                
+                if(!isSingleton(type)) {
+                    continue;
                 }
                 
                 Optional<?> managedObject = 
@@ -91,11 +104,14 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
                 if(managedObject.isPresent()) {
                     registeredServiceInstances.add(managedObject.get());
                     
-                    System.out.println("\t registering: " + managedObject.get());
+                    if(debug) {
+                        System.out.println("!!!\t registering: " + managedObject.get());
+                    }
                     
                 } else {
-                    if(bean.getBeanClass().getName().startsWith("org.apache.isis.")) {
-                        System.out.println("\t !!! bean not present: " + type.getName());    
+                    
+                    if(debug) {
+                        System.out.println("!!!\t bean not present: " + type.getName());    
                     }
                 }
                 
@@ -132,24 +148,59 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
     
     @Override
     public void validateServices() {
-        // TODO Auto-generated method stub
-        
+        validate(streamServices());
     }
-    
+
     // -- HELPER ...
     
     private final static AnnotationLiteral<Any> QUALIFIER_ANY = 
             new AnnotationLiteral<Any>() {
         private static final long serialVersionUID = 1L;};
+
+    private boolean isSingleton(Class<?> cls) {
+        
+        if(cls.isAnnotationPresent(Singleton.class) ||
+                cls.isAnnotationPresent(DomainService.class)) {
+            return true;
+        }
+        
+        return false;
+    }
+        
+    // -- VALIDATE
+        
+    private static void validate(final Stream<Object> serviceInstances) {
+
+        final ListMultimap<String, Object> servicesById = _Multimaps.newListMultimap();
+        serviceInstances.forEach(serviceInstance->{
+            String id = ServiceUtil.idOfPojo(serviceInstance);
+            System.out.println("!!! id="+id);
+            
+            servicesById.putElement(id, serviceInstance);
+        });
+
+        final String errorMsg = servicesById.entrySet().stream()
+                .filter(entry->entry.getValue().size()>1) // filter for duplicates
+                .map(entry->{
+                    String serviceId = entry.getKey();
+                    List<Object> duplicateServiceEntries = entry.getValue();
+                    return String.format("serviceId '%s' is declared by domain services %s",
+                            serviceId, classNamesFor(duplicateServiceEntries));
+                })
+                .collect(Collectors.joining(", "));
+
+        if(_Strings.isNotEmpty(errorMsg)) {
+            throw new IllegalStateException("Service ids must be unique! "+errorMsg);
+        }
+    }
     
-    
-//    private final static AnnotationLiteral<Singleton> SINGLETON =
-//            new AnnotationLiteral<Singleton>() {
-//        private static final long serialVersionUID = 1L;};
-//    
-//    private final static AnnotationLiteral<ApplicationScoped> APPLICATIONSCOPED = 
-//            new AnnotationLiteral<ApplicationScoped>() {
-//        private static final long serialVersionUID = 1L;};
+    private static String classNamesFor(Collection<Object> services) {
+        return stream(services)
+                .map(Object::getClass)
+                .map(Class::getName)
+                .collect(Collectors.joining(", "));
+    }
+
         
     // -- LOOKUP SERVICE(S)
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/BeansForTesting.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/BeansForTesting.java
new file mode 100644
index 0000000..f5de3f7
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/BeansForTesting.java
@@ -0,0 +1,121 @@
+/*
+ *  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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.enterprise.inject.Produces;
+
+import org.mockito.Mockito;
+
+import org.apache.isis.applib.services.repository.RepositoryService;
+import org.apache.isis.commons.internal._Constants;
+import org.apache.isis.config.IsisConfiguration;
+import org.apache.isis.config.builder.IsisConfigurationBuilder;
+import org.apache.isis.core.metamodel.services.ServiceInjectorDefault;
+import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
+import org.apache.isis.core.metamodel.specloader.InjectorMethodEvaluatorDefault;
+
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
+
+/**
+ * 
+ * @since 2.0.0-M2
+ *
+ */
+public final class BeansForTesting {
+
+    // -- BUILDER
+    
+    public static BeanListBuilder builder() {
+        return new BeanListBuilder();
+    }
+    
+    public static class BeanListBuilder {
+        
+        private final Set<Class<?>> beans = new HashSet<>();
+        
+        public Class<?>[] build() {
+            return beans.toArray(_Constants.emptyClasses);
+        }
+        
+        public BeanListBuilder add(Class<?> bean) {
+            beans.add(bean);
+            return this;
+        }
+        
+        public BeanListBuilder addAll(Class<?> ... beans) {
+            stream(beans)
+            .forEach(this.beans::add);
+            return this;
+        }
+        
+        /**
+         * Adds IsisConfiguration support.
+         */
+        public BeanListBuilder config() {
+            beans.add(config);
+            return this;
+        } 
+
+        /**
+         * Adds ServiceRegistry and ServiceInjector support.
+         */
+        public BeanListBuilder injector() {
+           
+            addAll(
+                config,
+                InjectorMethodEvaluatorDefault.class,
+                ServiceRegistryDefault.class,
+                ServiceInjectorDefault.class);
+            
+            return this;
+        }
+        
+        
+    }
+    
+    
+    // -- PREDEFINED
+    
+    public static Class<?> config = _Config.class;
+    public static Class<?> mock_repository = _Mock_RepositoryService.class;
+    
+    static class _Config {
+        
+        @Produces
+        IsisConfiguration getConfiguration() {
+            return IsisConfigurationBuilder.getDefaultForUnitTesting()
+            .build();
+        }
+        
+    }
+
+    static class _Mock_RepositoryService {
+        
+        @Produces
+        RepositoryService mockRepositoryService() {
+            return Mockito.mock(RepositoryService.class);
+        }
+        
+    }
+    
+    
+}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest.java
index 92e5744..3ecd870 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest.java
@@ -43,10 +43,7 @@ import org.mockito.Mockito;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.repository.RepositoryService;
-import org.apache.isis.config.IsisConfiguration;
-import org.apache.isis.config.builder.IsisConfigurationBuilder;
-import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
-import org.apache.isis.core.metamodel.specloader.InjectorMethodEvaluatorDefault;
+import org.apache.isis.core.metamodel.BeansForTesting;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.times;
@@ -56,13 +53,7 @@ import static org.mockito.Mockito.verify;
 @EnableWeld
 class ServicesInjectorDefaultTest {
 
-    static class FactoriesForTesting {
-        
-        @Produces
-        IsisConfiguration getConfiguration() {
-            return IsisConfigurationBuilder.getDefaultForUnitTesting()
-            .build();
-        }
+    static class Mocks {
         
         @Produces
         SomeDomainObject mockDomainObject() {
@@ -93,16 +84,15 @@ class ServicesInjectorDefaultTest {
     
     @WeldSetup
     public WeldInitiator weld = WeldInitiator.from(
-            FactoriesForTesting.class,
-            IsisConfiguration.class,
-            InjectorMethodEvaluatorDefault.class,
-            ServiceRegistryDefault.class,
-            ServiceInjectorDefault.class,
-            
-            RepositoryService.class,
             
-            Service1.class,
-            Service2.class
+            BeansForTesting.builder()
+            .injector()
+            .addAll(
+                    Mocks.class,
+                    Service1.class,
+                    Service2.class
+                    )
+            .build()
             
             )
     .build();
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_usingFields.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_usingFields.java
index ea3f9c7..7c9fd9d 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_usingFields.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_usingFields.java
@@ -30,10 +30,7 @@ import org.mockito.Mockito;
 
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.repository.RepositoryService;
-import org.apache.isis.config.IsisConfiguration;
-import org.apache.isis.config.builder.IsisConfigurationBuilder;
-import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
-import org.apache.isis.core.metamodel.specloader.InjectorMethodEvaluatorDefault;
+import org.apache.isis.core.metamodel.BeansForTesting;
 
 import static org.hamcrest.Matchers.any;
 import static org.junit.Assert.assertThat;
@@ -44,13 +41,7 @@ import lombok.Getter;
 class ServicesInjectorDefaultTest_usingFields {
 
 
-    static class FactoriesForTesting {
-        
-        @Produces
-        IsisConfiguration getConfiguration() {
-            return IsisConfigurationBuilder.getDefaultForUnitTesting()
-            .build();
-        }
+    static class Mocks {
         
         @Produces
         RepositoryService mockRepositoryService() {
@@ -61,14 +52,16 @@ class ServicesInjectorDefaultTest_usingFields {
     
     @WeldSetup
     public WeldInitiator weld = WeldInitiator.from(
-            FactoriesForTesting.class,
-            InjectorMethodEvaluatorDefault.class,
-            ServiceRegistryDefault.class,
-            ServiceInjectorDefault.class,
             
-            A.class,
-            B.class,
-            C.class
+            BeansForTesting.builder()
+            .injector()
+            .addAll(
+                    Mocks.class,
+                    A.class,
+                    B.class,
+                    C.class
+                    )
+            .build()
             
             )
     .build();
@@ -100,7 +93,7 @@ class ServicesInjectorDefaultTest_usingFields {
         @Inject @Getter private C someC;
     }
     
-    // not-managed managed
+    // not-managed
     static class D { 
         @Inject @Getter private A someA;    
         @Inject @Getter private B someB;
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices.java
index 2210999..4f86923 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices.java
@@ -19,75 +19,52 @@
 
 package org.apache.isis.core.metamodel.services;
 
-import java.util.List;
+import javax.inject.Inject;
 
-import org.junit.Before;
-import org.junit.Test;
+import org.jboss.weld.junit5.EnableWeld;
+import org.jboss.weld.junit5.WeldInitiator;
+import org.jboss.weld.junit5.WeldSetup;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
 
+import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
+import org.apache.isis.core.metamodel.BeansForTesting;
 
-public class ServicesInjectorDefaultTest_validateServices {
+@EnableWeld
+class ServicesInjectorDefaultTest_validateServices {
 
-    ServiceRegistry serviceRegistry;
+    // -- SCENARIO
 
+    @DomainService
     public static class DomainServiceWithSomeId {
         public String getId() { return "someId"; }
     }
 
+    @DomainService
     public static class DomainServiceWithDuplicateId {
         public String getId() { return "someId"; }
     }
 
-    public static class DomainServiceWithDifferentId {
-        public String getId() { return "otherId"; }
-    }
-
-    public static class ValidateServicesTestValidateServices extends ServicesInjectorDefaultTest_validateServices {
-
-        List<Object> serviceList;
-
-        @Before
-        public void setUp() throws Exception {
-            serviceList = _Lists.newArrayList();
-        }
+    // --
 
-        @Test(expected=IllegalStateException.class)
-        public void validate_DomainServicesWithDuplicateIds() {
+    @WeldSetup
+    public WeldInitiator weld = WeldInitiator.from(
 
-            // given
-            serviceList.add(new DomainServiceWithSomeId());
-            serviceList.add(new DomainServiceWithDuplicateId());
-            
-            serviceRegistry = new ServiceRegistryDefault();
-            serviceList.forEach(serviceRegistry::registerServiceInstance);
-            
-//            serviceRegistry.registerServiceInstance(serviceInstance);
-//                    ServiceRegistryBuilder_forTesting.get()
-//                    .addServices(serviceList)
-//                    .build();
+            BeansForTesting.builder()
+            .injector()
+            .add(DomainServiceWithSomeId.class)
+            .add(DomainServiceWithDuplicateId.class)
+            .build()
 
-            // when
-            serviceRegistry.validateServices();
-        }
+            )
+    .build();
 
-        public void validate_DomainServicesWithDifferentIds() {
-
-            // given
-            serviceList.add(new DomainServiceWithSomeId());
-            serviceList.add(new DomainServiceWithDifferentId());
-            
-            serviceRegistry = new ServiceRegistryDefault();
-            serviceList.forEach(serviceRegistry::registerServiceInstance);
-
-//            serviceRegistry = ServiceRegistryBuilder_forTesting.get()
-//                    .addServices(serviceList)
-//                    .build();
-
-            // when
-            serviceRegistry.validateServices();
-        }
+    @Inject private ServiceRegistry serviceRegistry;
 
+    @Test
+    public void validate_DomainServicesWithDuplicateIds() {
+        Assertions.assertThrows(IllegalStateException.class, serviceRegistry::validateServices);
     }
+
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices_happy.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices_happy.java
new file mode 100644
index 0000000..9a562dc
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefaultTest_validateServices_happy.java
@@ -0,0 +1,68 @@
+/*
+ *  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.services;
+
+import javax.inject.Inject;
+
+import org.jboss.weld.junit5.EnableWeld;
+import org.jboss.weld.junit5.WeldInitiator;
+import org.jboss.weld.junit5.WeldSetup;
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.core.metamodel.BeansForTesting;
+
+@EnableWeld
+class ServicesInjectorDefaultTest_validateServices_happy {
+    
+    // -- SCENARIO
+
+    @DomainService
+    public static class DomainServiceWithSomeId {
+        public String getId() { return "someId"; }
+    }
+
+    @DomainService
+    public static class DomainServiceWithDifferentId {
+        public String getId() { return "otherId"; }
+    }
+
+    @WeldSetup
+    public WeldInitiator weld = WeldInitiator.from(
+
+            BeansForTesting.builder()
+            .injector()
+            .add(DomainServiceWithSomeId.class)
+            .add(DomainServiceWithDifferentId.class)
+            .build()
+
+            )
+    .build();
+
+    @Inject private ServiceRegistry serviceRegistry;
+
+    @Test
+    public void validate_DomainServicesWithoutDuplicateIds() {
+        serviceRegistry.validateServices();
+    }
+    
+    
+}