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/05 12:07:08 UTC

[isis] 01/01: ISIS-1974: forward ports improvements on parallelisation bootstrapping from master up to v2

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

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

commit f231b6fbbfe9ee96d986508e051e5d085d469d7e
Merge: 9f262ab 4919e6c
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Oct 5 12:41:45 2018 +0100

    ISIS-1974: forward ports improvements on parallelisation bootstrapping from master up to v2

 .../java/org/apache/isis/applib/AppManifest.java   |  26 +++
 .../applib/services/registry/ServiceRegistry.java  |  11 +-
 .../apache/isis/schema/utils/CommonDtoUtils.java   |   2 +
 ...assFacetOnActionFromConfiguredRegexFactory.java |   3 +-
 .../core/metamodel/services/ServicesInjector.java  |   3 -
 .../specloader/SpecificationCacheDefault.java      |  26 ++-
 .../metamodel/specloader/SpecificationLoader.java  | 187 ++++++++++++++-------
 .../classsubstitutor/ClassSubstitutor.java         |  15 +-
 .../specloader/specimpl/FacetedMethodsBuilder.java |   6 +-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |   6 +-
 .../dflt/ProgrammingModelForObjectSpecIdFacet.java |  45 -----
 .../specloader/SpecificationCacheDefaultTest.java  |   3 +-
 .../SpecificationLoaderTestAbstract.java           |  13 +-
 core/pom.xml                                       |   3 +
 .../IsisComponentProvider.java                     |  10 +-
 15 files changed, 225 insertions(+), 134 deletions(-)

