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/12/13 06:13:53 UTC
[isis] 03/13: ISIS-2050: replaces IntrospectionStrategy with the
concept of introspecting "up to" a certain state.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2050
in repository https://gitbox.apache.org/repos/asf/isis.git
commit d352736e2e5771385ca821db40161da77e051b35
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Dec 12 22:49:55 2018 +0100
ISIS-2050: replaces IntrospectionStrategy with the concept of introspecting "up to" a certain state.
---
.../metamodel/specloader/SpecificationLoader.java | 86 ++++++++--------------
.../specloader/specimpl/IntrospectionState.java | 33 +++++++++
.../specimpl/ObjectSpecificationAbstract.java | 46 ++++++------
.../IntrospectionState_comparable_Test.java | 72 ++++++++++++++++++
4 files changed, 158 insertions(+), 79 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index fb106ca..8b21cce 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -41,8 +41,6 @@ import org.apache.isis.core.commons.ensure.Assert;
import org.apache.isis.core.commons.exceptions.IsisException;
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.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;
@@ -55,6 +53,7 @@ import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitut
import org.apache.isis.core.metamodel.specloader.facetprocessor.FacetProcessor;
import org.apache.isis.core.metamodel.specloader.postprocessor.PostProcessor;
import org.apache.isis.core.metamodel.specloader.specimpl.FacetedMethodsBuilderContext;
+import org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState;
import org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract;
import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
import org.apache.isis.core.metamodel.specloader.specimpl.standalonelist.ObjectSpecificationOnStandaloneList;
@@ -182,22 +181,28 @@ public class SpecificationLoader implements ApplicationScopedComponent {
loadSpecificationsFor(
CommonDtoUtils.VALUE_TYPES, null,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
loadSpecificationsFor(
allServiceClasses(), NatureOfService.DOMAIN,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
loadSpecificationsFor(
AppManifest.Registry.instance().getMixinTypes(), null,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
loadSpecificationsFor(
AppManifest.Registry.instance().getDomainObjectTypes(), null,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
loadSpecificationsFor(
AppManifest.Registry.instance().getViewModelTypes(), null,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
loadSpecificationsFor(
AppManifest.Registry.instance().getXmlElementTypes(), null,
- IntrospectionStrategy.STUB, specificationsFromRegistry);
+ specificationsFromRegistry, IntrospectionState.NOT_INTROSPECTED
+ );
state = State.INTROSPECTING;
final Collection<ObjectSpecification> cachedSpecifications = allCachedSpecifications();
@@ -233,7 +238,10 @@ public class SpecificationLoader implements ApplicationScopedComponent {
Callable<Object> callable = new Callable<Object>() {
@Override
public Object call() {
- introspectIfRequired(specification);
+
+ final ObjectSpecificationAbstract specSpi = (ObjectSpecificationAbstract) specification;
+ specSpi.introspectIfRequired(IntrospectionState.INTROSPECTED);
+
return null;
}
public String toString() {
@@ -279,13 +287,13 @@ public class SpecificationLoader implements ApplicationScopedComponent {
private void loadSpecificationsFor(
final Collection<Class<?>> domainTypes,
final NatureOfService natureOfServiceFallback,
- final IntrospectionStrategy introspectionStrategy,
- final List<ObjectSpecification> appendTo) {
+ final List<ObjectSpecification> appendTo,
+ final IntrospectionState upTo) {
for (final Class<?> domainType : domainTypes) {
ObjectSpecification objectSpecification =
- internalLoadSpecification(domainType, natureOfServiceFallback, introspectionStrategy);
+ internalLoadSpecification(domainType, natureOfServiceFallback, upTo);
if(objectSpecification != null) {
appendTo.add(objectSpecification);
@@ -419,36 +427,25 @@ public class SpecificationLoader implements ApplicationScopedComponent {
return spec;
}
- enum IntrospectionStrategy {
- /**
- * Used in a first pass to create ObjectSpecifications that haven't been introspected,
- * but are cached.
- */
- STUB,
- /**
- * Second phase (default), to fully introspect.
- */
- COMPLETE
- }
private ObjectSpecification internalLoadSpecification(final Class<?> type) {
- return internalLoadSpecification(type, null, IntrospectionStrategy.COMPLETE);
+ return internalLoadSpecification(type, null, IntrospectionState.INTROSPECTED);
}
private ObjectSpecification internalLoadSpecification(
final Class<?> type,
final NatureOfService natureFallback,
- final IntrospectionStrategy introspectionStrategy) {
+ final IntrospectionState upTo) {
final Class<?> substitutedType = classSubstitutor.getClass(type);
return substitutedType != null
- ? loadSpecificationForSubstitutedClass(substitutedType, natureFallback, introspectionStrategy)
+ ? loadSpecificationForSubstitutedClass(substitutedType, natureFallback, upTo)
: null;
}
private ObjectSpecification loadSpecificationForSubstitutedClass(
final Class<?> type,
final NatureOfService natureFallback,
- final IntrospectionStrategy introspectionStrategy) {
+ final IntrospectionState upTo) {
Assert.assertNotNull(type);
final String typeName = type.getName();
@@ -457,14 +454,14 @@ public class SpecificationLoader implements ApplicationScopedComponent {
return spec;
}
- return loadSpecificationForSubstitutedClassSynchronized(type, natureFallback, introspectionStrategy);
+ return loadSpecificationForSubstitutedClassSynchronized(type, natureFallback, upTo);
}
private synchronized ObjectSpecification loadSpecificationForSubstitutedClassSynchronized(
final Class<?> type,
final NatureOfService natureOfServiceFallback,
- final IntrospectionStrategy introspectionStrategy) {
+ final IntrospectionState upTo) {
final String typeName = type.getName();
final ObjectSpecification spec = cache.get(typeName);
@@ -479,8 +476,9 @@ public class SpecificationLoader implements ApplicationScopedComponent {
// infinite loops
cache.cache(typeName, specification);
- if(introspectionStrategy == IntrospectionStrategy.COMPLETE) {
- introspectIfRequired(specification);
+ if (state == State.INTROSPECTING) {
+ final ObjectSpecificationAbstract specSpi = (ObjectSpecificationAbstract) specification;
+ specSpi.introspectIfRequired(upTo);
}
return specification;
@@ -495,8 +493,8 @@ public class SpecificationLoader implements ApplicationScopedComponent {
boolean anyLoadedAsNull = false;
for (final Class<?> typeToLoad : typesToLoad) {
if (typeToLoad != typeToIgnore) {
- final ObjectSpecification noSpec = internalLoadSpecification(typeToLoad);
- final boolean loadedAsNull = (noSpec == null);
+ final ObjectSpecification objectSpecification = internalLoadSpecification(typeToLoad);
+ final boolean loadedAsNull = (objectSpecification == null);
anyLoadedAsNull = loadedAsNull || anyLoadedAsNull;
}
}
@@ -558,28 +556,6 @@ public class SpecificationLoader implements ApplicationScopedComponent {
return Class.forName(className);
}
- /**
- * Typically does not need to be called, but is available for {@link FacetFactory}s to force
- * early introspection of referenced specs in certain circumstances.
- *
- * <p>
- * Originally introduced to support {@link AutoCompleteFacet}.
- */
- private void introspectIfRequired(final ObjectSpecification spec) {
-
- if(state != State.INTROSPECTING) {
- return;
- }
-
- if (!(spec instanceof ObjectSpecificationAbstract)) {
- // shouldn't happen... the only other implementation is a test stub.
- return;
- }
-
- final ObjectSpecificationAbstract specSpi = (ObjectSpecificationAbstract)spec;
- specSpi.introspectIfRequired();
-
- }
@Programmatic
public void postProcess() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState.java
new file mode 100644
index 0000000..83c91c4
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState.java
@@ -0,0 +1,33 @@
+/**
+ * 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.specloader.specimpl;
+
+public enum IntrospectionState implements Comparable<IntrospectionState> {
+ /**
+ * ObjectSpecIdFacet only.
+ */
+ NOT_INTROSPECTED,
+ /**
+ * Interim stage, to avoid infinite loops while on way to being {@link #INTROSPECTED}
+ */
+ BEING_INTROSPECTED,
+ /**
+ * Fully introspected... class and also its members.
+ */
+ INTROSPECTED
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index 1c39e64..81460d8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -246,13 +246,6 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
return fullName;
}
-
- public enum IntrospectionState {
- NOT_INTROSPECTED,
- BEING_INTROSPECTED,
- INTROSPECTED,
- }
-
protected boolean isNotIntrospected() {
return !(introspectionState == IntrospectionState.INTROSPECTED);
}
@@ -269,25 +262,30 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
facetProcessor.processObjectSpecId(correspondingClass, this);
}
- public void introspectIfRequired() {
+ /**
+ * Keeps introspecting up to the level required.
+ */
+ public void introspectIfRequired(final IntrospectionState upTo) {
- switch (introspectionState) {
- case NOT_INTROSPECTED:
- // avoid infinite loops
- this.introspectionState = IntrospectionState.BEING_INTROSPECTED;
- try {
- introspectTypeHierarchyAndMembers();
- updateFromFacetValues();
- this.introspectionState = IntrospectionState.INTROSPECTED;
- } catch(Exception ex) {
- this.introspectionState = IntrospectionState.NOT_INTROSPECTED;
- throw ex;
+ while(this.introspectionState.compareTo(upTo) < 0) {
+ switch (introspectionState) {
+ case NOT_INTROSPECTED:
+ // avoid infinite loops
+ this.introspectionState = IntrospectionState.BEING_INTROSPECTED;
+ try {
+ introspectTypeHierarchyAndMembers();
+ updateFromFacetValues();
+ this.introspectionState = IntrospectionState.INTROSPECTED;
+ } catch(Exception ex) {
+ this.introspectionState = IntrospectionState.NOT_INTROSPECTED;
+ throw ex;
+ }
+ break;
+ case BEING_INTROSPECTED:
+ case INTROSPECTED:
+ // nothing to do
+ break;
}
- break;
- case BEING_INTROSPECTED:
- case INTROSPECTED:
- // nothing to do
- break;
}
}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState_comparable_Test.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState_comparable_Test.java
new file mode 100644
index 0000000..eefda8e
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/IntrospectionState_comparable_Test.java
@@ -0,0 +1,72 @@
+package org.apache.isis.core.metamodel.specloader.specimpl;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Test;
+
+import static org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState.BEING_INTROSPECTED;
+import static org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState.INTROSPECTED;
+import static org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState.NOT_INTROSPECTED;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class IntrospectionState_comparable_Test {
+
+ @Test
+ public void all_of_em() throws Exception {
+ assertComparison(NOT_INTROSPECTED, NOT_INTROSPECTED, equal());
+ assertComparison(NOT_INTROSPECTED, BEING_INTROSPECTED, negative());
+ assertComparison(NOT_INTROSPECTED, INTROSPECTED, negative());
+
+ assertComparison(BEING_INTROSPECTED, NOT_INTROSPECTED, positive());
+ assertComparison(BEING_INTROSPECTED, BEING_INTROSPECTED, equal());
+ assertComparison(BEING_INTROSPECTED, INTROSPECTED, negative());
+
+ assertComparison(INTROSPECTED, NOT_INTROSPECTED, positive());
+ assertComparison(INTROSPECTED, BEING_INTROSPECTED, positive());
+ assertComparison(INTROSPECTED, INTROSPECTED, equal());
+ }
+
+ private Matcher<Integer> equal() {
+ return new TypeSafeMatcher<Integer>() {
+ @Override protected boolean matchesSafely(final Integer integer) {
+ return integer == 0;
+ }
+
+ @Override public void describeTo(final Description description) {
+ description.appendText("equal");
+ }
+ };
+ }
+
+ private static Matcher<Integer> negative() {
+ return new TypeSafeMatcher<Integer>() {
+ @Override protected boolean matchesSafely(final Integer integer) {
+ return integer < 0;
+ }
+
+ @Override public void describeTo(final Description description) {
+ description.appendText("negative");
+ }
+ };
+ }
+
+ private static Matcher<Integer> positive() {
+ return new TypeSafeMatcher<Integer>() {
+ @Override protected boolean matchesSafely(final Integer integer) {
+ return integer > 0;
+ }
+
+ @Override public void describeTo(final Description description) {
+ description.appendText("positive");
+ }
+ };
+ }
+
+ private static void assertComparison(
+ final IntrospectionState a,
+ final IntrospectionState b, final Matcher<Integer> matcher) {
+ assertThat(a.compareTo(b), is(matcher));
+ }
+}
\ No newline at end of file