Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.causeway.applib.services.appfeat;

/**
* The various viewer implementations will individually honor any filters registered with Spring,
* based on a matching qualifier ('Graphql', 'Restful', etc.).
*
* <p>All filters that match a qualifier are consulted until any one rejects the {@link ApplicationFeature}.
*
* <p>If no filters match a qualifier, any {@link ApplicationFeature} is accepted.
*
* <p>'NoViewer' is a reserved string internally used to mean 'no filtering', hence it should not be used to qualify a filter.
*
* @since 4.0 {@index}
*/
@FunctionalInterface
public interface ApplicationFeatureFilter {

/**
* Whether to include given {@link ApplicationFeature}.
*/
boolean filter(ApplicationFeature feature);

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@

import java.util.UUID;

import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;

import org.apache.causeway.applib.annotation.Where;
import org.apache.causeway.applib.services.iactnlayer.InteractionContext;
import org.apache.causeway.commons.collections.Can;
import org.apache.causeway.schema.cmd.v2.CommandDto;
Expand Down Expand Up @@ -50,7 +51,12 @@ public record SyncControl(
*
* <p>The default behaviour is to rethrow the exception.
*/
ExceptionHandler exceptionHandler) {
ExceptionHandler exceptionHandler,
/**
* Simulated viewerId, honoring feature filtering.
*/
String viewerId,
Where where) {

//TODO can this be further simplified, or is there already an API we can reuse?

Expand Down Expand Up @@ -79,50 +85,50 @@ public void onCommand(
}

public static SyncControl defaults() {
return new SyncControl(false, false, null, null);
return new SyncControl(false, false, null, null, null, null);
}

public SyncControl(
boolean isSkipRules,
boolean isSkipExecute,
@Nullable Can<CommandListener> commandListeners,
@Nullable ExceptionHandler exceptionHandler) {
this.isSkipRules = isSkipRules;
this.isSkipExecute = isSkipExecute;
this.commandListeners = commandListeners!=null
? commandListeners
: Can.empty();
this.exceptionHandler = exceptionHandler!=null
? exceptionHandler
: exception -> { throw exception; };
public SyncControl {
commandListeners = commandListeners!=null
? commandListeners
: Can.empty();
exceptionHandler = exceptionHandler!=null
? exceptionHandler
: exception -> { throw exception; };
viewerId = StringUtils.hasText(viewerId)
? viewerId
: "NoViewer";
where = where!=null
? where
: Where.ANYWHERE;
}

/**
* Skip checking business rules (hide/disable/validate) before
* executing the underlying property or action
*/
public SyncControl withSkipRules() {
return new SyncControl(true, isSkipExecute, commandListeners, exceptionHandler);
return new SyncControl(true, isSkipExecute, commandListeners, exceptionHandler, viewerId, where);
}
public SyncControl withCheckRules() {
return new SyncControl(false, isSkipExecute, commandListeners, exceptionHandler);
return new SyncControl(false, isSkipExecute, commandListeners, exceptionHandler, viewerId, where);
}

/**
* Explicitly set the action to be executed.
*/
public SyncControl withExecute() {
return new SyncControl(isSkipRules, false, commandListeners, exceptionHandler);
return new SyncControl(isSkipRules, false, commandListeners, exceptionHandler, viewerId, where);
}
/**
* Explicitly set the action to <i>not</i> be executed, in other words a 'dry run'.
*/
public SyncControl withNoExecute() {
return new SyncControl(isSkipRules, true, commandListeners, exceptionHandler);
return new SyncControl(isSkipRules, true, commandListeners, exceptionHandler, viewerId, where);
}

public SyncControl listen(@NonNull CommandListener commandListener) {
return new SyncControl(isSkipRules, isSkipExecute, commandListeners.add(commandListener), exceptionHandler);
public SyncControl listen(@NonNull final CommandListener commandListener) {
return new SyncControl(isSkipRules, isSkipExecute, commandListeners.add(commandListener), exceptionHandler, viewerId, where);
}

/**
Expand All @@ -131,13 +137,21 @@ public SyncControl listen(@NonNull CommandListener commandListener) {
* <p>The default behaviour is to rethrow the exception.
*/
public SyncControl withExceptionHandler(final @NonNull ExceptionHandler exceptionHandler) {
return new SyncControl(isSkipRules, isSkipExecute, commandListeners, exceptionHandler);
return new SyncControl(isSkipRules, isSkipExecute, commandListeners, exceptionHandler, viewerId, where);
}

public SyncControl withViewerId(final String viewerId) {
return new SyncControl(isSkipRules, isSkipExecute, commandListeners, exceptionHandler, viewerId, where);
}

public SyncControl withWhere(final Where where) {
return new SyncControl(isSkipRules, isSkipExecute, commandListeners, exceptionHandler, viewerId, where);
}

/**
* @return whether this and other share the same execution mode, ignoring exceptionHandling
*/
public boolean isEquivalent(SyncControl other) {
public boolean isEquivalent(final SyncControl other) {
return this.isSkipExecute == other.isSkipExecute
&& this.isSkipRules == other.isSkipRules;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ public <T> Optional<T> get(final @NonNull Class<T> requiredType) {
* @see #select(Class, Annotation[])
* @see #getSingletonElseFail(Class)
*/
@SuppressWarnings("javadoc")
public <T> Can<T> select(final @NonNull Class<T> requiredType) {
var allMatchingBeans = springContext.getBeanProvider(requiredType)
.orderedStream()
Expand All @@ -128,7 +127,6 @@ public <T> Can<T> select(final @NonNull Class<T> requiredType) {
*
* @see #select(Class)
*/
@SuppressWarnings("javadoc")
public <T> Can<T> select(
final @NonNull Class<T> requiredType,
final @Nullable Annotation[] qualifiers) {
Expand Down Expand Up @@ -165,7 +163,6 @@ public <T> Can<T> select(
* @return IoC managed singleton
* @throws NoSuchElementException - if the singleton is not resolvable
*/
@SuppressWarnings("javadoc")
public <T> T getSingletonElseFail(final @NonNull Class<T> type) {
var candidates = select(type);
if (candidates.getCardinality() == Cardinality.ZERO) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.causeway.commons.net.DataUri;

import lombok.RequiredArgsConstructor;

class DataUriTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ public static VetoReason delegatedTo(final @NonNull Class<? extends ImmutableFac

/**
* Optionally the {@link VetoReason}, why consent is being vetoed, based on whether not allowed.
* <p>
* Will correspond to the {@link InteractionResult#getReason() reason} in
*
* <p>Will correspond to the {@link InteractionResult#getReason() reason} in
* the contained {@link #getInteractionResult() InteractionResult} (if one
* was specified).
*/
Expand All @@ -204,8 +204,7 @@ default Optional<String> getReasonAsString() {
/**
* Description of the interaction that this consent represents.
*
* <p>
* May be <tt>null</tt>.
* <p>May be <tt>null</tt>.
*/
String getDescription();

Expand All @@ -222,7 +221,6 @@ default Optional<String> getReasonAsString() {
* The {@link InteractionResult} that created this {@link Consent}.
*
* @return - may be <tt>null</tt> if created as a legacy {@link Consent}.
*
*/
public InteractionResult getInteractionResult();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@
*/
package org.apache.causeway.core.metamodel.consent;

import java.util.function.BiConsumer;

import org.apache.causeway.core.metamodel.facetapi.Facet;
import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
import org.apache.causeway.core.metamodel.interactions.InteractionAdvisorFacet;

import org.jspecify.annotations.NonNull;

/**
* Marker interface for implementations (specifically, {@link Facet}s) that can
Expand All @@ -34,37 +28,4 @@
*/
public interface InteractionAdvisor {

/**
* For testing purposes only.
*/
public static InteractionAdvisor forTesting() {
return new InteractionAdvisorFacet() {

@Override
public boolean semanticEquals(final @NonNull Facet other) {
return this == other;
}

@Override
public void visitAttributes(final BiConsumer<String, Object> visitor) {
}

@Override
public Class<? extends Facet> facetType() {
return null;
}

@Override
public FacetHolder facetHolder() {
return null;
}

@Override
public Precedence precedence() {
return Facet.Precedence.FALLBACK;
}

};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static ActionExecutor forAction(
throw _Exceptions.illegalArgument("arguments must be specified for action %s", owningAction);
}});

var method = actionInvocationFacetAbstract.getMethods().getFirstElseFail();
var method = actionInvocationFacetAbstract.methods().getFirstElseFail();

return new ActionExecutor(
owningAction.getMetaModelContext(), facetHolder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.collections._Lists;
import org.apache.causeway.core.metamodel.facetapi.Facet.Precedence;
import org.apache.causeway.core.metamodel.facetapi.FacetWithAttributes.DisablingOrEnabling;
import org.apache.causeway.core.metamodel.facetapi.FacetWithAttributes.HidingOrShowing;
import org.apache.causeway.core.metamodel.facetapi.FacetWithAttributes.Validating;
import org.apache.causeway.core.metamodel.interactions.DisablingInteractionAdvisor;
import org.apache.causeway.core.metamodel.interactions.HidingInteractionAdvisor;
import org.apache.causeway.core.metamodel.interactions.ValidatingInteractionAdvisor;
import org.apache.causeway.core.metamodel.util.snapshot.XmlSchema;

import lombok.experimental.UtilityClass;
Expand Down Expand Up @@ -245,9 +245,17 @@ public static void visitAttributes(Facet facet, BiConsumer<String, Object> visit
}

private String interactionAdvisors(Facet facet, final String delimiter) {
return Stream.of(Validating.class, HidingOrShowing.class, DisablingOrEnabling.class)
return Stream.of(
ValidatingInteractionAdvisor.class,
HidingInteractionAdvisor.class,
DisablingInteractionAdvisor.class)
.filter(marker->marker.isAssignableFrom(facet.getClass()))
.map(Class::getSimpleName)
.map(cls->switch(cls.getSimpleName().substring(0, 1)) {
case "V" -> "Validating";
case "H" -> "HidingOrShowing";
case "D" -> "DisablingOrEnabling";
default -> "?";
})
.collect(Collectors.joining(delimiter));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,5 @@ public interface FacetWithAttributes {
default void visitAttributes(final BiConsumer<String, Object> visitor) {
FacetUtil.visitAttributes((Facet)this, visitor);
}

/**
* Marker interface used within {@link FacetUtil#visitAttributes()}.
*/
public static interface HidingOrShowing {
}

/**
* Marker interface used within {@link FacetUtil#visitAttributes()}.
*/
public static interface DisablingOrEnabling {
}

/**
* Marker interface used within {@link FacetUtil#visitAttributes()}.
*/
public static interface Validating {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@
public interface HasImperativeAspect
extends ImperativeFacet {

ImperativeAspect getImperativeAspect();
ImperativeAspect imperativeAspect();

@Override
default Can<MethodFacade> getMethods() {
return getImperativeAspect().methods();
default Can<MethodFacade> methods() {
return imperativeAspect().methods();
}

@Override
default Intent getIntent() {
return getImperativeAspect().intent();
default Intent intent() {
return imperativeAspect().intent();
}

}
Loading