diff --cc core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
index fdb9b2a,ba1d991..9d84fbf
--- a/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
@@@ -227,8 -234,143 +227,34 @@@ public interface AppManifest 
          public void setDomainServiceTypes(final Set<Class<?>> domainServiceTypes) {
              this.domainServiceTypes = domainServiceTypes;
          }
 -        //endregion
 -
 -        //region > urlTypes
 -        public List<Vfs.UrlType> getUrlTypes() {
 -            final List<Vfs.UrlType> urlTypes = Lists.newArrayList();
 -            urlTypes.add(new EmptyIfFileEndingsUrlType(".pom", ".jnilib", "QTJava.zip"));
 -            urlTypes.add(new JettyConsoleUrlType());
 -            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
+ 
 -        private static class EmptyIfFileEndingsUrlType implements Vfs.UrlType {
 -
 -            private final List<String> fileEndings;
 -
 -            private EmptyIfFileEndingsUrlType(final String... fileEndings) {
 -                this.fileEndings = Lists.newArrayList(fileEndings);
 -            }
 -
 -            public boolean matches(URL url) {
 -                final String protocol = url.getProtocol();
 -                final String externalForm = url.toExternalForm();
 -                if (!protocol.equals("file")) {
 -                    return false;
 -                }
 -                for (String fileEnding : fileEndings) {
 -                    if (externalForm.endsWith(fileEnding))
 -                        return true;
 -                }
 -                return false;
 -            }
 -
 -            public Vfs.Dir createDir(final URL url) throws Exception {
 -                return emptyVfsDir(url);
 -            }
 -
 -            private static Vfs.Dir emptyVfsDir(final URL url) {
 -                return new Vfs.Dir() {
 -                    @Override
 -                    public String getPath() {
 -                        return url.toExternalForm();
 -                    }
 -
 -                    @Override
 -                    public Iterable<Vfs.File> getFiles() {
 -                        return Collections.emptyList();
 -                    }
 -
 -                    @Override
 -                    public void close() {
 -                        //
 -                    }
 -                };
 -            }
 -        }
 -
 -        private static class JettyConsoleUrlType implements Vfs.UrlType {
 -            public boolean matches(URL url) {
 -                final String protocol = url.getProtocol();
 -                final String externalForm = url.toExternalForm();
 -                final boolean matches = protocol.equals("file") && externalForm.contains("jetty-console") && externalForm.contains("-any-") && externalForm.endsWith("webapp/WEB-INF/classes/");
 -                return matches;
 -            }
 -
 -            public Vfs.Dir createDir(final URL url) throws Exception {
 -                return new SystemDir(getFile(url));
 -            }
 -
 -            /**
 -             * try to get {@link java.io.File} from url
 -             *
 -             * <p>
 -             *     Copied from {@link Vfs} (not publicly accessible)
 -             * </p>
 -             */
 -            static java.io.File getFile(URL url) {
 -                java.io.File file;
 -                String path;
 -
 -                try {
 -                    path = url.toURI().getSchemeSpecificPart();
 -                    if ((file = new java.io.File(path)).exists()) return file;
 -                } catch (URISyntaxException e) {
 -                }
 -
 -                try {
 -                    path = URLDecoder.decode(url.getPath(), "UTF-8");
 -                    if (path.contains(".jar!")) path = path.substring(0, path.lastIndexOf(".jar!") + ".jar".length());
 -                    if ((file = new java.io.File(path)).exists()) return file;
 -
 -                } catch (UnsupportedEncodingException e) {
 -                }
 -
 -                try {
 -                    path = url.toExternalForm();
 -                    if (path.startsWith("jar:")) path = path.substring("jar:".length());
 -                    if (path.startsWith("file:")) path = path.substring("file:".length());
 -                    if (path.contains(".jar!")) path = path.substring(0, path.indexOf(".jar!") + ".jar".length());
 -                    if ((file = new java.io.File(path)).exists()) return file;
 -
 -                    path = path.replace("%20", " ");
 -                    if ((file = new java.io.File(path)).exists()) return file;
 -
 -                } catch (Exception e) {
 -                }
 -
 -                return null;
 -            }
 -        }
      }
  
      public static class Util {
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
index b533b30,882c92d..2ff7363
--- 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
@@@ -30,38 -26,10 +30,41 @@@ public interface ServiceRegistry 
      @Programmatic
      <T> T injectServicesInto(final T domainObject);
  
 +
 +    /**
 +     * @return Stream of all currently registered service instances.
 +     */
 +    @Programmatic
 +    Stream<Object> streamServices();
 +
 +    @Programmatic
 +    <T> Stream<T> streamServices(Class<T> serviceClass);
 +    
 +    /**
 +     * Returns the first registered domain service implementing the requested type.
 +     *
 +     * <p>
 +     * Typically there will only ever be one domain service implementing a given type,
-      * (eg {@link PublishingService}), but for some services there can be more than one
-      * (eg {@link ExceptionRecognizer}).
-      *
-      * @see #lookupServices(Class)
++     * (eg {@link org.apache.isis.applib.services.repository.RepositoryService}), but for some services there can be
++     * more than one (eg {@link ExceptionRecognizer}).
 +     */
      @Programmatic
 -    <T> T lookupService(Class<T> service);
 +    public default <T> Optional<T> lookupService(final Class<T> serviceClass) {
 +        return streamServices(serviceClass)
 +                .findFirst();
 +    }
  
      @Programmatic
 -    <T> Iterable<T> lookupServices(Class<T> service);
++    public default boolean isService(final Class<?> serviceClass) {
++        return lookupService(serviceClass).isPresent();
++    }
+ 
++    @Programmatic
 +    public default <T> T lookupServiceElseFail(final Class<T> serviceClass) {
 +        return streamServices(serviceClass)
 +                .findFirst()
 +                .orElseThrow(()->
 +                    new IllegalStateException("Could not locate service of type '" + serviceClass + "'"));
 +    }
 +    
  }
