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 2021/07/05 11:14:35 UTC
[isis] branch master updated: ISIS-2787: prepare FacetRanking to
also serve lower than winning rank
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new d4a5884 ISIS-2787: prepare FacetRanking to also serve lower than winning rank
d4a5884 is described below
commit d4a5884d59430e5b870e02eee0f90748dd802f6b
Author: andi-huber <ah...@apache.org>
AuthorDate: Mon Jul 5 13:14:22 2021 +0200
ISIS-2787: prepare FacetRanking to also serve lower than winning rank
---
.../isis/applib/services/menu/MenuBarsService.java | 4 +-
.../apache/isis/core/metamodel/facetapi/Facet.java | 18 ++++++
.../isis/core/metamodel/facetapi/FacetRanking.java | 29 +++++++++-
.../imperative/HasImperativeTextFacetAbstract.java | 2 +-
...ctFacetForRecreatableDomainObjectInterface.java | 3 +-
.../specimpl/ObjectAssociationAbstract.java | 25 +++++++--
.../menubars/bootstrap3/MenuBarsServiceBS3.java | 64 +++++++++++++---------
7 files changed, 107 insertions(+), 38 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java b/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
index e013781..8a2c3e3 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
@@ -48,9 +48,9 @@ public interface MenuBarsService {
DEFAULT,
/**
- * As derived from annotations.
+ * As derived from annotations only.
*/
- FALLBACK
+ ANNOTATED
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
index 8a35304a..2ccf02c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
@@ -71,6 +71,11 @@ extends
/**
* Higher precedence than {@link #HIGH}. In other words, overrules {@link #HIGH}.
+ */
+ IMPERATIVE,
+
+ /**
+ * Higher precedence than {@link #IMPERATIVE}. In other words, overrules {@link #IMPERATIVE}.
* <p>
* Reserved for facet post-processing, when synthesizing a 'virtual' facet
* from facets of lower rank. (eg. {@link ObjectNamedFacet} with its singular and plural noun-form support)
@@ -132,6 +137,16 @@ extends
}
/**
+ * Whether to collect all facets of this type into the facet ranks,
+ * or (when {@code false}) allow for (heap) optimization,
+ * such that only (current) top ranks are populated.
+ * @since 2.0
+ */
+ default boolean isPopulateAllFacetRanks() {
+ return false;
+ }
+
+ /**
* Determines the type of this facet to be stored under.
*
* <p>
@@ -170,4 +185,7 @@ extends
*/
void forEachContributedFacet(Consumer<Facet> onContributedFacet);
+
+
+
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetRanking.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetRanking.java
index e2b88fd..f0eaf5c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetRanking.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetRanking.java
@@ -18,6 +18,7 @@
*/
package org.apache.isis.core.metamodel.facetapi;
+import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
@@ -105,8 +106,12 @@ public final class FacetRanking {
val changesTopRank = facetPreference.ordinal() >= currentTopRankOrdinal;
- // as an optimization (heap), don't store to lower ranks, as these have no effect any way when picking a winning facet
- if(changesTopRank) {
+ // As an optimization (heap), don't store to lower ranks,
+ // as these are not considered when picking a winning facet.
+ // However, there are use-cases, where access to all facets of a given type are required,
+ // regardless of facet-precedence (eg. MemberNamedFacets).
+ if(changesTopRank
+ || facet.isPopulateAllFacetRanks()) {
facetsByPrecedence.putElement(facetPreference, facet);
}
@@ -159,6 +164,26 @@ public final class FacetRanking {
: Can.empty();
}
+ /**
+ * Returns a defensive copy of the selected rank of given precedence constraint.
+ * @param facetType - for convenience, so the caller does not need to cast the result
+ * @param precedenceUpper - upper bound
+ */
+ public <F extends Facet> Can<F> getRankLowerOrEqualTo(final @NonNull Class<F> facetType, Precedence precedenceUpper) {
+ _Assert.assertEquals(this.facetType, facetType);
+
+ val precedenceSelected = facetsByPrecedence
+ .keySet()
+ .stream()
+ .filter(precedence->precedence.ordinal()<=precedenceUpper.ordinal())
+ .max(Comparator.comparing(Precedence::ordinal));
+
+ return precedenceSelected
+ .map(facetsByPrecedence::get)
+ .map(facetsOfSameRank->Can.<F>ofCollection(_Casts.uncheckedCast(facetsOfSameRank)))
+ .orElseGet(Can::empty);
+ }
+
public Optional<Facet.Precedence> getTopPrecedence() {
return Optional.ofNullable(topPrecedenceRef.get());
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/imperative/HasImperativeTextFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/imperative/HasImperativeTextFacetAbstract.java
index 599ae1b..d50941f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/imperative/HasImperativeTextFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/imperative/HasImperativeTextFacetAbstract.java
@@ -46,7 +46,7 @@ implements
protected HasImperativeTextFacetAbstract(
final Class<? extends Facet> facetType,
- final TranslationContext translationContext, //TranslationContext.forTranslationContextHolder(holder.getFeatureIdentifier());
+ final TranslationContext translationContext,
final Method method,
final FacetHolder holder) {
// imperative takes precedence over any other (except for events)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForRecreatableDomainObjectInterface.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForRecreatableDomainObjectInterface.java
index 2cecf3f..59ecabf 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForRecreatableDomainObjectInterface.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForRecreatableDomainObjectInterface.java
@@ -23,7 +23,8 @@ import org.apache.isis.applib.RecreatableDomainObject;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
-public class RecreatableObjectFacetForRecreatableDomainObjectInterface extends RecreatableObjectFacetAbstract {
+public class RecreatableObjectFacetForRecreatableDomainObjectInterface
+extends RecreatableObjectFacetAbstract {
public RecreatableObjectFacetForRecreatableDomainObjectInterface(
final FacetHolder holder,
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectAssociationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectAssociationAbstract.java
index 2d09b85..8cf581f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectAssociationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectAssociationAbstract.java
@@ -20,12 +20,15 @@
package org.apache.isis.core.metamodel.specloader.specimpl;
import org.apache.isis.applib.Identifier;
+import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.Facet.Precedence;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facetapi.FeatureType;
import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.described.CanonicalDescribedFacet;
-import org.apache.isis.core.metamodel.facets.all.named.CanonicalNamedFacet;
+import org.apache.isis.core.metamodel.facets.all.described.MemberDescribedFacet;
+import org.apache.isis.core.metamodel.facets.all.i8n.staatic.HasStaticText;
+import org.apache.isis.core.metamodel.facets.all.named.MemberNamedFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacet;
@@ -92,8 +95,13 @@ implements ObjectAssociation {
@Override
public final String getCanonicalFriendlyName() {
- return lookupFacet(CanonicalNamedFacet.class)
- .map(CanonicalNamedFacet::translated)
+ return lookupFacet(MemberNamedFacet.class)
+ .flatMap(MemberNamedFacet::getSharedFacetRanking)
+ .map(facetRanking->facetRanking.getRankLowerOrEqualTo(MemberNamedFacet.class, Precedence.HIGH))
+ .flatMap(Can::getLast) // TODO ranking implementation detail
+ .map(MemberNamedFacet::getSpecialization)
+ .flatMap(specialization->specialization.left())
+ .map(HasStaticText::translated)
//we have a facet-post-processor to ensure following code path is unreachable,
// however, we keep it in support of JUnit testing
.orElseGet(()->getFeatureIdentifier().getMemberNaturalName());
@@ -101,8 +109,13 @@ implements ObjectAssociation {
@Override
public final String getCanonicalDescription() {
- return lookupFacet(CanonicalDescribedFacet.class)
- .map(CanonicalDescribedFacet::translated)
+ return lookupFacet(MemberDescribedFacet.class)
+ .flatMap(MemberDescribedFacet::getSharedFacetRanking)
+ .map(facetRanking->facetRanking.getRankLowerOrEqualTo(MemberDescribedFacet.class, Precedence.HIGH))
+ .flatMap(Can::getLast) // TODO ranking implementation detail
+ .map(MemberDescribedFacet::getSpecialization)
+ .flatMap(specialization->specialization.left())
+ .map(HasStaticText::translated)
.orElse(null);
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/menubars/bootstrap3/MenuBarsServiceBS3.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/menubars/bootstrap3/MenuBarsServiceBS3.java
index 9de5cdb..43158cb 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/menubars/bootstrap3/MenuBarsServiceBS3.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/menubars/bootstrap3/MenuBarsServiceBS3.java
@@ -45,14 +45,17 @@ import org.apache.isis.applib.services.jaxb.JaxbService;
import org.apache.isis.applib.services.menu.MenuBarsLoaderService;
import org.apache.isis.applib.services.menu.MenuBarsService;
import org.apache.isis.applib.services.message.MessageService;
-import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Lazy;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.commons.internal.collections._Maps;
import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.core.config.environment.IsisSystemEnvironment;
import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.facetapi.Facet.Precedence;
import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.NotInServiceMenuFacet;
+import org.apache.isis.core.metamodel.facets.all.named.MemberNamedFacet;
import org.apache.isis.core.metamodel.facets.members.layout.group.LayoutGroupFacet;
import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
@@ -91,20 +94,22 @@ implements MenuBarsService {
private final IsisSystemEnvironment isisSystemEnvironment;
private final MetaModelContext metaModelContext;
+ private final _Lazy<BS3MenuBars> menuBarsFromAnnotationsOnly = _Lazy.threadSafe(this::menuBarsFromAnnotationsOnly);
+
BS3MenuBars menuBars;
@Override
public BS3MenuBars menuBars(final Type type) {
- val fallbackMenuBars = deriveMenuBarsFromMetaModelFacets();
+ val menuBarsFromAnnotationsOnly = this.menuBarsFromAnnotationsOnly.get();
- if(type == Type.FALLBACK) {
- return fallbackMenuBars;
+ if(type == Type.ANNOTATED) {
+ return menuBarsFromAnnotationsOnly;
}
// else load (and only fallback if nothing could be loaded)...
if(menuBars == null || menuBarsLoaderService.supportsReloading()) {
- this.menuBars = loadOrElse(fallbackMenuBars);
+ this.menuBars = loadOrElse(menuBarsFromAnnotationsOnly);
}
return menuBars;
@@ -112,22 +117,22 @@ implements MenuBarsService {
// -- HELPER
- private BS3MenuBars loadOrElse(final BS3MenuBars fallbackMenuBars) {
+ private BS3MenuBars loadOrElse(final BS3MenuBars menuBarsFromAnnotationsOnly) {
val menuBars = Optional.ofNullable(menuBarsLoaderService.menuBars())
.map(this::addTnsAndSchemaLocation)
- .orElse(fallbackMenuBars);
+ .orElse(menuBarsFromAnnotationsOnly);
val unreferencedActionsMenu = validateAndGetUnreferencedActionMenu(menuBars);
if (unreferencedActionsMenu == null) {
// just use fallback
- return fallbackMenuBars;
+ return menuBarsFromAnnotationsOnly;
}
// add in any missing actions from the fallback
val referencedActionsByObjectTypeAndId = menuBars.getAllServiceActionsByObjectTypeAndId();
- fallbackMenuBars.visit(BS3MenuBars.VisitorAdapter.visitingMenuSections(menuSection->{
+ menuBarsFromAnnotationsOnly.visit(BS3MenuBars.VisitorAdapter.visitingMenuSections(menuSection->{
// created only if required to collect unreferenced actions
// for this menuSection into a new section within the designated
@@ -202,16 +207,16 @@ implements MenuBarsService {
return null;
}
- private BS3MenuBars deriveMenuBarsFromMetaModelFacets() {
+ private BS3MenuBars menuBarsFromAnnotationsOnly() {
final BS3MenuBars menuBars = new BS3MenuBars();
- final List<ManagedObject> visibleServiceAdapters = metaModelContext.streamServiceAdapters()
+ val visibleServiceAdapters = metaModelContext.streamServiceAdapters()
.filter(this::isVisibleAdapterForMenu)
- .collect(Collectors.toList());
+ .collect(Can.toCan());
- append(visibleServiceAdapters, menuBars.getPrimary(), DomainServiceLayout.MenuBar.PRIMARY);
- append(visibleServiceAdapters, menuBars.getSecondary(), DomainServiceLayout.MenuBar.SECONDARY);
- append(visibleServiceAdapters, menuBars.getTertiary(), DomainServiceLayout.MenuBar.TERTIARY);
+ appendFromAnnotationsOnly(visibleServiceAdapters, menuBars.getPrimary(), DomainServiceLayout.MenuBar.PRIMARY);
+ appendFromAnnotationsOnly(visibleServiceAdapters, menuBars.getSecondary(), DomainServiceLayout.MenuBar.SECONDARY);
+ appendFromAnnotationsOnly(visibleServiceAdapters, menuBars.getTertiary(), DomainServiceLayout.MenuBar.TERTIARY);
menuBars.setTnsAndSchemaLocation(tnsAndSchemaLocation());
@@ -236,15 +241,15 @@ implements MenuBarsService {
}
- private void append(
- final List<ManagedObject> serviceAdapters,
+ private void appendFromAnnotationsOnly(
+ final Can<ManagedObject> serviceAdapters,
final BS3MenuBar menuBar,
final DomainServiceLayout.MenuBar menuBarPos) {
val serviceActions = _Lists.<ServiceAndAction>newArrayList();
// cf ServiceActionsModel & ServiceActionUtil#buildMenu in Wicket viewer
- _NullSafe.stream(serviceAdapters)
+ serviceAdapters.stream()
.filter(with(menuBarPos))
.forEach(serviceAdapter->{
@@ -259,11 +264,11 @@ implements MenuBarsService {
// prune any service names that have no service actions
serviceNamesInOrder.retainAll(serviceActionsByName.keySet());
- List<BS3Menu> menus = buildMenuItems(serviceNamesInOrder, serviceActionsByName);
+ List<BS3Menu> menus = buildMenuItemsFromAnnotationsOnly(serviceNamesInOrder, serviceActionsByName);
menuBar.getMenus().addAll(menus);
}
- private static List<BS3Menu> buildMenuItems(
+ private static List<BS3Menu> buildMenuItemsFromAnnotationsOnly(
final Set<String> serviceNamesInOrder,
final Map<String, List<ServiceAndAction>> serviceActionsByName) {
@@ -282,12 +287,19 @@ implements MenuBarsService {
menuSection = new BS3MenuSection();
}
- ObjectAction objectAction = serviceAndAction.getObjectAction();
+ val objectAction = serviceAndAction.getObjectAction();
val service = serviceAndAction.getServiceAdapter();
- final String logicalTypeName = serviceAndAction.getServiceAdapter().getSpecification().getLogicalTypeName();
- ServiceActionLayoutData action = new ServiceActionLayoutData(logicalTypeName, objectAction.getId());
- action.setNamed(objectAction.getFriendlyName(service.asProvider()));
- menuSection.getServiceActions().add(action);
+ val logicalTypeName = serviceAndAction.getServiceAdapter().getSpecification().getLogicalTypeName();
+ val actionLayoutData = new ServiceActionLayoutData(logicalTypeName, objectAction.getId());
+
+ objectAction
+ .getFacetRanking(MemberNamedFacet.class)
+ .get()
+ .getRankLowerOrEqualTo(MemberNamedFacet.class, Precedence.DEFAULT)
+ .getLastOrFail();
+
+ actionLayoutData.setNamed(objectAction.getFriendlyName(service.asProvider()));
+ menuSection.getServiceActions().add(actionLayoutData);
}
if(!menuSection.getServiceActions().isEmpty()) {
menu.getSections().add(menuSection);
@@ -303,7 +315,7 @@ implements MenuBarsService {
* straight copy from Wicket UI
*/
private static Set<String> serviceNamesInOrder(
- final List<ManagedObject> serviceAdapters,
+ final Can<ManagedObject> serviceAdapters,
final List<ServiceAndAction> serviceActions) {
final Set<String> serviceNameOrder = _Sets.newLinkedHashSet();