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 <d...@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());