diff --cc core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
index 53dc2df,81d552d..579d90d
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
@@@ -59,43 -57,53 +59,45 @@@ import org.joda.time.LocalTime
  
  public final class CommonDtoUtils {
  
 -    //region > PARAM_DTO_TO_NAME, PARAM_DTO_TO_TYPE
 -
 -    public static final Function<ParamDto, String> PARAM_DTO_TO_NAME = new Function<ParamDto, String>() {
 -        @Override public String apply(final ParamDto paramDto) {
 -            return paramDto.getName();
 -        }
 -    };
 -    public static final Function<ParamDto, ValueType> PARAM_DTO_TO_TYPE = new Function<ParamDto, ValueType>() {
 -        @Override public ValueType apply(final ParamDto paramDto) {
 -            return paramDto.getType();
 -        }
 -    };
 -    //endregion
 -
 -    //region > asValueType
 -    private final static ImmutableMap<Class<?>, ValueType> valueTypeByClass =
 -            new ImmutableMap.Builder<Class<?>, ValueType>()
 -                    .put(String.class, ValueType.STRING)
 -                    .put(byte.class, ValueType.BYTE)
 -                    .put(Byte.class, ValueType.BYTE)
 -                    .put(short.class, ValueType.SHORT)
 -                    .put(Short.class, ValueType.SHORT)
 -                    .put(int.class, ValueType.INT)
 -                    .put(Integer.class, ValueType.INT)
 -                    .put(long.class, ValueType.LONG)
 -                    .put(Long.class, ValueType.LONG)
 -                    .put(char.class, ValueType.CHAR)
 -                    .put(Character.class, ValueType.CHAR)
 -                    .put(boolean.class, ValueType.BOOLEAN)
 -                    .put(Boolean.class, ValueType.BOOLEAN)
 -                    .put(float.class, ValueType.FLOAT)
 -                    .put(Float.class, ValueType.FLOAT)
 -                    .put(double.class, ValueType.DOUBLE)
 -                    .put(Double.class, ValueType.DOUBLE)
 -                    .put(BigInteger.class, ValueType.BIG_INTEGER)
 -                    .put(BigDecimal.class, ValueType.BIG_DECIMAL)
 -                    .put(DateTime.class, ValueType.JODA_DATE_TIME)
 -                    .put(LocalDateTime.class, ValueType.JODA_LOCAL_DATE_TIME)
 -                    .put(LocalDate.class, ValueType.JODA_LOCAL_DATE)
 -                    .put(LocalTime.class, ValueType.JODA_LOCAL_TIME)
 -                    .put(java.sql.Timestamp.class, ValueType.JAVA_SQL_TIMESTAMP)
 -                    .put(Blob.class, ValueType.BLOB)
 -                    .put(Clob.class, ValueType.CLOB)
 -                    .build();
 +    // -- PARAM_DTO_TO_NAME, PARAM_DTO_TO_TYPE
 +
 +    public static final Function<ParamDto, String> PARAM_DTO_TO_NAME = ParamDto::getName;
 +    public static final Function<ParamDto, ValueType> PARAM_DTO_TO_TYPE = ParamDto::getType;
 +
 +    // -- asValueType
 +    private final static Map<Class<?>, ValueType> valueTypeByClass =
 +            _Maps.unmodifiableEntries(
 +                    entry(String.class, ValueType.STRING),
 +                    entry(String.class, ValueType.STRING),
 +                    entry(byte.class, ValueType.BYTE),
 +                    entry(Byte.class, ValueType.BYTE),
 +                    entry(short.class, ValueType.SHORT),
 +                    entry(Short.class, ValueType.SHORT),
 +                    entry(int.class, ValueType.INT),
 +                    entry(Integer.class, ValueType.INT),
 +                    entry(long.class, ValueType.LONG),
 +                    entry(Long.class, ValueType.LONG),
 +                    entry(char.class, ValueType.CHAR),
 +                    entry(Character.class, ValueType.CHAR),
 +                    entry(boolean.class, ValueType.BOOLEAN),
 +                    entry(Boolean.class, ValueType.BOOLEAN),
 +                    entry(float.class, ValueType.FLOAT),
 +                    entry(Float.class, ValueType.FLOAT),
 +                    entry(double.class, ValueType.DOUBLE),
 +                    entry(Double.class, ValueType.DOUBLE),
 +                    entry(BigInteger.class, ValueType.BIG_INTEGER),
 +                    entry(BigDecimal.class, ValueType.BIG_DECIMAL),
 +                    entry(DateTime.class, ValueType.JODA_DATE_TIME),
 +                    entry(LocalDateTime.class, ValueType.JODA_LOCAL_DATE_TIME),
 +                    entry(LocalDate.class, ValueType.JODA_LOCAL_DATE),
 +                    entry(LocalTime.class, ValueType.JODA_LOCAL_TIME),
 +                    entry(java.sql.Timestamp.class, ValueType.JAVA_SQL_TIMESTAMP),
 +                    entry(Blob.class, ValueType.BLOB),
 +                    entry(Clob.class, ValueType.CLOB)
 +                    );
  
+     public static Collection<Class<?>> VALUE_TYPES = valueTypeByClass.keySet();
+ 
      public static ValueType asValueType(final Class<?> type) {
          final ValueType valueType = valueTypeByClass.get(type);
          if (valueType != null) {
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
index a3ed62b,81c23d2..7b95188
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
@@@ -499,10 -584,10 +499,7 @@@ public class ServicesInjector implement
      public DeploymentCategoryProvider getDeploymentCategoryProvider() {
          return deploymentCategoryProvider != null
                  ? deploymentCategoryProvider
 -                : (deploymentCategoryProvider = lookupServiceElseFail(DeploymentCategoryProvider.class));
 +                        : (deploymentCategoryProvider = lookupServiceElseFail(DeploymentCategoryProvider.class));
      }
  
- 
--
 -    //endregion
--
  }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefault.java
index a55ea74,7de1890..0f53f69
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefault.java
@@@ -27,12 -28,20 +27,20 @@@ import org.apache.isis.commons.internal
  import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
  import org.apache.isis.core.metamodel.spec.ObjectSpecId;
  import org.apache.isis.core.metamodel.spec.ObjectSpecification;
- import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
- import org.apache.isis.core.metamodel.specloader.validator.ValidationFailures;
  
+ /**
+  * This is populated in two parts.
+  *
+  * Initially the #specByClassName is populated using {@link #cache(String, ObjectSpecification)}.  This allows
+  * {@link #allSpecifications()} to return a list of specs.
+  *
+  * Later on, {@link #init(Map)} is called which populates #classNameBySpecId.
+  *
+  * TODO: the information passed to #init actually comes from the cache itself (the caller calls #allSpecifications() first) so this could be simplified
+  */
  class SpecificationCacheDefault {
 -    
 -    private final Map<String, ObjectSpecification> specByClassName = Maps.newHashMap();
 +
 +    private final Map<String, ObjectSpecification> specByClassName = _Maps.newHashMap();
      private Map<ObjectSpecId, String> classNameBySpecId;
  
      public ObjectSpecification get(final String className) {
@@@ -62,12 -71,10 +70,11 @@@
      }
  
      /**
-      * Populated as a result of running {@link MetaModelValidator#validate(ValidationFailures)} validation} after
-      * xxxallxxx most specs have been loaded.
       */
-     void setCacheBySpecId(final Map<ObjectSpecId, ObjectSpecification> specById) {
-         this.classNameBySpecId = _Maps.newHashMap();
+     synchronized void init(final Map<ObjectSpecId, ObjectSpecification> specById) {
 -        final Map<ObjectSpecId, String> classNameBySpecId = Maps.newHashMap();
 -        final Map<String, ObjectSpecification> specByClassName = Maps.newHashMap();
++        final Map<ObjectSpecId, String> classNameBySpecId = _Maps.newHashMap();
++        final Map<String, ObjectSpecification> specByClassName = _Maps.newHashMap();
 +
          for (ObjectSpecId objectSpecId : specById.keySet()) {
              final ObjectSpecification objectSpec = specById.get(objectSpecId);
              final String className = objectSpec.getCorrespondingClass().getName();
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index c7c01a9,244ac15..fafcd4b
--- 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
@@@ -17,12 -17,18 +17,13 @@@
  package org.apache.isis.core.metamodel.specloader;
  
  import java.util.Collection;
 -import java.util.Collections;
  import java.util.List;
  import java.util.Map;
- import java.util.Set;
  import java.util.concurrent.Callable;
  import java.util.concurrent.Future;
 -
 -import com.google.common.base.Function;
 -import com.google.common.base.Predicate;
 -import com.google.common.collect.FluentIterable;
 -import com.google.common.collect.ImmutableList;
 -import com.google.common.collect.Lists;
 -import com.google.common.collect.Maps;
++import java.util.function.Predicate;
++import java.util.stream.Collectors;
 +import java.util.stream.Stream;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
@@@ -40,9 -44,9 +41,8 @@@ import org.apache.isis.core.commons.exc
  import org.apache.isis.core.commons.lang.ClassUtil;
  import org.apache.isis.core.metamodel.facetapi.Facet;
  import org.apache.isis.core.metamodel.facets.FacetFactory;
- import org.apache.isis.core.metamodel.facets.MethodRemoverConstants;
  import org.apache.isis.core.metamodel.facets.object.autocomplete.AutoCompleteFacet;
  import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 -import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader;
  import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
  import org.apache.isis.core.metamodel.services.ServicesInjector;
  import org.apache.isis.core.metamodel.services.configinternal.ConfigurationServiceInternal;
@@@ -167,16 -176,59 +155,53 @@@ public class SpecificationLoader implem
  
          state = State.CACHING;
  
-         loadSpecificationsForServices();
-         loadSpecificationsForMixins();
-         cacheBySpecId();
+         // need to completely load services and mixins (synchronously)
 -        final List<ObjectSpecification> specificationsFromRegistry = Lists.newArrayList();
++        final List<ObjectSpecification> specificationsFromRegistry = _Lists.newArrayList();
+ 
+         loadSpecificationsFor(
+                 CommonDtoUtils.VALUE_TYPES, null,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
+         loadSpecificationsFor(
 -                allServiceClasses(), NatureOfService.DOMAIN,
++                streamServiceClasses().collect(Collectors.toList()), NatureOfService.DOMAIN,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
+         loadSpecificationsFor(
+                 AppManifest.Registry.instance().getMixinTypes(), null,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
+         loadSpecificationsFor(
+                 AppManifest.Registry.instance().getDomainObjectTypes(), null,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
+         loadSpecificationsFor(
+                 AppManifest.Registry.instance().getViewModelTypes(), null,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
+         loadSpecificationsFor(
+                 AppManifest.Registry.instance().getXmlElementTypes(), null,
+                 IntrospectionStrategy.STUB, specificationsFromRegistry);
  
          state = State.INTROSPECTING;
+         final Collection<ObjectSpecification> cachedSpecifications = allCachedSpecifications();
+ 
+ 
+         // for debugging only
+         LOG.info(String.format(
+                 "specificationsFromRegistry.size = %d ; cachedSpecifications.size = %d",
+                 specificationsFromRegistry.size(), cachedSpecifications.size()));
+ 
 -        ImmutableList<ObjectSpecification> registryNotCached = FluentIterable.from(specificationsFromRegistry)
 -                .filter(new Predicate<ObjectSpecification>() {
 -                    @Override
 -                    public boolean apply(final ObjectSpecification objectSpecification) {
 -                        return !cachedSpecifications.contains(objectSpecification);
 -                    }
 -                }).toList();
 -        ImmutableList<ObjectSpecification> cachedNotRegistry = FluentIterable.from(cachedSpecifications)
 -                .filter(new Predicate<ObjectSpecification>() {
 -                    @Override
 -                    public boolean apply(final ObjectSpecification objectSpecification) {
 -                        return !specificationsFromRegistry.contains(objectSpecification);
 -                    }
 -                }).toList();
++        List<ObjectSpecification> registryNotCached = specificationsFromRegistry.stream()
++                .filter(spec -> !cachedSpecifications.contains(spec))
++                .collect(Collectors.toList());
++        List<ObjectSpecification> cachedNotRegistry = cachedSpecifications.stream()
++                .filter(spec -> !specificationsFromRegistry.contains(spec))
++                .collect(Collectors.toList());
+ 
+         LOG.info(String.format(
+                 "registryNotCached.size = %d ; cachedNotRegistry.size = %d",
+                 registryNotCached.size(), cachedNotRegistry.size()));
+ 
  
-         final Collection<ObjectSpecification> objectSpecifications = allSpecifications();
 -        final List<Callable<Object>> callables = Lists.newArrayList();
 +
 +        final List<Callable<Object>> callables = _Lists.newArrayList();
-         for (final ObjectSpecification specification : objectSpecifications) {
+         for (final ObjectSpecification specification : specificationsFromRegistry) {
++
              Callable<Object> callable = new Callable<Object>() {
                  @Override
                  public Object call() {
@@@ -195,39 -247,47 +220,44 @@@
          List<Future<Object>> futures = threadPoolSupport.invokeAll(callables);
          threadPoolSupport.joinGatherFailures(futures);
  
-     }
  
-     private void loadSpecificationsForServices() {
-         streamServiceClasses()
-         .forEach(serviceClass->{
-             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,
-                     MethodRemoverConstants.NULL, objectSpecification);
-         });
+         // for debugging only
+         final Collection<ObjectSpecification> cachedSpecificationsAfter = allCachedSpecifications();
 -        ImmutableList<ObjectSpecification> cachedAfterNotBefore = FluentIterable.from(cachedSpecificationsAfter)
 -                .filter(new Predicate<ObjectSpecification>() {
 -                    @Override
 -                    public boolean apply(final ObjectSpecification objectSpecification) {
 -                        return !cachedSpecifications.contains(objectSpecification);
 -                    }
 -                }).toList();
++        List<ObjectSpecification> cachedAfterNotBefore = cachedSpecificationsAfter.stream()
++                .filter(spec -> !cachedSpecifications.contains(spec))
++                .collect(Collectors.toList());
+         LOG.info(String.format("cachedSpecificationsAfter.size = %d ; cachedAfterNotBefore.size = %d",
+                 cachedSpecificationsAfter.size(), cachedAfterNotBefore.size()));
+ 
+ 
+         // only after full introspection has occured do we cache ObjectSpecifications
+         // by their ObjectSpecId.
+         // the cache (SpecificationCacheDefault will fail-fast as not initialized
+         cacheBySpecId(specificationsFromRegistry);
+ 
      }
  
-     private void loadSpecificationsForMixins() {
+     private void loadSpecificationsFor(
+             final Collection<Class<?>> domainTypes,
+             final NatureOfService natureOfServiceFallback,
+             final IntrospectionStrategy introspectionStrategy,
+             final List<ObjectSpecification> appendTo) {
  
-         final Set<Class<?>> mixinTypes = AppManifest.Registry.instance().getMixinTypes();
-         if(mixinTypes == null) {
-             return;
-         }
-         for (final Class<?> mixinType : mixinTypes) {
-             ObjectSpecification objectSpecification = internalLoadSpecification(mixinType);
-             facetProcessorObjectSpecId.process(
-                     mixinType,
-                     MethodRemoverConstants.NULL, objectSpecification);
+         for (final Class<?> domainType : domainTypes) {
  
+             ObjectSpecification objectSpecification =
+                 internalLoadSpecification(domainType, natureOfServiceFallback, introspectionStrategy);
+ 
+             if(objectSpecification != null) {
+                 appendTo.add(objectSpecification);
+             }
          }
      }
  
-     private void cacheBySpecId() {
++
+     private void cacheBySpecId(final Collection<ObjectSpecification> objectSpecifications) {
 -        final Map<ObjectSpecId, ObjectSpecification> specById = Maps.newHashMap();
 +        final Map<ObjectSpecId, ObjectSpecification> specById = _Maps.newHashMap();
-         for (final ObjectSpecification objSpec : allCachedSpecifications()) {
+         for (final ObjectSpecification objSpec : objectSpecifications) {
              final ObjectSpecId objectSpecId = objSpec.getSpecId();
              if (objectSpecId == null) {
                  continue;
@@@ -435,14 -524,16 +484,16 @@@
  
          // ... 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(
 +            final ConfigurationServiceInternal configService = servicesInjector.lookupServiceElseFail(
                      ConfigurationServiceInternal.class);
              final FacetedMethodsBuilderContext facetedMethodsBuilderContext =
                      new FacetedMethodsBuilderContext(
 -                            this, facetProcessor, layoutMetadataReaders, configService);
 +                            this, facetProcessor, configService);
+ 
+             final NatureOfService natureOfServiceIfAny = natureOfServiceFrom(cls, fallback);
+ 
              return new ObjectSpecificationDefault(cls, facetedMethodsBuilderContext,
                      servicesInjector, facetProcessor, natureOfServiceIfAny);
          }
@@@ -560,9 -669,14 +618,12 @@@
          return cache.get(fullyQualifiedClassName) != null;
      }
  
 -    //endregion
 -
 -    //region > lookupBySpecId
 +    // -- lookupBySpecId
      @Programmatic
      public ObjectSpecification lookupBySpecId(ObjectSpecId objectSpecId) {
+         if(!cache.isInitialized()) {
+             throw new IllegalStateException("Internal cache not yet initialized");
+         }
          final ObjectSpecification objectSpecification = cache.getByObjectType(objectSpecId);
          if(objectSpecification == null) {
              // fallback
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutor.java
index 31e461d,df2ac9a..cf1255b
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutor.java
@@@ -114,10 -114,23 +114,23 @@@ public class ClassSubstitutor 
              return true;
          }
  
-         return classesToIgnore.contains(cls) || classNamesToIgnore.contains(cls.getCanonicalName());
+         try{
+             return classesToIgnore.contains(cls) || classNamesToIgnore.contains(cls.getCanonicalName());
+         } catch(java.lang.NoClassDefFoundError e) {
+ 
+             try{
+                 if(cls.isAnonymousClass()) {
+                     return shouldIgnore(cls.getSuperclass());
+                 } else {
+                     return false;
+                 }
+             } catch(java.lang.NoClassDefFoundError ex) {
+                 return true;
+             }
+         }
      }
  
 -    //endregion
 +
  
  
  }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index d562294,119c8f4..e0ca905
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@@ -161,9 -162,14 +161,14 @@@ public class ObjectSpecificationDefaul
              updateInterfaces(interfaceSpecList);
          }
  
+         updateAssociationsAndActions();
+     }
+ 
+     private synchronized void updateAssociationsAndActions() {
+ 
          // associations and actions
          if(isNotIntrospected()) {
 -            final List<ObjectAssociation> associations = createAssociations(metadataProperties);
 +            final List<ObjectAssociation> associations = createAssociations();
              sortAndUpdateAssociations(associations);
          }
  
diff --cc core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
index eba6176,9cf8ce8..ac05bb2
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
@@@ -107,10 -106,10 +106,10 @@@ public class SpecificationCacheDefaultT
  
      @Test
      public void getByObjectType_whenSet() {
 -        Map<ObjectSpecId, ObjectSpecification> specByObjectType = Maps.newHashMap();
 +        Map<ObjectSpecId, ObjectSpecification> specByObjectType = _Maps.newHashMap();
          specByObjectType.put(ObjectSpecId.of("CUS"), customerSpec);
          
-         specificationCache.setCacheBySpecId(specByObjectType);
+         specificationCache.init(specByObjectType);
          final ObjectSpecification objectSpec = specificationCache.getByObjectType(ObjectSpecId.of("CUS"));
          
          assertSame(objectSpec, customerSpec);
diff --cc core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
index 907ce73,8e386f2..d697f59
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
@@@ -19,19 -19,18 +19,20 @@@
  
  package org.apache.isis.core.metamodel.specloader;
  
- import org.apache.isis.commons.internal.collections._Lists;
 -import com.google.common.collect.Lists;
--
  import org.jmock.Expectations;
  import org.jmock.auto.Mock;
 +import org.junit.After;
  import org.junit.Assert;
  import org.junit.Before;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.ExpectedException;
  
++import org.apache.isis.applib.AppManifest;
  import org.apache.isis.applib.services.grid.GridService;
  import org.apache.isis.applib.services.message.MessageService;
++import org.apache.isis.commons.internal.collections._Lists;
++import org.apache.isis.commons.internal.collections._Sets;
  import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
  import org.apache.isis.core.commons.config.IsisConfigurationDefault;
  import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
@@@ -113,6 -114,6 +114,14 @@@ public abstract class SpecificationLoad
  
          stubServicesInjector.addFallbackIfRequired(SpecificationLoader.class, specificationLoader);
  
++        AppManifest.Registry.instance().setDomainServiceTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setFixtureScriptTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setDomainObjectTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setMixinTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setViewModelTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setPersistenceCapableTypes(_Sets.newHashSet());
++        AppManifest.Registry.instance().setXmlElementTypes(_Sets.newHashSet());
++
          specificationLoader.init();
          
          specification = loadSpecification(specificationLoader);
diff --cc core/pom.xml
index 4fc7a63,88e31a9..300893d
--- a/core/pom.xml
+++ b/core/pom.xml
@@@ -46,9 -46,12 +46,12 @@@
      <inceptionYear>2010</inceptionYear>
  
      <properties>
 -        <revision>1.0.0-SNAPSHOT</revision>
 +        <revision>2.0.0-M2-SNAPSHOT</revision>
          <isis.version>${revision}</isis.version>
  
+         <isis.skipTests>false</isis.skipTests>
+         <maven.test.skip>${isis.skipTests}</maven.test.skip>
+ 
          <jar-plugin.automaticModuleName>org.apache.isis.core</jar-plugin.automaticModuleName>
          <git-plugin.propertiesDir>org/apache/isis/core</git-plugin.propertiesDir>
  
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisComponentProvider.java
index 4f8f514,1e69806..52e8e19
--- 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
@@@ -23,21 -23,30 +23,24 @@@ import java.util.Collection
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
 +import java.util.function.Function;
 +import java.util.stream.Collectors;
 +import java.util.stream.Stream;
  
  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;
 -import com.google.common.base.Predicate;
 -import com.google.common.collect.FluentIterable;
 -import com.google.common.collect.Iterables;
 -import com.google.common.collect.Lists;
 -import com.google.common.collect.Sets;
 -
 -import org.reflections.Reflections;
 -import org.reflections.vfs.Vfs;
  
  import org.apache.isis.applib.AppManifest;
  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.commons.internal.base._NullSafe;
 +import org.apache.isis.commons.internal.collections._Lists;
 +import org.apache.isis.commons.internal.collections._Sets;
  import org.apache.isis.core.commons.config.IsisConfiguration;
  import org.apache.isis.core.commons.config.IsisConfigurationDefault;
  import org.apache.isis.core.commons.factory.InstanceUtil;
@@@ -125,31 -133,39 +128,34 @@@ public abstract class IsisComponentProv
      }
  
      private void findAndRegisterTypes(final AppManifest appManifest) {
 -        final Iterable<String> modulePackages = modulePackageNamesFrom(appManifest);
 +        final Stream<String> modulePackages = modulePackageNamesFrom(appManifest);
          final AppManifest.Registry registry = AppManifest.Registry.instance();
  
 -        final List<String> moduleAndFrameworkPackages = Lists.newArrayList();
 +        final List<String> moduleAndFrameworkPackages = _Lists.newArrayList();
          moduleAndFrameworkPackages.addAll(AppManifest.Registry.FRAMEWORK_PROVIDED_SERVICES);
 -        Iterables.addAll(moduleAndFrameworkPackages, modulePackages);
 +        
 +        modulePackages.forEach(moduleAndFrameworkPackages::add);
  
 -        Vfs.setDefaultURLTypes(ClassDiscoveryServiceUsingReflections.getUrlTypes());
 +        final ClassDiscovery discovery = ClassDiscoveryPlugin.get().discover(moduleAndFrameworkPackages);
  
 -        final Reflections reflections = new Reflections(moduleAndFrameworkPackages);
 +        final Set<Class<?>> domainServiceTypes = discovery.getTypesAnnotatedWith(DomainService.class);
 +        final Set<Class<?>> persistenceCapableTypes = PersistenceCapableTypeFinder.find(discovery);
 +        final Set<Class<? extends FixtureScript>> fixtureScriptTypes = discovery.getSubTypesOf(FixtureScript.class);
  
 -        final Set<Class<?>> domainServiceTypes = reflections.getTypesAnnotatedWith(DomainService.class);
 -        final Set<Class<?>> persistenceCapableTypes = reflections.getTypesAnnotatedWith(PersistenceCapable.class);
 -        final Set<Class<? extends FixtureScript>> fixtureScriptTypes = reflections.getSubTypesOf(FixtureScript.class);
 +        final Set<Class<?>> mixinTypes = _Sets.newHashSet();
 +        mixinTypes.addAll(discovery.getTypesAnnotatedWith(Mixin.class));
  
 -        final Set<Class<?>> mixinTypes = Sets.newHashSet();
 -        mixinTypes.addAll(reflections.getTypesAnnotatedWith(Mixin.class));
 +        final Set<Class<?>> domainObjectTypes = discovery.getTypesAnnotatedWith(DomainObject.class);
 +        domainObjectTypes.stream()
 +        .filter(input -> {
 +            final DomainObject annotation = input.getAnnotation(DomainObject.class);
 +            return annotation.nature() == Nature.MIXIN;
 +        })
 +        .forEach(mixinTypes::add);
  
 -        final Set<Class<?>> domainObjectTypes = reflections.getTypesAnnotatedWith(DomainObject.class);
 -        mixinTypes.addAll(
 -                Lists.newArrayList(Iterables.filter(domainObjectTypes, new Predicate<Class<?>>() {
 -                    @Override
 -                    public boolean apply(@Nullable final Class<?> input) {
 -                        if(input == null) { return false; }
 -                        final DomainObject annotation = input.getAnnotation(DomainObject.class);
 -                        return annotation.nature() == Nature.MIXIN;
 -                    }
 -                }))
 -        );
 -
 -        final Set<Class<?>> viewModelTypes = reflections.getTypesAnnotatedWith(ViewModel.class);
 -        final Set<Class<?>> xmlElementTypes = reflections.getTypesAnnotatedWith(XmlElement.class);
++        final Set<Class<?>> viewModelTypes = discovery.getTypesAnnotatedWith(ViewModel.class);
++        final Set<Class<?>> xmlElementTypes = discovery.getTypesAnnotatedWith(XmlElement.class);
+ 
          // add in any explicitly registered services...
          domainServiceTypes.addAll(appManifest.getAdditionalServices());