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 2022/07/13 17:24:34 UTC
[isis] branch ISIS-3002 updated: ISIS-3002: wip ... commandlog test plus Strinifier, mostly
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-3002
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/ISIS-3002 by this push:
new 9d890d1bb7 ISIS-3002: wip ... commandlog test plus Strinifier, mostly
9d890d1bb7 is described below
commit 9d890d1bb731d9c52065c9bcc9bd17948d5d2a6a
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Jul 13 18:24:22 2022 +0100
ISIS-3002: wip ... commandlog test plus Strinifier, mostly
---
.../org/apache/isis/applib/IsisModuleApplib.java | 2 +
.../applib/mixins/system/DomainChangeRecord.java | 2 +-
.../applib/services/bookmark/BookmarkService.java | 37 +++
.../isis/commons/internal/memento/_Mementos.java | 2 +
.../actions/action/invocation/IdentifierUtil.java | 45 +++-
.../publish/command/CommandPublishingFacet.java | 4 +-
.../core/metamodel/spec/feature/ObjectAction.java | 2 -
.../core/metamodel/spec/feature/ObjectMember.java | 5 +
.../specimpl/OneToManyAssociationMixedIn.java | 7 +-
.../bookmarks/BookmarkServiceDefault.java | 33 ++-
.../command/CommandDtoFactoryDefault.java | 4 +-
.../executor/MemberExecutorServiceDefault.java | 6 +-
.../images/jpa/JavaAwtBufferedImageJpa.java | 2 +-
.../commandlog/applib/dom/CommandLogEntry.java | 20 +-
.../applib/dom/CommandLogEntryRepository.java | 27 +-
.../subscriber/CommandSubscriberForCommandLog.java | 7 +-
.../integtest/CommandLogIntegTestAbstract.java | 256 ++++++++++++++++--
.../integtest/model/CommandLogTestDomainModel.java | 4 +
.../commandlog/applib/integtest/model/Counter.java | 53 ++++
.../applib/integtest/model/CounterRepository.java | 15 ++
.../integtest/model/Counter_bumpUsingMixin.java | 17 ++
...umpUsingMixinWithCommandPublishingDisabled.java | 17 ++
.../jdo/IsisModuleExtCommandLogPersistenceJdo.java | 3 +
.../commandlog/jdo/dom/CommandLogEntry.java | 12 +-
.../commandlog/jdo/CommandLog_IntegTest.java | 11 +-
.../extensions/commandlog/jdo/model/Counter.java | 52 ++++
.../commandlog/jdo/model/CounterRepository.java | 36 +++
.../src/test/resources/application-test.yml | 29 ++
.../jpa/IsisModuleExtCommandLogPersistenceJpa.java | 7 +-
.../commandlog/jpa/dom/CommandLogEntry.java | 37 +--
.../commandlog/jpa/dom/CommandLogEntryPK.java | 58 ++++
.../jpa/dom/CommandLogEntryRepository.java | 9 +-
.../resources/META-INF/orm-commandlog.template | 6 +-
.../commandlog/jpa/CommandLog_IntegTest.java | 12 +-
.../extensions/commandlog/jpa/model/Counter.java | 55 ++++
.../commandlog/jpa/model/CounterRepository.java | 27 ++
.../src/test/resources/META-INF/persistence.xml | 10 +
.../src/test/resources/application-test.yml | 29 ++
extensions/core/commandlog/pom.xml | 22 +-
extensions/pom.xml | 14 +
.../applib/SessionLogIntegTestAbstract.java | 4 +-
.../graphql/viewer/source/gqltestdomain/E1.java | 2 +
.../changetracking/EntityChangeTrackerJdo.java | 4 +-
.../IsisModulePersistenceJpaIntegration.java | 27 +-
.../integration/entity/JpaEntityFacetFactory.java | 37 ++-
.../JavaAwtBufferedImageByteArrayConverter.java | 2 +-
.../time/JavaTimeIsoOffsetTimeConverter.java} | 6 +-
.../time/JavaTimeIsoZonedDateTimeConverter.java} | 7 +-
.../util/JavaUtilUuidConverter.java} | 19 +-
pom.xml | 291 ++++++++++++++++++++-
.../testdomain/interact/ActionInteractionTest.java | 9 +-
51 files changed, 1271 insertions(+), 133 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
index 9c48643117..648db58652 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
@@ -37,6 +37,7 @@ import org.apache.isis.applib.services.appfeatui.ApplicationTypeMember;
import org.apache.isis.applib.services.appfeatui.ApplicationTypeProperty;
import org.apache.isis.applib.services.bookmark.BookmarkHolder_lookup;
import org.apache.isis.applib.services.bookmark.BookmarkHolder_object;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
import org.apache.isis.applib.services.clock.ClockService;
import org.apache.isis.applib.services.commanddto.conmap.ContentMappingServiceForCommandDto;
import org.apache.isis.applib.services.commanddto.conmap.ContentMappingServiceForCommandsDto;
@@ -92,6 +93,7 @@ import org.apache.isis.schema.IsisModuleSchema;
UserMenu.class,
// @Service(s)
+ BookmarkService.Stringifier.Noop.class,
CommandDtoProcessorServiceIdentity.class,
ContentMappingServiceForCommandDto.class,
ContentMappingServiceForCommandsDto.class,
diff --git a/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java b/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
index 72234bd4cd..c32ae57861 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
@@ -245,7 +245,7 @@ public interface DomainChangeRecord extends HasInteractionId, HasUsername, HasTa
default String getPropertyId() {
return null;
}
- default boolean hidePropertyIds() {
+ default boolean hidePropertyId() {
return getType() != ChangeType.AUDIT_ENTRY;
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
index 4e7c016f59..9daab17065 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
@@ -18,9 +18,12 @@
*/
package org.apache.isis.applib.services.bookmark;
+import java.io.Serializable;
import java.util.Optional;
import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
import lombok.NonNull;
@@ -91,4 +94,38 @@ public interface BookmarkService {
*/
Bookmark bookmarkForElseFail(@Nullable Object domainObject);
+ /**
+ * SPI to allow other modules to extend the bookmarking mechanism.
+ *
+ * <p>
+ * Originally introduced to allow JPA CommandLog implementation use CommandLogEntryPK for its primary key.
+ * </p>
+ */
+ interface Stringifier<T> {
+
+ Class<T> handles();
+
+ String stringify(final T value);
+ Object parse(final String stringified);
+
+ @Service
+ public class Noop implements Stringifier<Noop> {
+
+ @Override
+ public Class<Noop> handles() {
+ return Noop.class;
+ }
+
+ @Override
+ public String stringify(Noop value) {
+ throw new IllegalStateException("should never be called");
+ }
+
+ @Override
+ public Object parse(String stringified) {
+ throw new IllegalStateException("should never be called");
+ }
+ }
+
+ }
}
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/memento/_Mementos.java b/commons/src/main/java/org/apache/isis/commons/internal/memento/_Mementos.java
index ed235b4fff..7426cb3e94 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/memento/_Mementos.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/memento/_Mementos.java
@@ -111,6 +111,8 @@ public final class _Mementos {
public <T> T read(Class<T> cls, Serializable value);
}
+
+
// -- MEMENTO CONSTRUCTION
/**
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
index b8964823de..59c435700b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
@@ -26,6 +26,8 @@ import org.apache.isis.applib.services.command.Command;
import org.apache.isis.commons.internal.base._Refs;
import org.apache.isis.commons.internal.exceptions._Exceptions;
import org.apache.isis.core.metamodel.commons.StringExtensions;
+import org.apache.isis.core.metamodel.interactions.InteractionHead;
+import org.apache.isis.core.metamodel.interactions.managed.ActionInteractionHead;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -57,21 +59,30 @@ public class IdentifierUtil {
return objectMember.getFeatureIdentifier().getFullIdentityString();
}
- public String logicalMemberIdentifierFor(final ObjectMember objectMember) {
+ /**
+ * This assumes that the member is declared, ie is not a mixin.
+ */
+ public String logicalMemberIdentifierForDeclaredMember(final ObjectMember objectMember) {
if(objectMember instanceof ObjectAction) {
- return logicalMemberIdentifierFor((ObjectAction)objectMember);
+ return logicalMemberIdentifierForDeclaredMember((ObjectAction)objectMember);
}
if(objectMember instanceof OneToOneAssociation) {
- return logicalMemberIdentifierFor((OneToOneAssociation)objectMember);
+ return logicalMemberIdentifierForDeclaredMember((OneToOneAssociation)objectMember);
}
throw new IllegalArgumentException(objectMember.getClass() + " is not supported");
}
- public String logicalMemberIdentifierFor(final ObjectAction objectAction) {
+ /**
+ * This assumes that the member is declared, ie is not a mixin.
+ */
+ public String logicalMemberIdentifierForDeclaredMember(final ObjectAction objectAction) {
return logicalMemberIdentifierFor(objectAction.getDeclaringType(), objectAction);
}
- public String logicalMemberIdentifierFor(final OneToOneAssociation otoa) {
+ /**
+ * This assumes that the member is declared, ie is not a mixin.
+ */
+ public String logicalMemberIdentifierForDeclaredMember(final OneToOneAssociation otoa) {
return logicalMemberIdentifierFor(otoa.getDeclaringType(), otoa);
}
@@ -109,19 +120,39 @@ public class IdentifierUtil {
/**
* Whether given command corresponds to given objectMember.
* <p>
- * Is related to {@link #logicalMemberIdentifierFor(ObjectMember)}.
+ * Is related to {@link #logicalMemberIdentifierForDeclaredMember(ObjectMember)}.
*/
public boolean isCommandForMember(
final @Nullable Command command,
+ final @NonNull InteractionHead interactionHead,
final @Nullable ObjectMember objectMember) {
return command!=null
&& objectMember!=null
- && logicalMemberIdentifierFor(objectMember)
+ && logicalMemberIdentifierFor(interactionHead, objectMember)
.equals(command.getLogicalMemberIdentifier());
}
// -- HELPER
+ private String logicalMemberIdentifierFor(
+ final @NonNull InteractionHead interactionHead,
+ final ObjectMember objectMember) {
+ if (objectMember instanceof ObjectAction) {
+ ObjectAction objectAction = (ObjectAction) objectMember;
+ if (objectAction.isDeclaredOnMixin()) {
+ if (interactionHead instanceof ActionInteractionHead) {
+ ObjectAction objectActionOnMixee = ((ActionInteractionHead) interactionHead).getMetaModel();
+ ObjectSpecification specificationOfMixee = interactionHead.getOwner().getSpecification();
+ return logicalMemberIdentifierFor(specificationOfMixee, objectActionOnMixee);
+ }
+ }
+ // we fall through to the declared case, which isn't correct; but don't think it matters because
+ // effectively this would be contributed properties or collections, which don't emit commands.
+ }
+
+ return logicalMemberIdentifierForDeclaredMember(objectMember);
+ }
+
private String logicalMemberIdentifierFor(
final ObjectSpecification onType, final ObjectMember objectMember) {
final String logicalTypeName = onType.getLogicalTypeName();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/publish/command/CommandPublishingFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/publish/command/CommandPublishingFacet.java
index 4b728f5387..a51d6beac1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/publish/command/CommandPublishingFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/publish/command/CommandPublishingFacet.java
@@ -25,6 +25,7 @@ import org.apache.isis.applib.services.publishing.spi.CommandSubscriber;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facets.actions.action.invocation.IdentifierUtil;
+import org.apache.isis.core.metamodel.interactions.InteractionHead;
import org.apache.isis.core.metamodel.services.publishing.CommandPublisher;
import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
@@ -56,10 +57,11 @@ public interface CommandPublishingFacet extends Facet {
*/
public static void prepareCommandForPublishing(
final @NonNull Command command,
+ final @NonNull InteractionHead interactionHead,
final @NonNull ObjectMember objectMember,
final @NonNull FacetHolder facetHolder) {
- if(IdentifierUtil.isCommandForMember(command, objectMember)
+ if(IdentifierUtil.isCommandForMember(command, interactionHead, objectMember)
&& isPublishingEnabled(facetHolder)) {
command.updater().setPublishingPhase(CommandPublishingPhase.READY);
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index 619282844d..2ebcdd703a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -102,8 +102,6 @@ public interface ObjectAction extends ObjectMember {
/**
* Invokes the action's method on the target object given the specified set
* of parameters, checking the visibility, usability and validity first.
- *
- * @param mixedInAdapter - will be null for regular actions, and for mixin actions. When a mixin action invokes its underlying mixedIn action, then will be populated (so that the ActionDomainEvent can correctly provide the underlying mixin)
*/
ManagedObject executeWithRuleChecking(
InteractionHead head,
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectMember.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectMember.java
index 7f67e5ff62..4d839d7a5f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectMember.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectMember.java
@@ -53,6 +53,11 @@ public interface ObjectMember extends ObjectFeature {
/**
* Returns the {@link ObjectSpecification} representing the class or interface
* that declares the member represented by this object.
+ *
+ * <p>
+ * If the member is a regular member, declared on a class, then this returns that type.
+ * But if the member is a mixin, then this will return the {@link ObjectSpecification} representing the mixin type.
+ * </p>
*/
ObjectSpecification getDeclaringType();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
index 2d3ef6c6ed..a216d1e76e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -20,6 +20,7 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
import org.apache.isis.applib.Identifier;
import org.apache.isis.applib.annotation.Domain;
+import org.apache.isis.applib.annotation.DomainObject;
import org.apache.isis.applib.id.LogicalType;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.reflection._Annotations;
@@ -46,12 +47,14 @@ extends OneToManyAssociationDefault
implements MixedInMember {
/**
- * The type of the mixin (providing the action), eg annotated with {@link org.apache.isis.applib.annotation.Mixin}.
+ * The type of the mixin (providing the action), eg annotated or meta-annotated using
+ * {@link org.apache.isis.applib.annotation.DomainObject} with a {@link DomainObject#nature() nature} of
+ * {@link org.apache.isis.applib.annotation.Nature#MIXIN MIXIN}.
*/
private final Class<?> mixinType;
/**
- * The {@link ObjectActionDefault} for the action being mixed in (ie on the {@link #mixinType}.
+ * The {@link ObjectActionDefault} for the action being mixed in (ie on the {@link #mixinType}).
*/
private final ObjectActionDefault mixinAction;
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
index 87f69e045b..c7658e6ce3 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
@@ -22,6 +22,7 @@ import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
import javax.annotation.Priority;
import javax.inject.Inject;
@@ -128,7 +129,8 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
@Override
public Bookmark bookmarkForElseFail(final @Nullable Object domainObject) {
return bookmarkFor(domainObject)
- .orElseThrow(()->_Exceptions.illegalArgument(
+ .orElseThrow(
+ ()->_Exceptions.illegalArgument(
"cannot create bookmark for type %s",
domainObject!=null
? specificationLoader.specForType(domainObject.getClass())
@@ -141,6 +143,14 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
@Override
public <T> T read(final Class<T> cls, final Serializable value) {
+ if (stringifiers != null) {
+ for (Stringifier<?> serializer : stringifiers) {
+ if (serializer.handles() == cls) {
+ return (T) serializer.parse((String)value);
+ }
+ }
+ }
+
if(Bookmark.class.equals(cls)) {
return _Casts.uncheckedCast(value);
@@ -156,6 +166,14 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
@Override
public Serializable write(final Object value) {
+ if (stringifiers != null) {
+ for (Stringifier stringifier : stringifiers) {
+ if (stringifier.handles() == value.getClass()) {
+ return stringified(stringifier, value);
+ }
+ }
+ }
+
if(isPredefinedSerializable(value.getClass())) {
return (Serializable) value;
} else {
@@ -163,6 +181,10 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
}
}
+ private static <T> String stringified(Stringifier<T> stringifier, T value) {
+ return stringifier.stringify(value);
+ }
+
// -- HELPER
private static final Set<Class<? extends Serializable>> serializableFinalTypes = _Sets.of(
@@ -176,7 +198,8 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
Integer[].class, int[].class,
Long[].class, long[].class,
Float[].class, float[].class,
- Double[].class, double[].class
+ Double[].class, double[].class,
+ UUID.class
);
private static final List<Class<? extends Serializable>> serializableTypes = _Lists.of(
@@ -187,7 +210,7 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
TreeState.class
);
- private static boolean isPredefinedSerializable(final Class<?> cls) {
+ private boolean isPredefinedSerializable(final Class<?> cls) {
if(!Serializable.class.isAssignableFrom(cls)) {
return false;
}
@@ -205,8 +228,10 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
if(serializableFinalTypes.contains(cls)) {
return true;
}
- return serializableTypes.stream().anyMatch(t->t.isAssignableFrom(cls));
+ return serializableTypes.stream().anyMatch(t -> t.isAssignableFrom(cls));
}
+ @Inject List<Stringifier> stringifiers;
+
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoFactoryDefault.java
index a88cd72c00..2517013e4f 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoFactoryDefault.java
@@ -111,7 +111,7 @@ public class CommandDtoFactoryDefault implements CommandDtoFactory {
final ActionDto actionDto,
final Can<ManagedObject> argAdapters) {
- actionDto.setLogicalMemberIdentifier(IdentifierUtil.logicalMemberIdentifierFor(objectAction));
+ actionDto.setLogicalMemberIdentifier(IdentifierUtil.logicalMemberIdentifierForDeclaredMember(objectAction));
actionDto.setMemberIdentifier(IdentifierUtil.memberIdentifierFor(objectAction));
val actionParameters = objectAction.getParameters();
@@ -150,7 +150,7 @@ public class CommandDtoFactoryDefault implements CommandDtoFactory {
final PropertyDto propertyDto,
final ManagedObject valueAdapter) {
- propertyDto.setLogicalMemberIdentifier(IdentifierUtil.logicalMemberIdentifierFor(property));
+ propertyDto.setLogicalMemberIdentifier(IdentifierUtil.logicalMemberIdentifierForDeclaredMember(property));
propertyDto.setMemberIdentifier(IdentifierUtil.memberIdentifierFor(property));
valueMarshaller.recordPropertyValue(propertyDto, property, valueAdapter);
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
index 31b9d9599a..ba1d324562 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
@@ -56,6 +56,7 @@ import org.apache.isis.core.metamodel.facets.members.publish.command.CommandPubl
import org.apache.isis.core.metamodel.facets.members.publish.execution.ExecutionPublishingFacet;
import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterOrClearFacetForDomainEventAbstract.EditingVariant;
import org.apache.isis.core.metamodel.interactions.InteractionHead;
+import org.apache.isis.core.metamodel.interactions.managed.ActionInteractionHead;
import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
import org.apache.isis.core.metamodel.objectmanager.ObjectManager.EntityAdaptingMode;
import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
@@ -64,6 +65,7 @@ import org.apache.isis.core.metamodel.services.publishing.ExecutionPublisher;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ManagedObjects;
import org.apache.isis.core.metamodel.spec.ManagedObjects.UnwrapUtil;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.PackedManagedObject;
import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
@@ -128,7 +130,7 @@ implements MemberExecutorService {
val interaction = getInteractionElseFail();
val command = interaction.getCommand();
- CommandPublishingFacet.prepareCommandForPublishing(command, owningAction, facetHolder);
+ CommandPublishingFacet.prepareCommandForPublishing(command, head, owningAction, facetHolder);
val xrayHandle = _Xray.enterActionInvocation(interactionLayerTracker, interaction, owningAction, head, argumentAdapters);
@@ -204,7 +206,7 @@ implements MemberExecutorService {
return head.getTarget();
}
- CommandPublishingFacet.prepareCommandForPublishing(command, owningProperty, facetHolder);
+ CommandPublishingFacet.prepareCommandForPublishing(command, head, owningProperty, facetHolder);
val xrayHandle = _Xray.enterPropertyEdit(interactionLayerTracker, interaction, owningProperty, head, newValueAdapter);
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/types/javaawt/images/jpa/JavaAwtBufferedImageJpa.java b/examples/demo/domain/src/main/java/demoapp/dom/types/javaawt/images/jpa/JavaAwtBufferedImageJpa.java
index cb4435d27e..2fc1e3727c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/types/javaawt/images/jpa/JavaAwtBufferedImageJpa.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/types/javaawt/images/jpa/JavaAwtBufferedImageJpa.java
@@ -37,7 +37,7 @@ import org.apache.isis.applib.annotation.Optionality;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.PropertyLayout;
import org.apache.isis.persistence.jpa.applib.integration.IsisEntityListener;
-import org.apache.isis.persistence.jpa.integration.typeconverters.image.JavaAwtBufferedImageByteArrayConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.awt.JavaAwtBufferedImageByteArrayConverter;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntry.java b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntry.java
index 6060e15910..9db3798356 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntry.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntry.java
@@ -87,7 +87,7 @@ import lombok.experimental.UtilityClass;
editing = Editing.DISABLED
)
@DomainObjectLayout(
- named = "Command",
+ named = "CommandLogEntry",
titleUiEvent = CommandLogEntry.TitleUiEvent.class,
iconUiEvent = CommandLogEntry.IconUiEvent.class,
cssClassUiEvent = CommandLogEntry.CssClassUiEvent.class,
@@ -97,9 +97,9 @@ import lombok.experimental.UtilityClass;
public abstract class CommandLogEntry
implements Comparable<CommandLogEntry>, DomainChangeRecord, HasCommandDto {
- public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogApplib.NAMESPACE + ".CommandLog";
+ public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogApplib.NAMESPACE + ".CommandLogEntry";
public static final String SCHEMA = IsisModuleExtCommandLogApplib.SCHEMA;
- public static final String TABLE = "Command";
+ public static final String TABLE = "CommandLogEntry";
public static class TitleUiEvent extends IsisModuleExtCommandLogApplib.TitleUiEvent<CommandLogEntry> { }
public static class IconUiEvent extends IsisModuleExtCommandLogApplib.IconUiEvent<CommandLogEntry> { }
@@ -130,15 +130,12 @@ implements Comparable<CommandLogEntry>, DomainChangeRecord, HasCommandDto {
public static final String FIND_SINCE = LOGICAL_TYPE_NAME + ".findSince";
public static final String FIND_MOST_RECENT_REPLAYED = LOGICAL_TYPE_NAME + ".findMostRecentReplayed";
public static final String FIND_MOST_RECENT_COMPLETED = LOGICAL_TYPE_NAME + ".findMostRecentCompleted";
- public static final String FIND_NOT_YET_REPLAYED = LOGICAL_TYPE_NAME + ".findNotYetReplayed";
+ public static final String FIND_BY_REPLAY_STATE = LOGICAL_TYPE_NAME + ".findNotYetReplayed";
}
- /**
- * Intended for use on primary system.
- *
- * @param command
- */
- public CommandLogEntry(final Command command) {
+
+ @Programmatic
+ public void init(Command command) {
setInteractionId(command.getInteractionId());
setUsername(command.getUsername());
@@ -231,6 +228,7 @@ implements Comparable<CommandLogEntry>, DomainChangeRecord, HasCommandDto {
@Retention(RetentionPolicy.RUNTIME)
public @interface InteractionId {
class DomainEvent extends PropertyDomainEvent<UUID> {}
+ String NAME = "interactionId";
int MAX_LENGTH = HasInteractionId.InteractionId.MAX_LENGTH;
boolean NULLABLE = HasInteractionId.InteractionId.NULLABLE;
String ALLOWS_NULL = HasInteractionId.InteractionId.ALLOWS_NULL;
@@ -311,7 +309,7 @@ implements Comparable<CommandLogEntry>, DomainChangeRecord, HasCommandDto {
@Retention(RetentionPolicy.RUNTIME)
public @interface Parent {
class DomainEvent extends PropertyDomainEvent<CommandLogEntry> {}
- String NAME = "parentId";
+ String NAME = "parentInteractionId";
boolean NULLABLE = true;
String ALLOWS_NULL = "true";
}
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntryRepository.java b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
index 47b032b551..8fac17c4d0 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
@@ -42,6 +42,7 @@ import org.apache.isis.applib.services.command.Command;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.core.config.environment.IsisSystemEnvironment;
import org.apache.isis.schema.cmd.v2.CommandDto;
import org.apache.isis.schema.cmd.v2.CommandsDto;
import org.apache.isis.schema.cmd.v2.MapDto;
@@ -52,6 +53,7 @@ import lombok.val;
public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
+
public static class NotFoundException extends RecoverableException {
private static final long serialVersionUID = 1L;
@Getter
@@ -64,6 +66,7 @@ public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
@Inject Provider<RepositoryService> repositoryServiceProvider;
@Inject FactoryService factoryService;
+ @Inject IsisSystemEnvironment isisSystemEnvironment;
private final Class<C> commandLogEntryClass;
@@ -73,7 +76,7 @@ public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
public C createEntryAndPersist(final Command command, CommandLogEntry parentEntryIfAny) {
C c = factoryService.detachedEntity(commandLogEntryClass);
- c.setCommandDto(command.getCommandDto());
+ c.init(command);
c.setParent(parentEntryIfAny);
persist(c);
return c;
@@ -82,7 +85,14 @@ public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
public Optional<C> findByInteractionId(final UUID interactionId) {
return repositoryService().firstMatch(
Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_BY_INTERACTION_ID)
- .withParameter("interactionId", interactionId));
+ .withParameter("interactionId", convert(interactionId)));
+ }
+
+ /**
+ * optional hook
+ */
+ protected Object convert(UUID interactionId) {
+ return interactionId;
}
public List<C> findByParent(final CommandLogEntry parent) {
@@ -258,7 +268,9 @@ public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
public List<C> findNotYetReplayed() {
return repositoryService().allMatches(
- Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_NOT_YET_REPLAYED).withLimit(10));
+ Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_BY_REPLAY_STATE)
+ .withParameter("replayState", ReplayState.PENDING)
+ .withLimit(10));
}
@@ -371,6 +383,15 @@ public abstract class CommandLogEntryRepository<C extends CommandLogEntry> {
: null;
}
+ /**
+ * for testing purposes only
+ */
+ public void removeAll() {
+ if (isisSystemEnvironment.getDeploymentType().isProduction()) {
+ throw new IllegalStateException("Cannot removeAll in production systems");
+ }
+ repositoryService().removeAll(commandLogEntryClass);
+ }
}
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/subscriber/CommandSubscriberForCommandLog.java b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/subscriber/CommandSubscriberForCommandLog.java
index 3344bdc1cd..356df758ff 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/subscriber/CommandSubscriberForCommandLog.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/subscriber/CommandSubscriberForCommandLog.java
@@ -51,9 +51,10 @@ public class CommandSubscriberForCommandLog implements CommandSubscriber {
@Override
public void onCompleted(final Command command) {
- if(!command.isSystemStateChanged()) {
- return;
- }
+ // TODO: JPA does not yet support lifecycle listeners, so always would be false.
+// if(!command.isSystemStateChanged()) {
+// return;
+// }
val existingCommandJdoIfAny =
commandLogEntryRepository.findByInteractionId(command.getInteractionId());
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/CommandLogIntegTestAbstract.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/CommandLogIntegTestAbstract.java
index 9287dd3eed..e6c9195dab 100644
--- a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/CommandLogIntegTestAbstract.java
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/CommandLogIntegTestAbstract.java
@@ -18,53 +18,271 @@
*/
package org.apache.isis.extensions.commandlog.applib.integtest;
-import java.sql.Timestamp;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject;
-import org.assertj.core.api.Assertions;
-import org.eclipse.persistence.logging.SessionLogEntry;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.applib.services.session.SessionLogService;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.isis.applib.mixins.system.DomainChangeRecord;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.iactnlayer.InteractionService;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.extensions.commandlog.applib.app.CommandLogMenu;
+import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntry;
import org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntryRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.Counter;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.CounterRepository;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.Counter_bumpUsingMixin;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.Counter_bumpUsingMixinWithCommandPublishingDisabled;
+import org.apache.isis.schema.cmd.v2.ActionDto;
+import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.schema.cmd.v2.PropertyDto;
import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
+import lombok.val;
public abstract class CommandLogIntegTestAbstract extends IsisIntegrationTestAbstract {
+
+ @BeforeAll
+ static void beforeAll() {
+ IsisPresets.forcePrototyping();
+ }
+
+ Counter counter;
+
@BeforeEach
- void setUp() {
+ void beforeEach() {
+
+ counter = createE1();
+
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isEmpty();
+ }
+
+ private Counter createE1() {
+ List<Counter> before = counterRepository.find();
+ assertThat(before).isEmpty();
+
+ val e1 = counterRepository.persist(newCounter());
+
+ List<Counter> after = counterRepository.find();
+ assertThat(after).hasSize(1);
+
+ return e1;
+ }
+
+ protected abstract Counter newCounter();
+
+ @AfterEach
+ void afterEach() {
+ counterRepository.remove(counter);
+ commandLogEntryRepository.removeAll();
}
@Test
void invoke_mixin() {
- List<CommandLogEntry> notYetReplayed = commandLogEntryRepository.findNotYetReplayed();
+ // when
+ wrapperFactory.wrapMixin(Counter_bumpUsingMixin.class, counter).act();
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isPresent();
+
+ CommandLogEntry commandLogEntry = mostRecentCompleted.get();
+
+ assertThat(commandLogEntry.getInteractionId()).isNotNull();
+ assertThat(commandLogEntry.getCompletedAt()).isNotNull();
+ assertThat(commandLogEntry.getDuration()).isNotNull();
+ assertThat(commandLogEntry.getException()).isEqualTo("");
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isNotNull();
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isEqualTo("commandlog.test.Counter#bumpUsingMixin");
+ assertThat(commandLogEntry.getUsername()).isEqualTo("__system");
+ assertThat(commandLogEntry.getResult()).isNotNull();
+ assertThat(commandLogEntry.getResultSummary()).isEqualTo("OK");
+ assertThat(commandLogEntry.getReplayState()).isEqualTo(ReplayState.UNDEFINED);
+ assertThat(commandLogEntry.getReplayStateFailureReason()).isNull();
+ assertThat(commandLogEntry.getTarget()).isNotNull();
+ assertThat(commandLogEntry.getTimestamp()).isNotNull();
+ assertThat(commandLogEntry.getType()).isEqualTo(DomainChangeRecord.ChangeType.COMMAND);
+ assertThat(commandLogEntry.getCommandDto()).isNotNull();
+ CommandDto commandDto = commandLogEntry.getCommandDto();
+ assertThat(commandDto).isNotNull();
+ assertThat(commandDto.getMember()).isInstanceOf(ActionDto.class);
+ assertThat(commandDto.getMember().getLogicalMemberIdentifier()).isEqualTo(commandLogEntry.getLogicalMemberIdentifier());
+ }
+
+ @Test
+ void invoke_direct() {
+
+ // when
+ wrapperFactory.wrap(counter).bumpUsingDeclaredAction();
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isPresent();
+
+ CommandLogEntry commandLogEntry = mostRecentCompleted.get();
+
+ assertThat(commandLogEntry.getInteractionId()).isNotNull();
+ assertThat(commandLogEntry.getCompletedAt()).isNotNull();
+ assertThat(commandLogEntry.getDuration()).isNotNull();
+ assertThat(commandLogEntry.getException()).isEqualTo("");
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isNotNull();
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isEqualTo("commandlog.test.Counter#bumpUsingDeclaredAction");
+ assertThat(commandLogEntry.getUsername()).isEqualTo("__system");
+ assertThat(commandLogEntry.getResult()).isNotNull();
+ assertThat(commandLogEntry.getResultSummary()).isEqualTo("OK");
+ assertThat(commandLogEntry.getReplayState()).isEqualTo(ReplayState.UNDEFINED);
+ assertThat(commandLogEntry.getReplayStateFailureReason()).isNull();
+ assertThat(commandLogEntry.getTarget()).isNotNull();
+ assertThat(commandLogEntry.getTimestamp()).isNotNull();
+ assertThat(commandLogEntry.getType()).isEqualTo(DomainChangeRecord.ChangeType.COMMAND);
+ assertThat(commandLogEntry.getCommandDto()).isNotNull();
+ CommandDto commandDto = commandLogEntry.getCommandDto();
+ assertThat(commandDto).isNotNull();
+ assertThat(commandDto.getMember()).isInstanceOf(ActionDto.class);
+ assertThat(commandDto.getMember().getLogicalMemberIdentifier()).isEqualTo(commandLogEntry.getLogicalMemberIdentifier());
+ }
+
+ @Test
+ void invoke_mixin_disabled() {
+
+ // when
+ wrapperFactory.wrapMixin(Counter_bumpUsingMixinWithCommandPublishingDisabled.class, counter).act();
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isEmpty();
+ }
+
+ @Test
+ void invoke_direct_disabled() {
+
+ // when
+ wrapperFactory.wrap(counter).bumpUsingDeclaredActionWithCommandPublishingDisabled();
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isEmpty();
+ }
+
+
+
+ @Test
+ void edit() {
+
+ // when
+ wrapperFactory.wrap(counter).setNum(99L);
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isPresent();
+
+ CommandLogEntry commandLogEntry = mostRecentCompleted.get();
+
+ assertThat(commandLogEntry.getInteractionId()).isNotNull();
+ assertThat(commandLogEntry.getCompletedAt()).isNotNull();
+ assertThat(commandLogEntry.getDuration()).isNotNull();
+ assertThat(commandLogEntry.getException()).isEqualTo("");
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isNotNull();
+ assertThat(commandLogEntry.getLogicalMemberIdentifier()).isEqualTo("commandlog.test.Counter#num");
+ assertThat(commandLogEntry.getUsername()).isEqualTo("__system");
+ assertThat(commandLogEntry.getResult()).isNull();
+ assertThat(commandLogEntry.getResultSummary()).isEqualTo("OK (VOID)");
+ assertThat(commandLogEntry.getReplayState()).isEqualTo(ReplayState.UNDEFINED);
+ assertThat(commandLogEntry.getReplayStateFailureReason()).isNull();
+ assertThat(commandLogEntry.getTarget()).isNotNull();
+ assertThat(commandLogEntry.getTimestamp()).isNotNull();
+ assertThat(commandLogEntry.getType()).isEqualTo(DomainChangeRecord.ChangeType.COMMAND);
+ CommandDto commandDto = commandLogEntry.getCommandDto();
+ assertThat(commandDto).isNotNull();
+ assertThat(commandDto.getMember()).isInstanceOf(PropertyDto.class);
+ }
+
+ @Test
+ void edit_disabled() {
+
+ // when
+ wrapperFactory.wrap(counter).setNum2(99L);
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+
+ // then
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+ assertThat(mostRecentCompleted).isEmpty();
+ }
+
+
+ @Test
+ void roundtrip_CLE_bookmarks() {
+
+ // given
+ wrapperFactory.wrapMixin(Counter_bumpUsingMixin.class, counter).act();
+ interactionService.closeInteractionLayers(); // to flush
+
+ interactionService.openInteraction();
+ Optional<? extends CommandLogEntry> mostRecentCompleted = commandLogEntryRepository.findMostRecentCompleted();
+
+ CommandLogEntry commandLogEntry = mostRecentCompleted.get();
+ CommandDto commandDto = commandLogEntry.getCommandDto();
+
+ // when
+ Optional<Bookmark> cleBookmarkIfAny = bookmarkService.bookmarkFor(commandLogEntry);
+
+ // then
+ assertThat(cleBookmarkIfAny).isPresent();
+ Bookmark cleBookmark = cleBookmarkIfAny.get();
+ UUID.fromString(cleBookmark.getIdentifier()); // should not fail, ie check the format is as we expect
+
+ // when we start a new session and lookup from the bookmark
+ interactionService.closeInteractionLayers();
+ interactionService.openInteraction();
+
+ Optional<Object> cle2IfAny = bookmarkService.lookup(cleBookmarkIfAny.get());
+ assertThat(cle2IfAny).isPresent();
+
+ CommandLogEntry cle2 = (CommandLogEntry) cle2IfAny.get();
+ CommandDto commandDto2 = cle2.getCommandDto();
- wrapperFactory.wrapMixin(CommandLogMenu.truncateLog.class, commandLogMenu).act();
+ assertThat(commandDto2).isEqualTo(commandDto);
- List<CommandLogEntry> notYetReplayedAfter = commandLogEntryRepository.findNotYetReplayed();
}
- @Inject CommandLogMenu commandLogMenu;
- @Inject CommandLogEntryRepository<CommandLogEntry> commandLogEntryRepository;
+ @Inject CommandLogEntryRepository<? extends CommandLogEntry> commandLogEntryRepository;
+ @Inject InteractionService interactionService;
+ @Inject CounterRepository counterRepository;
@Inject WrapperFactory wrapperFactory;
+ @Inject BookmarkService bookmarkService;
+ @Inject MetaModelService metaModelService;
}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CommandLogTestDomainModel.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CommandLogTestDomainModel.java
new file mode 100644
index 0000000000..a1fae7ec42
--- /dev/null
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CommandLogTestDomainModel.java
@@ -0,0 +1,4 @@
+package org.apache.isis.extensions.commandlog.applib.integtest.model;
+
+public class CommandLogTestDomainModel {
+}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter.java
new file mode 100644
index 0000000000..71d445c456
--- /dev/null
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter.java
@@ -0,0 +1,53 @@
+package org.apache.isis.extensions.commandlog.applib.integtest.model;
+
+import javax.inject.Named;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.Publishing;
+
+@Named("commandlog.test.Counter")
+@DomainObject(nature = Nature.ENTITY)
+public abstract class Counter implements Comparable<Counter> {
+
+ public abstract Long getId();
+ public abstract void setId(Long id);
+
+ @Property(editing = Editing.ENABLED, commandPublishing = Publishing.ENABLED)
+ public abstract Long getNum();
+ public abstract void setNum(Long num);
+
+ @Property(editing = Editing.ENABLED, commandPublishing = Publishing.DISABLED)
+ public abstract Long getNum2();
+ public abstract void setNum2(Long num2);
+
+ public abstract String getName();
+ public abstract void setName(String name);
+
+ @Action(commandPublishing = Publishing.ENABLED)
+ public Counter bumpUsingDeclaredAction() {
+ return doBump();
+ }
+
+ @Action(commandPublishing = Publishing.DISABLED)
+ public Counter bumpUsingDeclaredActionWithCommandPublishingDisabled() {
+ return doBump();
+ }
+
+ Counter doBump() {
+ if (getNum() == null) {
+ setNum(1L);
+ } else {
+ setNum(getNum() + 1);
+ }
+ return this;
+ }
+
+ @Override
+ public int compareTo(final Counter o) {
+ return this.getName().compareTo(o.getName());
+ }
+}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CounterRepository.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CounterRepository.java
new file mode 100644
index 0000000000..08bb352664
--- /dev/null
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/CounterRepository.java
@@ -0,0 +1,15 @@
+package org.apache.isis.extensions.commandlog.applib.integtest.model;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CounterRepository<X extends Counter> {
+
+ List<X> find();
+
+ X persist(X e1);
+
+ void remove(X e1);
+}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixin.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixin.java
new file mode 100644
index 0000000000..c07848137f
--- /dev/null
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixin.java
@@ -0,0 +1,17 @@
+package org.apache.isis.extensions.commandlog.applib.integtest.model;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.Publishing;
+
+import lombok.RequiredArgsConstructor;
+
+@Action(commandPublishing = Publishing.ENABLED)
+@RequiredArgsConstructor
+public class Counter_bumpUsingMixin {
+
+ private final Counter counter;
+
+ public Counter act() {
+ return counter.doBump();
+ }
+}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixinWithCommandPublishingDisabled.java b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixinWithCommandPublishingDisabled.java
new file mode 100644
index 0000000000..d6e16d093d
--- /dev/null
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/integtest/model/Counter_bumpUsingMixinWithCommandPublishingDisabled.java
@@ -0,0 +1,17 @@
+package org.apache.isis.extensions.commandlog.applib.integtest.model;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.Publishing;
+
+import lombok.RequiredArgsConstructor;
+
+@Action(commandPublishing = Publishing.DISABLED)
+@RequiredArgsConstructor
+public class Counter_bumpUsingMixinWithCommandPublishingDisabled {
+
+ private final Counter counter;
+
+ public Counter act() {
+ return counter.doBump();
+ }
+}
diff --git a/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogPersistenceJdo.java b/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogPersistenceJdo.java
index fd8d6eb703..933d95be0c 100644
--- a/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogPersistenceJdo.java
+++ b/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogPersistenceJdo.java
@@ -24,6 +24,7 @@ import org.springframework.context.annotation.Import;
import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
import org.apache.isis.extensions.commandlog.jdo.dom.CommandLogEntry;
import org.apache.isis.extensions.commandlog.jdo.dom.CommandLogEntryRepository;
+import org.apache.isis.persistence.jdo.datanucleus.IsisModulePersistenceJdoDatanucleus;
import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
import org.apache.isis.testing.fixtures.applib.teardown.jdo.TeardownFixtureJdoAbstract;
@@ -33,7 +34,9 @@ import org.apache.isis.testing.fixtures.applib.teardown.jdo.TeardownFixtureJdoAb
@Configuration
@Import({
// modules
+ // IsisModuleTestingFixturesApplib.class,
IsisModuleExtCommandLogApplib.class,
+ IsisModulePersistenceJdoDatanucleus.class,
// @Service's
CommandLogEntryRepository.class,
diff --git a/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/dom/CommandLogEntry.java b/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/dom/CommandLogEntry.java
index 52b444fbb7..156ad180d7 100644
--- a/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/dom/CommandLogEntry.java
+++ b/extensions/core/commandlog/persistence-jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/dom/CommandLogEntry.java
@@ -188,10 +188,10 @@ import lombok.Setter;
// which SQL Server doesn't understand. However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
@Query(
- name = Nq.FIND_NOT_YET_REPLAYED,
+ name = Nq.FIND_BY_REPLAY_STATE,
value = "SELECT "
+ " FROM " + CommandLogEntry.FQCN + " "
- + " WHERE replayState == 'PENDING' "
+ + " WHERE replayState == :replayState "
+ " ORDER BY this.timestamp ASC "
+ " RANGE 0,10"), // same as batch size
})
@@ -206,14 +206,6 @@ extends org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntry {
protected final static String FQCN = "org.apache.isis.extensions.commandlog.jdo.entities.CommandJdo";
- /**
- * Intended for use on primary system.
- *
- * @param command - framework's representation of the action invocation or property edit to be performed
- */
- public CommandLogEntry(final Command command) {
- super(command);
- }
/**
* Intended for use on secondary (replay) system.
diff --git a/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/CommandLog_IntegTest.java b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/CommandLog_IntegTest.java
index b69c6aad4d..6f3c43df5e 100644
--- a/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/CommandLog_IntegTest.java
+++ b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/CommandLog_IntegTest.java
@@ -21,6 +21,7 @@ package org.apache.isis.extensions.commandlog.jdo;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
@@ -29,6 +30,9 @@ import org.springframework.test.context.ActiveProfiles;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
import org.apache.isis.extensions.commandlog.applib.integtest.CommandLogIntegTestAbstract;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.CommandLogTestDomainModel;
+import org.apache.isis.extensions.commandlog.jdo.model.Counter;
+import org.apache.isis.extensions.commandlog.jdo.model.CounterRepository;
import org.apache.isis.security.bypass.IsisModuleSecurityBypass;
@SpringBootTest(
@@ -46,10 +50,15 @@ public class CommandLog_IntegTest extends CommandLogIntegTestAbstract {
IsisModuleExtCommandLogPersistenceJdo.class,
})
@PropertySources({
- @PropertySource(IsisPresets.UseLog4j2Test),
+ @PropertySource(IsisPresets.UseLog4j2Test)
})
+ @ComponentScan(basePackageClasses = {AppManifest.class, CommandLogTestDomainModel.class, CounterRepository.class})
public static class AppManifest {
}
+ protected org.apache.isis.extensions.commandlog.applib.integtest.model.Counter newCounter() {
+ return Counter.builder().name("Fred").build();
+ }
+
}
diff --git a/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/Counter.java b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/Counter.java
new file mode 100644
index 0000000000..6c503c1344
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/Counter.java
@@ -0,0 +1,52 @@
+package org.apache.isis.extensions.commandlog.jdo.model;
+
+import javax.inject.Named;
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.DatastoreIdentity;
+import javax.jdo.annotations.IdGeneratorStrategy;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.PrimaryKey;
+
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.Publishing;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@PersistenceCapable(
+ schema = "public",
+ table = "Counter"
+)
+@DatastoreIdentity(strategy = IdGeneratorStrategy.IDENTITY)
+@Named("commandlog.test.Counter")
+@DomainObject(nature = Nature.ENTITY)
+@NoArgsConstructor
+@Builder
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class Counter extends org.apache.isis.extensions.commandlog.applib.integtest.model.Counter {
+
+ @PrimaryKey
+ @Getter @Setter
+ private Long id;
+
+ @Column(allowsNull = "false")
+ @Getter @Setter
+ private String name;
+
+ @Column(allowsNull = "true")
+ @Getter @Setter
+ private Long num;
+
+ @Column(allowsNull = "true")
+ @Getter @Setter
+ private Long num2;
+
+
+}
diff --git a/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/CounterRepository.java b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/CounterRepository.java
new file mode 100644
index 0000000000..5ceb2d7bd4
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jdo/src/test/java/org/apache/isis/extensions/commandlog/jdo/model/CounterRepository.java
@@ -0,0 +1,36 @@
+package org.apache.isis.extensions.commandlog.jdo.model;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Repository;
+
+import org.apache.isis.applib.services.repository.RepositoryService;
+
+@Repository
+public class CounterRepository
+ implements org.apache.isis.extensions.commandlog.applib.integtest.model.CounterRepository<Counter> {
+
+ final RepositoryService repositoryService;
+
+ @Inject
+ public CounterRepository( RepositoryService repositoryService) {
+ this.repositoryService = repositoryService;
+ }
+
+ @Override
+ public List<Counter> find() {
+ return repositoryService.allInstances(Counter.class);
+ }
+
+ @Override
+ public Counter persist(Counter counter) {
+ return repositoryService.persist(counter);
+ }
+
+ @Override
+ public void remove(Counter counter) {
+ repositoryService.remove(counter);
+ }
+}
diff --git a/extensions/core/commandlog/persistence-jdo/src/test/resources/application-test.yml b/extensions/core/commandlog/persistence-jdo/src/test/resources/application-test.yml
new file mode 100644
index 0000000000..4edf0c2667
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jdo/src/test/resources/application-test.yml
@@ -0,0 +1,29 @@
+# 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.
+isis:
+ persistence:
+ schema:
+ auto-create-schemas: "ISISEXTCOMMANDLOG"
+
+ extensions:
+ session-log:
+ auto-logout-on-restart: false
+
+spring:
+ jpa:
+ show-sql: true
+
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/IsisModuleExtCommandLogPersistenceJpa.java b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/IsisModuleExtCommandLogPersistenceJpa.java
index 9260c5707c..25c8697d0b 100644
--- a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/IsisModuleExtCommandLogPersistenceJpa.java
+++ b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/IsisModuleExtCommandLogPersistenceJpa.java
@@ -24,7 +24,9 @@ import org.springframework.context.annotation.Import;
import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
import org.apache.isis.extensions.commandlog.jpa.dom.CommandLogEntry;
+import org.apache.isis.extensions.commandlog.jpa.dom.CommandLogEntryPK;
import org.apache.isis.extensions.commandlog.jpa.dom.CommandLogEntryRepository;
+import org.apache.isis.persistence.jpa.eclipselink.IsisModulePersistenceJpaEclipselink;
/**
* @since 2.0 {@index}
@@ -32,16 +34,19 @@ import org.apache.isis.extensions.commandlog.jpa.dom.CommandLogEntryRepository;
@Configuration
@Import({
// modules
+ // IsisModuleTestingFixturesApplib.class,
IsisModuleExtCommandLogApplib.class,
+ IsisModulePersistenceJpaEclipselink.class,
// @Service's
CommandLogEntryRepository.class,
+ CommandLogEntryPK.Stringifier.class,
// entities
CommandLogEntry.class
})
@EntityScan(basePackageClasses = {
- CommandLogEntry.class,
+ CommandLogEntry.class
})
public class IsisModuleExtCommandLogPersistenceJpa {
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntry.java b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntry.java
index 6e7008224f..309efc5354 100644
--- a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntry.java
+++ b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntry.java
@@ -24,19 +24,23 @@ import javax.inject.Named;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Convert;
+import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
+import javax.persistence.IdClass;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
+import javax.persistence.Transient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.isis.applib.annotation.DomainObject;
@@ -46,6 +50,7 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.applib.services.command.Command;
import org.apache.isis.persistence.jpa.applib.integration.IsisEntityListener;
import org.apache.isis.persistence.jpa.integration.typeconverters.applib.IsisBookmarkConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.util.JavaUtilUuidConverter;
import org.apache.isis.persistence.jpa.integration.typeconverters.schema.v2.IsisCommandDtoConverter;
import org.apache.isis.schema.cmd.v2.CommandDto;
@@ -183,10 +188,10 @@ import lombok.Setter;
+ " AND cl.completedAt is not null "
+ " ORDER BY cl.timestamp DESC"), // programmatic LIMIT 1
@NamedQuery(
- name = Nq.FIND_NOT_YET_REPLAYED,
+ name = Nq.FIND_BY_REPLAY_STATE,
query = "SELECT cl "
+ " FROM CommandLogEntry cl "
- + " WHERE cl.replayState = 'PENDING' "
+ + " WHERE cl.replayState = :replayState "
+ " ORDER BY cl.timestamp ASC"), // programmatic LIMIT 10
})
@Named(CommandLogEntry.LOGICAL_TYPE_NAME)
@@ -198,15 +203,6 @@ import lombok.Setter;
@NoArgsConstructor
public class CommandLogEntry extends org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntry {
- /**
- * Intended for use on primary system.
- *
- * @param command - representation of the action invocation or property edit to be performed
- */
- public CommandLogEntry(final Command command) {
- super(command);
- }
-
/**
* Intended for use on secondary (replay) system.
*
@@ -221,11 +217,18 @@ public class CommandLogEntry extends org.apache.isis.extensions.commandlog.appli
super(commandDto, replayState, targetIndex);
}
- @Id
- @Column(nullable = InteractionId.NULLABLE, length = InteractionId.MAX_LENGTH)
+ @Transient
@InteractionId
- @Getter @Setter
- private UUID interactionId;
+ public UUID getInteractionId() {
+ return interactionId != null ? interactionId.getInteractionId() : null;
+ }
+ @Transient
+ public void setInteractionId(UUID interactionId) {
+ this.interactionId = new CommandLogEntryPK(interactionId);
+ }
+
+ @EmbeddedId
+ private CommandLogEntryPK interactionId;
@Column(nullable = Username.NULLABLE, length = Username.MAX_LENGTH)
@@ -248,7 +251,9 @@ public class CommandLogEntry extends org.apache.isis.extensions.commandlog.appli
@ManyToOne
- @JoinColumn(name = Parent.NAME, nullable = Parent.NULLABLE)
+ @JoinColumns({
+ @JoinColumn(name = Parent.NAME, nullable = Parent.NULLABLE, referencedColumnName = InteractionId.NAME)
+ })
@Parent
@Getter
private CommandLogEntry parent;
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryPK.java b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryPK.java
new file mode 100644
index 0000000000..79c81a1bf6
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryPK.java
@@ -0,0 +1,58 @@
+package org.apache.isis.extensions.commandlog.jpa.dom;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Embeddable;
+
+import org.springframework.stereotype.Component;
+
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntry;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.util.JavaUtilUuidConverter;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@EqualsAndHashCode(of = {"interactionId"})
+@NoArgsConstructor
+@AllArgsConstructor
+@Embeddable
+public class CommandLogEntryPK implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Convert(converter = JavaUtilUuidConverter.class)
+ @Column(name = CommandLogEntry.InteractionId.NAME, nullable = CommandLogEntry.InteractionId.NULLABLE, length = CommandLogEntry.InteractionId.MAX_LENGTH)
+ @Getter(AccessLevel.PACKAGE)
+ private UUID interactionId;
+
+ @Override
+ public String toString() {
+ return interactionId != null ? interactionId.toString() : null;
+ }
+
+
+ @Component
+ public static class Stringifier implements BookmarkService.Stringifier {
+ @Override
+ public Class<?> handles() {
+ return CommandLogEntryPK.class;
+ }
+
+ @Override
+ public String stringify(Object value) {
+ return ((CommandLogEntryPK)value).getInteractionId().toString();
+ }
+
+ @Override
+ public Object parse(String stringified) {
+ return new CommandLogEntryPK(UUID.fromString(stringified));
+ }
+ }
+}
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryRepository.java b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryRepository.java
index 409b1c50b1..a6c8282794 100644
--- a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryRepository.java
+++ b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/dom/CommandLogEntryRepository.java
@@ -18,6 +18,9 @@
*/
package org.apache.isis.extensions.commandlog.jpa.dom;
+import java.util.Optional;
+import java.util.UUID;
+
import javax.inject.Named;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -25,6 +28,7 @@ import org.springframework.stereotype.Service;
import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.extensions.commandlog.jpa.IsisModuleExtCommandLogPersistenceJpa;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.util.JavaUtilUuidConverter;
/**
* Provides supporting functionality for querying and persisting
@@ -43,5 +47,8 @@ extends org.apache.isis.extensions.commandlog.applib.dom.CommandLogEntryReposito
super(CommandLogEntry.class);
}
-
+ @Override
+ protected Object convert(UUID interactionId) {
+ return new CommandLogEntryPK(interactionId);
+ }
}
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/resources/META-INF/orm-commandlog.template b/extensions/core/commandlog/persistence-jpa/src/main/resources/META-INF/orm-commandlog.template
index d2c2c83c31..b02b2c6d8e 100644
--- a/extensions/core/commandlog/persistence-jpa/src/main/resources/META-INF/orm-commandlog.template
+++ b/extensions/core/commandlog/persistence-jpa/src/main/resources/META-INF/orm-commandlog.template
@@ -25,8 +25,8 @@
<!-- rename file to .xml then customize-->
- <entity class="org.apache.isis.extensions.commandlog.jpa.entities.CommandJpa">
- <table schema="isisExtensionsCommandLog" name="Command"/>
+ <entity class="org.apache.isis.extensions.commandlog.jpa.dom.CommandLogEntry">
+ <table schema="isisExtCommandLog" name="Command"/>
</entity>
-</entity-mappings>
\ No newline at end of file
+</entity-mappings>
diff --git a/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/CommandLog_IntegTest.java b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/CommandLog_IntegTest.java
index a96e609809..977e14212b 100644
--- a/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/CommandLog_IntegTest.java
+++ b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/CommandLog_IntegTest.java
@@ -20,7 +20,9 @@ package org.apache.isis.extensions.commandlog.jpa;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
@@ -29,6 +31,8 @@ import org.springframework.test.context.ActiveProfiles;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
import org.apache.isis.extensions.commandlog.applib.integtest.CommandLogIntegTestAbstract;
+import org.apache.isis.extensions.commandlog.applib.integtest.model.CommandLogTestDomainModel;
+import org.apache.isis.extensions.commandlog.jpa.model.Counter;
import org.apache.isis.security.bypass.IsisModuleSecurityBypass;
@SpringBootTest(
@@ -46,10 +50,16 @@ public class CommandLog_IntegTest extends CommandLogIntegTestAbstract {
IsisModuleExtCommandLogPersistenceJpa.class,
})
@PropertySources({
- @PropertySource(IsisPresets.UseLog4j2Test),
+ @PropertySource(IsisPresets.UseLog4j2Test)
})
+ @EntityScan(basePackageClasses = {Counter.class})
+ @ComponentScan(basePackageClasses = {AppManifest.class, CommandLogTestDomainModel.class})
public static class AppManifest {
}
+ protected org.apache.isis.extensions.commandlog.applib.integtest.model.Counter newCounter() {
+ return Counter.builder().name("Fred").build();
+ }
+
}
diff --git a/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/Counter.java b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/Counter.java
new file mode 100644
index 0000000000..6546e7e7b4
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/Counter.java
@@ -0,0 +1,55 @@
+package org.apache.isis.extensions.commandlog.jpa.model;
+
+import javax.inject.Named;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.Publishing;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(
+ schema = "public",
+ name = "Counter"
+)
+@Named("commandlog.test.Counter")
+@DomainObject(nature = Nature.ENTITY)
+@NoArgsConstructor
+@Builder
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class Counter extends org.apache.isis.extensions.commandlog.applib.integtest.model.Counter {
+
+ @Id
+ @GeneratedValue
+ @Getter @Setter
+ private Long id;
+
+ @Column(nullable = false)
+ @Getter @Setter
+ private String name;
+
+ @Column(nullable = true)
+ @Property(editing = Editing.ENABLED, commandPublishing = Publishing.ENABLED)
+ @Getter @Setter
+ private Long num;
+
+ @Column(nullable = true)
+ @Property(editing = Editing.ENABLED, commandPublishing = Publishing.DISABLED)
+ @Getter @Setter
+ private Long num2;
+
+
+}
diff --git a/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/CounterRepository.java b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/CounterRepository.java
new file mode 100644
index 0000000000..d01c157290
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jpa/src/test/java/org/apache/isis/extensions/commandlog/jpa/model/CounterRepository.java
@@ -0,0 +1,27 @@
+package org.apache.isis.extensions.commandlog.jpa.model;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CounterRepository
+ extends JpaRepository<Counter, Integer>,
+ org.apache.isis.extensions.commandlog.applib.integtest.model.CounterRepository<Counter> {
+
+ @Override
+ default List<Counter> find() {
+ return findAll();
+ }
+
+ @Override
+ default Counter persist(Counter counter) {
+ return save(counter);
+ }
+
+ @Override
+ default void remove(Counter counter) {
+ delete(counter);
+ }
+}
diff --git a/extensions/core/commandlog/persistence-jpa/src/test/resources/META-INF/persistence.xml b/extensions/core/commandlog/persistence-jpa/src/test/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..a7f0675630
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jpa/src/test/resources/META-INF/persistence.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence
+ version="2.1"
+ xmlns="http://xmlns.jcp.org/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
+
+ <persistence-unit name="command-log-jpa"/>
+
+</persistence>
diff --git a/extensions/core/commandlog/persistence-jpa/src/test/resources/application-test.yml b/extensions/core/commandlog/persistence-jpa/src/test/resources/application-test.yml
new file mode 100644
index 0000000000..4edf0c2667
--- /dev/null
+++ b/extensions/core/commandlog/persistence-jpa/src/test/resources/application-test.yml
@@ -0,0 +1,29 @@
+# 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.
+isis:
+ persistence:
+ schema:
+ auto-create-schemas: "ISISEXTCOMMANDLOG"
+
+ extensions:
+ session-log:
+ auto-logout-on-restart: false
+
+spring:
+ jpa:
+ show-sql: true
+
diff --git a/extensions/core/commandlog/pom.xml b/extensions/core/commandlog/pom.xml
index aa42900d28..14de923c6c 100644
--- a/extensions/core/commandlog/pom.xml
+++ b/extensions/core/commandlog/pom.xml
@@ -31,25 +31,17 @@
<dependencies>
<dependency>
<groupId>org.apache.isis.extensions</groupId>
- <artifactId>isis-extensions-commandlog-applib</artifactId>
+ <artifactId>isis-extensions</artifactId>
<version>2.0.0-SNAPSHOT</version>
+ <scope>import</scope>
+ <type>pom</type>
</dependency>
<dependency>
- <groupId>org.apache.isis.extensions</groupId>
- <artifactId>isis-extensions-commandlog-applib</artifactId>
- <version>2.0.0-SNAPSHOT</version>
- <scope>test</scope>
- <type>test-jar</type>
- </dependency>
- <dependency>
- <groupId>org.apache.isis.extensions</groupId>
- <artifactId>isis-extensions-commandlog-persistence-jdo</artifactId>
- <version>2.0.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.apache.isis.extensions</groupId>
- <artifactId>isis-extensions-commandlog-persistence-jpa</artifactId>
+ <groupId>org.apache.isis.testing</groupId>
+ <artifactId>isis-testing</artifactId>
<version>2.0.0-SNAPSHOT</version>
+ <scope>import</scope>
+ <type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 613665b665..42ae48780c 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -76,6 +76,13 @@
<artifactId>isis-extensions-commandlog-applib</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.isis.extensions</groupId>
+ <artifactId>isis-extensions-commandlog-applib</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>org.apache.isis.extensions</groupId>
<artifactId>isis-extensions-commandlog-persistence-jdo</artifactId>
@@ -127,6 +134,13 @@
<artifactId>isis-extensions-executionlog-applib</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.isis.extensions</groupId>
+ <artifactId>isis-extensions-executionlog-applib</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>org.apache.isis.extensions</groupId>
<artifactId>isis-extensions-executionlog-persistence-jdo</artifactId>
diff --git a/extensions/security/sessionlog/applib/src/test/java/org/apache/isis/sessionlog/applib/SessionLogIntegTestAbstract.java b/extensions/security/sessionlog/applib/src/test/java/org/apache/isis/sessionlog/applib/SessionLogIntegTestAbstract.java
index ad8ae82a30..b282f82efb 100644
--- a/extensions/security/sessionlog/applib/src/test/java/org/apache/isis/sessionlog/applib/SessionLogIntegTestAbstract.java
+++ b/extensions/security/sessionlog/applib/src/test/java/org/apache/isis/sessionlog/applib/SessionLogIntegTestAbstract.java
@@ -66,7 +66,7 @@ public abstract class SessionLogIntegTestAbstract extends IsisIntegrationTestAbs
List<? extends SessionLogEntry> sessions;
SessionLogEntry session;
- Optional<SessionLogEntry> sessionIfAny;
+ Optional<? extends SessionLogEntry> sessionIfAny;
// given
sessions = sessionLogEntryRepository.findActiveSessions();
@@ -138,6 +138,6 @@ public abstract class SessionLogIntegTestAbstract extends IsisIntegrationTestAbs
}
@Inject @Qualifier("default") SessionLogService sessionLogService;
- @Inject SessionLogEntryRepository sessionLogEntryRepository;
+ @Inject SessionLogEntryRepository<? extends SessionLogEntry> sessionLogEntryRepository;
}
diff --git a/incubator/viewers/graphql/viewer/src/test/java/org/apache/isis/viewer/graphql/viewer/source/gqltestdomain/E1.java b/incubator/viewers/graphql/viewer/src/test/java/org/apache/isis/viewer/graphql/viewer/source/gqltestdomain/E1.java
index e532b2c30a..8f1ba43c33 100644
--- a/incubator/viewers/graphql/viewer/src/test/java/org/apache/isis/viewer/graphql/viewer/source/gqltestdomain/E1.java
+++ b/incubator/viewers/graphql/viewer/src/test/java/org/apache/isis/viewer/graphql/viewer/source/gqltestdomain/E1.java
@@ -33,6 +33,8 @@ import org.apache.isis.applib.annotation.Property;
import lombok.Getter;
import lombok.Setter;
+import graphql.com.google.common.collect.ComparisonChain;
+
//@Profile("demo-jpa")
@Entity
@Table(
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java
index 101b26ddde..db9a940171 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java
@@ -217,7 +217,7 @@ implements
}
private void enableCommandPublishing() {
- val alreadySet = persitentChangesEncountered.getAndSet(true);
+ val alreadySet = persistentChangesEncountered.getAndSet(true);
if(!alreadySet) {
val command = currentInteraction().getCommand();
command.updater().setSystemStateChanged(true);
@@ -410,6 +410,6 @@ implements
private final LongAdder numberEntitiesLoaded = new LongAdder();
private final LongAdder entityChangeEventCount = new LongAdder();
- private final AtomicBoolean persitentChangesEncountered = new AtomicBoolean();
+ private final AtomicBoolean persistentChangesEncountered = new AtomicBoolean();
}
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/IsisModulePersistenceJpaIntegration.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/IsisModulePersistenceJpaIntegration.java
index 2aa325d788..bf5e38c657 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/IsisModulePersistenceJpaIntegration.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/IsisModulePersistenceJpaIntegration.java
@@ -26,7 +26,18 @@ import org.apache.isis.core.runtime.IsisModuleCoreRuntime;
import org.apache.isis.persistence.jpa.integration.changetracking.PersistenceMetricsServiceJpa;
import org.apache.isis.persistence.jpa.integration.entity.JpaEntityIntegration;
import org.apache.isis.persistence.jpa.integration.services.JpaSupportServiceUsingSpring;
-import org.apache.isis.persistence.jpa.integration.typeconverters.image.JavaAwtBufferedImageByteArrayConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.applib.IsisBookmarkConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.applib.IsisLocalResourcePathConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.applib.IsisMarkupConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.applib.IsisPasswordConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.awt.JavaAwtBufferedImageByteArrayConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.util.JavaUtilUuidConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.schema.v2.IsisChangesDtoConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.schema.v2.IsisCommandDtoConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.schema.v2.IsisInteractionDtoConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.schema.v2.IsisOidDtoConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.time.JavaTimeIsoOffsetTimeConverter;
+import org.apache.isis.persistence.jpa.integration.typeconverters.java.time.JavaTimeIsoZonedDateTimeConverter;
import org.apache.isis.persistence.jpa.metamodel.IsisModulePersistenceJpaMetamodel;
@Configuration
@@ -46,7 +57,19 @@ import org.apache.isis.persistence.jpa.metamodel.IsisModulePersistenceJpaMetamod
@EntityScan(basePackageClasses = {
// @Converter's
- JavaAwtBufferedImageByteArrayConverter.class
+ IsisBookmarkConverter.class,
+ IsisLocalResourcePathConverter.class,
+ IsisMarkupConverter.class,
+ IsisPasswordConverter.class,
+ IsisChangesDtoConverter.class,
+ IsisCommandDtoConverter.class,
+ IsisInteractionDtoConverter.class,
+ IsisOidDtoConverter.class,
+ JavaAwtBufferedImageByteArrayConverter.class,
+ JavaUtilUuidConverter.class,
+ JavaTimeIsoOffsetTimeConverter.class,
+ JavaTimeIsoZonedDateTimeConverter.class
+
})
public class IsisModulePersistenceJpaIntegration {
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacetFactory.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacetFactory.java
index 35b5dace81..137c3105a6 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacetFactory.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacetFactory.java
@@ -24,9 +24,11 @@ import java.util.Optional;
import javax.inject.Inject;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
+import javax.persistence.PersistenceException;
import javax.persistence.PersistenceUnitUtil;
import javax.persistence.metamodel.EntityType;
+import org.eclipse.persistence.exceptions.DescriptorException;
import org.springframework.data.jpa.repository.JpaContext;
import org.apache.isis.applib.exceptions.unrecoverable.ObjectNotFoundException;
@@ -34,6 +36,7 @@ import org.apache.isis.applib.query.AllInstancesQuery;
import org.apache.isis.applib.query.NamedQuery;
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
import org.apache.isis.applib.services.registry.ServiceRegistry;
import org.apache.isis.applib.services.repository.EntityState;
import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
@@ -299,9 +302,22 @@ extends FacetFactoryAbstract {
return EntityState.PERSISTABLE_ATTACHED;
}
- val primaryKey = getPersistenceUnitUtil(entityManager).getIdentifier(pojo);
- if(primaryKey == null) {
- return EntityState.PERSISTABLE_DETACHED; // an optimization, not strictly required
+ try {
+ val primaryKey = getPersistenceUnitUtil(entityManager).getIdentifier(pojo);
+ if(primaryKey == null) {
+ return EntityState.PERSISTABLE_DETACHED; // an optimization, not strictly required
+ }
+ } catch(PersistenceException ex) {
+ // horrible hack, but encountered NPEs if using a composite key (eg CommandLogEntry)
+ Throwable cause = ex.getCause();
+ if (cause instanceof DescriptorException) {
+ DescriptorException descriptorException = (DescriptorException) cause;
+ Throwable internalException = descriptorException.getInternalException();
+ if(internalException instanceof NullPointerException) {
+ return EntityState.PERSISTABLE_DETACHED;
+ }
+ }
+ throw ex;
}
//XXX whether DETACHED or REMOVED is currently undecidable (JPA)
@@ -393,6 +409,12 @@ extends FacetFactoryAbstract {
return new ByteIdSerializer();
}
}
+ Can<BookmarkService.Stringifier> select = serviceRegistry.select(BookmarkService.Stringifier.class);
+ for (BookmarkService.Stringifier stringifier : select.toList()) {
+ if(stringifier.handles() == primaryKeyType) {
+ return new DelegatingSerializer(stringifier);
+ }
+ }
val codec = serviceRegistry.lookupServiceElseFail(UrlEncodingService.class);
val serializer = serviceRegistry.lookupServiceElseFail(SerializingAdapter.class);
@@ -428,6 +450,15 @@ extends FacetFactoryAbstract {
@Override String stringify(final Byte id) { return id.toString(); }
@Override Byte parse(final String stringifiedPrimaryKey) { return Byte.parseByte(stringifiedPrimaryKey); }
}
+ private static class DelegatingSerializer extends JpaObjectIdSerializer<Object> {
+ private final BookmarkService.Stringifier stringifier;
+ public DelegatingSerializer(BookmarkService.Stringifier stringifier) {
+ super(stringifier.handles());
+ this.stringifier = stringifier;
+ }
+ @Override String stringify(final Object value) { return stringifier.stringify(value); }
+ @Override Object parse(final String stringified) { return stringifier.parse(stringified); }
+ }
private static class JpaObjectIdSerializerUsingMementos<T> extends JpaObjectIdSerializer<T> {
private final UrlEncodingService codec;
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/image/JavaAwtBufferedImageByteArrayConverter.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/awt/JavaAwtBufferedImageByteArrayConverter.java
similarity index 99%
rename from persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/image/JavaAwtBufferedImageByteArrayConverter.java
rename to persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/awt/JavaAwtBufferedImageByteArrayConverter.java
index 5a466c9f77..a12899a7eb 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/image/JavaAwtBufferedImageByteArrayConverter.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/awt/JavaAwtBufferedImageByteArrayConverter.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.persistence.jpa.integration.typeconverters.image;
+package org.apache.isis.persistence.jpa.integration.typeconverters.java.awt;
import java.awt.image.BufferedImage;
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoOffsetTimeConverter.java
similarity index 90%
copy from persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java
copy to persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoOffsetTimeConverter.java
index 437e24695e..29322cdf6c 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoOffsetTimeConverter.java
@@ -16,17 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.persistence.jpa.integration.typeconverters.time;
+package org.apache.isis.persistence.jpa.integration.typeconverters.java.time;
import java.time.OffsetTime;
import java.time.format.DateTimeFormatter;
import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
/**
* @since 2.0 {@index}
*/
-public class IsoOffsetTimeConverter implements AttributeConverter<OffsetTime, String>{
+@Converter(autoApply = true)
+public class JavaTimeIsoOffsetTimeConverter implements AttributeConverter<OffsetTime, String>{
private static final long serialVersionUID = 1L;
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoZonedDateTimeConverter.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoZonedDateTimeConverter.java
similarity index 89%
rename from persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoZonedDateTimeConverter.java
rename to persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoZonedDateTimeConverter.java
index a1ba29edcf..3bf5c6e634 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoZonedDateTimeConverter.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/time/JavaTimeIsoZonedDateTimeConverter.java
@@ -16,18 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.persistence.jpa.integration.typeconverters.time;
+package org.apache.isis.persistence.jpa.integration.typeconverters.java.time;
-import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
/**
* @since 2.0 {@index}
*/
-public class IsoZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, String> {
+@Converter(autoApply = true)
+public class JavaTimeIsoZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, String> {
private static final long serialVersionUID = 1L;
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/util/JavaUtilUuidConverter.java
similarity index 69%
rename from persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java
rename to persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/util/JavaUtilUuidConverter.java
index 437e24695e..5c5e8016de 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/time/IsoOffsetTimeConverter.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/typeconverters/java/util/JavaUtilUuidConverter.java
@@ -16,31 +16,32 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.persistence.jpa.integration.typeconverters.time;
+package org.apache.isis.persistence.jpa.integration.typeconverters.java.util;
-import java.time.OffsetTime;
-import java.time.format.DateTimeFormatter;
+import java.util.UUID;
import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
/**
* @since 2.0 {@index}
*/
-public class IsoOffsetTimeConverter implements AttributeConverter<OffsetTime, String>{
+@Converter(autoApply = true)
+public class JavaUtilUuidConverter implements AttributeConverter<UUID, String> {
private static final long serialVersionUID = 1L;
@Override
- public String convertToDatabaseColumn(final OffsetTime offsetTime) {
- return offsetTime != null
- ? offsetTime.format(DateTimeFormatter.ISO_OFFSET_TIME)
+ public String convertToDatabaseColumn(final UUID uuid) {
+ return uuid != null
+ ? uuid.toString()
: null;
}
@Override
- public OffsetTime convertToEntityAttribute(final String datastoreValue) {
+ public UUID convertToEntityAttribute(final String datastoreValue) {
return datastoreValue != null
- ? OffsetTime.parse(datastoreValue, DateTimeFormatter.ISO_OFFSET_TIME)
+ ? UUID.fromString(datastoreValue)
: null;
}
diff --git a/pom.xml b/pom.xml
index 1aa3bdf604..63f178a0e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
<maven.deploy.skip>true</maven.deploy.skip> <!-- don't deploy the aggregator -->
<maven-timeline.version>1.6</maven-timeline.version>
- </properties>
+ </properties>
<scm>
<connection>scm:git:https://github.com/apache/isis.git</connection>
@@ -348,6 +348,295 @@
</modules>
</profile>
+ <profile>
+ <id>isis-app-starter-surefire</id>
+ <activation>
+ <property>
+ <name>!skip.isis-app-starter-surefire</name>
+ </property>
+ </activation>
+
+ <properties>
+ <!-- uses maven-surefire-plugin.version, which is declared by spring-boot-starter-parent -->
+ <skipTests>false</skipTests>
+ <skipUTs>${skipTests}</skipUTs>
+ <skipITs>${skipTests}</skipITs>
+ <skipBDDs>${skipTests}</skipBDDs>
+ <surefire-plugin.argLine></surefire-plugin.argLine>
+ </properties>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${maven-surefire-plugin.version}</version>
+ <executions>
+ <execution>
+ <id>default-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skipTests>${skipUTs}</skipTests>
+ <includes>
+ <include>**/*Test*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*Testing.java</exclude>
+ <exclude>**/*IntegTest*.java</exclude>
+ <exclude>**/*Abstract*.java</exclude>
+ </excludes>
+ <useFile>true</useFile>
+ <printSummary>true</printSummary>
+ <reportsDirectory>${project.build.directory}/surefire-unittest-reports</reportsDirectory>
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <argLine>${surefire-plugin.argLine}</argLine>
+ </configuration>
+ </execution>
+ <execution>
+ <id>integ-test</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skipTests>${skipITs}</skipTests>
+ <includes>
+ <include>**/*IntegTest*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*Abstract*.java</exclude>
+ </excludes>
+ <useFile>true</useFile>
+ <printSummary>true</printSummary>
+ <reportsDirectory>${project.build.directory}/surefire-integtest-reports</reportsDirectory>
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <argLine>${surefire-plugin.argLine}</argLine>
+ </configuration>
+ </execution>
+ <execution>
+ <id>bdd-specs</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skipTests>${skipBDDs}</skipTests>
+ <includes>
+ <include>**/*Spec*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*Test.java</exclude>
+ <exclude>**/*Testing.java</exclude>
+ <exclude>**/*IntegTest*.java</exclude>
+ <exclude>**/*Abstract*.java</exclude>
+ </excludes>
+ <useFile>true</useFile>
+ <printSummary>true</printSummary>
+ <reportsDirectory>${project.build.directory}/surefire-bddspecs-reports</reportsDirectory>
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <argLine>${surefire-plugin.argLine}</argLine>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>${maven-surefire-plugin.version}</version>
+ <configuration>
+ <showSuccess>false</showSuccess>
+ </configuration>
+ <executions>
+ <execution>
+ <id>test</id>
+ <phase>test</phase>
+ </execution>
+ <execution>
+ <id>integration-test</id>
+ <phase>integration-test</phase>
+ </execution>
+ <execution>
+ <id>bdd-specs</id>
+ <phase>integration-test</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>isis-app-starter-docker</id>
+ <activation>
+ <property>
+ <name>!skip.isis-app-starter-docker</name>
+ </property>
+ </activation>
+ <properties>
+ <jib-maven-plugin.version>3.2.1</jib-maven-plugin.version>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>com.google.cloud.tools</groupId>
+ <artifactId>jib-maven-plugin</artifactId>
+ <version>${jib-maven-plugin.version}</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <!-- running: mvn spring-boot:run -->
+ <profile>
+ <id>isis-app-starter-boot</id>
+ <activation>
+ <property>
+ <name>!skip.isis-app-starter-boot</name>
+ </property>
+ </activation>
+ <properties>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>apache-release</id>
+ <activation>
+ <property>
+ <name>apache-release</name>
+ </property>
+ </activation>
+ <properties>
+ <skipTests>true</skipTests>
+ <altDeploymentRepository>apache.releases.https::default::https://repository.apache.org/service/local/staging/deploy/maven2</altDeploymentRepository>
+ </properties>
+ <build>
+ <plugins>
+ <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>3.0.1</version>
+ <executions>
+ <execution>
+ <id>sign-release-artifacts</id>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <gpgArguments>
+ <arg>--digest-algo=SHA512</arg>
+ </gpgArguments>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>net.nicoulaj.maven.plugins</groupId>
+ <artifactId>checksum-maven-plugin</artifactId>
+ <version>1.11</version>
+ <executions>
+ <execution>
+ <id>source-release-checksum</id>
+ <goals>
+ <goal>files</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <algorithms>
+ <algorithm>SHA-512</algorithm>
+ </algorithms>
+ <csvSummary>false</csvSummary>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <includes>
+ <include>${project.artifactId}-${project.version}-source-release.zip</include>
+ <include>${project.artifactId}-${project.version}-source-release.tar*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ <failIfNoFiles>false</failIfNoFiles><!-- usually, no file to do checksum:
+ don't consider error -->
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>github</id>
+ <activation>
+ <property>
+ <name>github</name>
+ </property>
+ </activation>
+ <distributionManagement>
+ <repository>
+ <id>github</id>
+ <name>Github Releases</name>
+ <url>https://maven.pkg.github.com/apache/isis</url>
+ </repository>
+ </distributionManagement>
+ </profile>
+
+ <profile>
+ <id>nightly-localfs-repo</id>
+ <activation>
+ <property>
+ <name>nightly-localfs-repo</name>
+ </property>
+ </activation>
+ <distributionManagement>
+ <repository>
+ <id>nightly-localfs-repo</id>
+ <name>Temporary Local Filesystem Staging Repository</name>
+ <url>file://${MVN_SNAPSHOTS_PATH}</url>
+ </repository>
+ </distributionManagement>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.8.2</version>
+ <configuration>
+ <altDeploymentRepository>
+ nightly-localfs-repo::default::file://${MVN_SNAPSHOTS_PATH}
+ </altDeploymentRepository>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
</profiles>
</project>
diff --git a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
index 9b504e2b20..c82590dcaa 100644
--- a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
+++ b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
@@ -35,6 +35,8 @@ import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.core.metamodel.facets.actions.action.invocation.IdentifierUtil;
+import org.apache.isis.core.metamodel.interactions.InteractionHead;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.testdomain.conf.Configuration_headless;
import org.apache.isis.testdomain.model.interaction.Configuration_usingInteractionDomain;
import org.apache.isis.testdomain.model.interaction.DemoEnum;
@@ -45,6 +47,7 @@ import org.apache.isis.testdomain.model.interaction.InteractionDemo_multiEnum;
import org.apache.isis.testdomain.model.interaction.InteractionDemo_multiInt;
import org.apache.isis.testdomain.util.interaction.InteractionTestAbstract;
+import lombok.NonNull;
import lombok.val;
@SpringBootTest(
@@ -134,7 +137,8 @@ class ActionInteractionTest extends InteractionTestAbstract {
// test feature-identifier to command matching ...
val act = tester.getActionMetaModelElseFail();
- assertTrue(IdentifierUtil.isCommandForMember(command, act));
+ InteractionHead head = tester.getActionMetaModelElseFail().interactionHead(tester.getActionOwnerElseFail());
+ assertTrue(IdentifierUtil.isCommandForMember(command, head, act));
}
@Test
@@ -180,7 +184,8 @@ class ActionInteractionTest extends InteractionTestAbstract {
// test feature-identifier to command matching ...
val act = tester.getActionMetaModelElseFail();
- assertTrue(IdentifierUtil.isCommandForMember(command, act));
+ InteractionHead head = tester.getActionMetaModelElseFail().interactionHead(tester.getActionOwnerElseFail());
+ assertTrue(IdentifierUtil.isCommandForMember(command, head, act));
}
@Test