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/08/03 12:15:40 UTC
[isis] branch ISIS-3110 created (now f427fbea15)
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a change to branch ISIS-3110
in repository https://gitbox.apache.org/repos/asf/isis.git
at f427fbea15 ISIS-3110: introduces EntityChangeTrackerJpa, mirroring JDO impl, but leveraging the PropertyChangeRecords already provided to us
This branch includes the following new commits:
new 55e8afb76d ISIS-2965: small improvements to build.sh
new f427fbea15 ISIS-3110: introduces EntityChangeTrackerJpa, mirroring JDO impl, but leveraging the PropertyChangeRecords already provided to us
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[isis] 02/02: ISIS-3110: introduces EntityChangeTrackerJpa, mirroring JDO impl, but leveraging the PropertyChangeRecords already provided to us
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-3110
in repository https://gitbox.apache.org/repos/asf/isis.git
commit f427fbea15a081018034cbfbc6a54e4d2e94e783
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Aug 3 13:15:20 2022 +0100
ISIS-3110: introduces EntityChangeTrackerJpa, mirroring JDO impl, but leveraging the PropertyChangeRecords already provided to us
---
.../objectlifecycle/ObjectLifecyclePublisher.java | 118 +++++++----------
.../publish/ObjectLifecyclePublisherDefault.java | 27 ++--
.../changetracking/EntityChangeTracker.java | 11 +-
.../integtests/AuditTrail_IntegTestAbstract.java | 4 +-
.../jpa/integtests/AuditTrail_IntegTest.java | 5 -
.../audittrail/jpa/integtests/model/Counter.java | 6 +-
.../changetracking/EntityChangeTrackerJdo.java | 12 ++
.../IsisModulePersistenceJpaIntegration.java | 4 +-
.../changetracking/EntityChangeTrackerJpa.java} | 145 ++++++++++++++++-----
.../PersistenceMetricsServiceJpa.java | 54 --------
.../changetracking/_ChangingEntitiesFactory.java | 143 ++++++++++++++++++++
.../changetracking/_SimpleChangingEntities.java | 121 +++++++++++++++++
.../jpa/integration/changetracking/_Xray.java | 145 +++++++++++++++++++++
.../bootstrap/css/bootstrap-overrides-all-v2.css | 5 +
14 files changed, 618 insertions(+), 182 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/objectlifecycle/ObjectLifecyclePublisher.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/objectlifecycle/ObjectLifecyclePublisher.java
index 2ef38b932f..8d7adce84f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/objectlifecycle/ObjectLifecyclePublisher.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/objectlifecycle/ObjectLifecyclePublisher.java
@@ -69,100 +69,74 @@ public interface ObjectLifecyclePublisher {
static HasEnlistedEntityPropertyChanges publishingPayloadForCreation(
final @NonNull ManagedObject entity) {
- return new HasEnlistedEntityPropertyChanges() {
+ return (timestamp, user, txId) -> entityPropertyChangesForCreation(timestamp, user, txId, entity);
+ }
- @Override
- public Can<EntityPropertyChange> getPropertyChanges(
- final Timestamp timestamp,
- final String user,
- final TransactionId txId) {
+ private static Can<EntityPropertyChange> entityPropertyChangesForCreation(Timestamp timestamp, String user, TransactionId txId, ManagedObject entity) {
+ return propertyChangeRecordsForCreation(entity).stream()
+ .map(pcr -> pcr.toEntityPropertyChange(timestamp, user, txId))
+ .collect(Can.toCan());
+ }
- return entity
+ static Can<PropertyChangeRecord> propertyChangeRecordsForCreation(ManagedObject entity) {
+ return entity
.getSpecification()
.streamProperties(MixedIn.EXCLUDED)
- .filter(property->EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification()))
- .filter(property->!EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property))
- .map(property->
+ .filter(property -> EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification()))
+ .filter(property -> !EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property))
+ .map(property ->
PropertyChangeRecord
- .of(
- entity,
- property,
- PreAndPostValue
- .pre(PropertyValuePlaceholder.NEW)
- .withPost(ManagedObjects.UnwrapUtil.single(property.get(entity, InteractionInitiatedBy.FRAMEWORK))))
- .toEntityPropertyChange(
- timestamp,
- user,
- txId)
- )
+ .of(
+ entity,
+ property,
+ PreAndPostValue
+ .pre(PropertyValuePlaceholder.NEW)
+ .withPost(ManagedObjects.UnwrapUtil.single(property.get(entity, InteractionInitiatedBy.FRAMEWORK)))))
.collect(Can.toCan());
-
- }
-
- };
-
}
static HasEnlistedEntityPropertyChanges publishingPayloadForDeletion(
final @NonNull ManagedObject entity) {
- return new HasEnlistedEntityPropertyChanges() {
+ return (timestamp, user, txId) -> entityPropertyChangesForDeletion(timestamp, user, txId, entity);
- @Override
- public Can<EntityPropertyChange> getPropertyChanges(
- final Timestamp timestamp,
- final String user,
- final TransactionId txId) {
+ }
- return entity
+ private static Can<EntityPropertyChange> entityPropertyChangesForDeletion(Timestamp timestamp, String user, TransactionId txId, ManagedObject entity) {
+ return propertyChangeRecordsForDeletion(entity).stream()
+ .map(pcr -> pcr.toEntityPropertyChange(timestamp, user, txId))
+ .collect(Can.toCan());
+ }
+
+ static Can<PropertyChangeRecord> propertyChangeRecordsForDeletion(ManagedObject entity) {
+ return entity
.getSpecification()
.streamProperties(MixedIn.EXCLUDED)
- .filter(property->EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification()))
- .filter(property->!EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property))
- .map(property->
+ .filter(property -> EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification()))
+ .filter(property -> !EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property))
+ .map(property ->
PropertyChangeRecord
- .of(
- entity,
- property,
- PreAndPostValue
- .pre(ManagedObjects.UnwrapUtil.single(property.get(entity, InteractionInitiatedBy.FRAMEWORK)))
- .withPost(PropertyValuePlaceholder.DELETED))
- .toEntityPropertyChange(
- timestamp,
- user,
- txId)
+ .of(
+ entity,
+ property,
+ PreAndPostValue
+ .pre(ManagedObjects.UnwrapUtil.single(property.get(entity, InteractionInitiatedBy.FRAMEWORK)))
+ .withPost(PropertyValuePlaceholder.DELETED))
)
.collect(Can.toCan());
-
- }
-
- };
-
}
- static HasEnlistedEntityPropertyChanges publishingPayloadForUpdate(
- final ManagedObject entity,
- final Can<PropertyChangeRecord> changeRecords) {
-
- return new HasEnlistedEntityPropertyChanges() {
-
- @Override
- public Can<EntityPropertyChange> getPropertyChanges(
- final Timestamp timestamp,
- final String user,
- final TransactionId txId) {
-
- return changeRecords
- .map(changeRecord->
- changeRecord
- .toEntityPropertyChange(
- timestamp,
- user,
- txId));
- }
+ static HasEnlistedEntityPropertyChanges publishingPayloadForUpdate(final Can<PropertyChangeRecord> changeRecords) {
+ return (timestamp, user, txId) -> entityPropertyChangesForUpdate(timestamp, user, txId, changeRecords);
+ }
- };
+ private static Can<EntityPropertyChange> entityPropertyChangesForUpdate(Timestamp timestamp, String user, TransactionId txId, Can<PropertyChangeRecord> changeRecords) {
+ return propertyChangeRecordsForUpdate(changeRecords)
+ .map(pcr -> pcr.toEntityPropertyChange(timestamp, user, txId));
+ }
+ static Can<PropertyChangeRecord> propertyChangeRecordsForUpdate(Can<PropertyChangeRecord> changeRecords) {
+ return changeRecords;
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/ObjectLifecyclePublisherDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/ObjectLifecyclePublisherDefault.java
index f1ff4e6a07..cf3aa6f0f6 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/ObjectLifecyclePublisherDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/ObjectLifecyclePublisherDefault.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.runtimeservices.publish;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@@ -48,7 +49,7 @@ import org.apache.isis.core.metamodel.services.objectlifecycle.ObjectLifecyclePu
import org.apache.isis.core.metamodel.services.objectlifecycle.PropertyChangeRecord;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
-import org.apache.isis.core.transaction.changetracking.EntityPropertyChangePublisher;
+import org.apache.isis.core.transaction.changetracking.EntityChangeTracker;
import org.apache.isis.core.transaction.changetracking.PersistenceCallbackHandlerAbstract;
/**
@@ -65,14 +66,18 @@ extends PersistenceCallbackHandlerAbstract
implements
ObjectLifecyclePublisher {
- private final EntityPropertyChangePublisher entityPropertyChangePublisher;
+ private final Provider<EntityChangeTracker> entityChangeTrackerProvider;
@Inject
public ObjectLifecyclePublisherDefault(
final EventBusService eventBusService,
- final EntityPropertyChangePublisher entityPropertyChangePublisher) {
+ final Provider<EntityChangeTracker> entityChangeTrackerProvider) {
super(eventBusService);
- this.entityPropertyChangePublisher = entityPropertyChangePublisher;
+ this.entityChangeTrackerProvider = entityChangeTrackerProvider;
+ }
+
+ EntityChangeTracker entityChangeTracker() {
+ return entityChangeTrackerProvider.get();
}
@Override
@@ -100,9 +105,7 @@ implements
postLifecycleEventIfRequired(entity, UpdatingLifecycleEventFacet.class);
if(EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification())) {
- entityPropertyChangePublisher.publishChangedProperties(
- ObjectLifecyclePublisher
- .publishingPayloadForUpdate(entity, changeRecords));
+ entityChangeTracker().enlistUpdating(entity, changeRecords);
}
}
@@ -113,9 +116,8 @@ implements
postLifecycleEventIfRequired(entity, RemovingLifecycleEventFacet.class);
if(EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification())) {
- entityPropertyChangePublisher.publishChangedProperties(
- ObjectLifecyclePublisher
- .publishingPayloadForDeletion(entity));
+ entityChangeTracker().enlistDeleting(entity, ObjectLifecyclePublisher
+ .propertyChangeRecordsForDeletion(entity));
}
}
@@ -125,9 +127,8 @@ implements
postLifecycleEventIfRequired(entity, PersistedLifecycleEventFacet.class);
if(EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification())) {
- entityPropertyChangePublisher.publishChangedProperties(
- ObjectLifecyclePublisher
- .publishingPayloadForCreation(entity));
+ entityChangeTracker().enlistCreated(entity, ObjectLifecyclePublisher
+ .propertyChangeRecordsForCreation(entity));
}
}
diff --git a/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/EntityChangeTracker.java b/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/EntityChangeTracker.java
index ffe1bf8da5..45acfa6121 100644
--- a/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/EntityChangeTracker.java
+++ b/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/EntityChangeTracker.java
@@ -18,6 +18,8 @@
*/
package org.apache.isis.core.transaction.changetracking;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.core.metamodel.services.objectlifecycle.PropertyChangeRecord;
import org.apache.isis.core.metamodel.spec.ManagedObject;
/**
@@ -38,6 +40,8 @@ public interface EntityChangeTracker {
*/
void enlistCreated(ManagedObject entity);
+ void enlistCreated(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords);
+
/**
* Publishing support: for object stores to enlist an object that is about to be deleted,
* capturing the pre-deletion value of the properties of the {@link ManagedObject}.
@@ -47,7 +51,9 @@ public interface EntityChangeTracker {
* The post-modification values are captured when the transaction commits. In the case of deleted objects, a
* dummy value <tt>'[DELETED]'</tt> is used as the post-modification value.
*/
- void enlistDeleting(ManagedObject entity);
+ void enlistDeleting(ManagedObject entity) ;
+
+ void enlistDeleting(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords);
/**
* Publishing support: for object stores to enlist an object that is about to be updated,
@@ -59,6 +65,8 @@ public interface EntityChangeTracker {
*/
void enlistUpdating(ManagedObject entity);
+ void enlistUpdating(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords);
+
/**
* Fires the appropriate event and lifecycle callback: {@literal LOADED}
*/
@@ -74,5 +82,6 @@ public interface EntityChangeTracker {
*/
void recognizeUpdating(ManagedObject entity);
+
}
diff --git a/extensions/security/audittrail/applib/src/test/java/org/apache/isis/extensions/audittrail/applib/integtests/AuditTrail_IntegTestAbstract.java b/extensions/security/audittrail/applib/src/test/java/org/apache/isis/extensions/audittrail/applib/integtests/AuditTrail_IntegTestAbstract.java
index 3673c987a7..e4c4910bec 100644
--- a/extensions/security/audittrail/applib/src/test/java/org/apache/isis/extensions/audittrail/applib/integtests/AuditTrail_IntegTestAbstract.java
+++ b/extensions/security/audittrail/applib/src/test/java/org/apache/isis/extensions/audittrail/applib/integtests/AuditTrail_IntegTestAbstract.java
@@ -74,7 +74,7 @@ public abstract class AuditTrail_IntegTestAbstract extends IsisIntegrationTestAb
// then
var entries = auditTrailEntryRepository.findAll();
val propertyIds = entries.stream().map(AuditTrailEntry::getPropertyId).collect(Collectors.toList());
- assertThat(propertyIds).containsExactlyInAnyOrder("name", "num", "num2");
+ assertThat(propertyIds).contains("name", "num", "num2");
val entriesById = entries.stream().collect(Collectors.toMap(AuditTrailEntry::getPropertyId, x -> x));
assertThat(entriesById.get("name"))
@@ -175,7 +175,7 @@ public abstract class AuditTrail_IntegTestAbstract extends IsisIntegrationTestAb
// then
var entries = auditTrailEntryRepository.findAll();
val propertyIds = entries.stream().map(AuditTrailEntry::getPropertyId).collect(Collectors.toList());
- assertThat(propertyIds).containsExactlyInAnyOrder("name", "num", "num2");
+ assertThat(propertyIds).contains("name", "num", "num2");
val entriesById = entries.stream().collect(Collectors.toMap(AuditTrailEntry::getPropertyId, x -> x));
assertThat(entriesById.get("name"))
diff --git a/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/AuditTrail_IntegTest.java b/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/AuditTrail_IntegTest.java
index 2c768d2f72..837457fcb5 100644
--- a/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/AuditTrail_IntegTest.java
+++ b/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/AuditTrail_IntegTest.java
@@ -73,11 +73,6 @@ public class AuditTrail_IntegTest extends AuditTrail_IntegTestAbstract {
return Counter.builder().name(name).build();
}
- @BeforeEach()
- void checkPersistenceStack() {
- // currently disabled for JPA, since EntityPropertyChangePublisher still to be implemented.
- Assumptions.assumeThat(isisBeanTypeRegistry.determineCurrentPersistenceStack().isJpa()).isFalse();
- }
@Inject IsisBeanTypeRegistry isisBeanTypeRegistry;
}
diff --git a/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/model/Counter.java b/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/model/Counter.java
index f477634eb2..351fec8052 100644
--- a/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/model/Counter.java
+++ b/extensions/security/audittrail/persistence-jpa/src/test/java/org/apache/isis/extensions/audittrail/jpa/integtests/model/Counter.java
@@ -23,12 +23,15 @@ package org.apache.isis.extensions.audittrail.jpa.integtests.model;
import javax.inject.Named;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
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.Nature;
+import org.apache.isis.applib.annotation.Publishing;
+import org.apache.isis.persistence.jpa.applib.integration.IsisEntityListener;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
@@ -43,7 +46,8 @@ import lombok.Setter;
name = "Counter"
)
@Named("audittrail.test.Counter")
-@DomainObject(nature = Nature.ENTITY)
+@EntityListeners(IsisEntityListener.class)
+@DomainObject(nature = Nature.ENTITY, entityChangePublishing = Publishing.ENABLED)
@NoArgsConstructor
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
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 cb2427003b..fd39f99375 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
@@ -366,6 +366,10 @@ implements
}
}
+ @Override
+ public void enlistCreated(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords) {
+ }
+
@Override
public void enlistDeleting(final ManagedObject entity) {
_Xray.enlistDeleting(entity, interactionProviderProvider);
@@ -374,6 +378,10 @@ implements
postLifecycleEventIfRequired(entity, RemovingLifecycleEventFacet.class);
}
+ @Override
+ public void enlistDeleting(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords) {
+ }
+
@Override
public void enlistUpdating(final ManagedObject entity) {
_Xray.enlistUpdating(entity, interactionProviderProvider);
@@ -389,6 +397,10 @@ implements
}
}
+ @Override
+ public void enlistUpdating(ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords) {
+ }
+
@Override
public void recognizeLoaded(final ManagedObject entity) {
_Xray.recognizeLoaded(entity, interactionProviderProvider);
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 682b625059..6989843f23 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
@@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.apache.isis.core.runtime.IsisModuleCoreRuntime;
-import org.apache.isis.persistence.jpa.integration.changetracking.PersistenceMetricsServiceJpa;
+import org.apache.isis.persistence.jpa.integration.changetracking.EntityChangeTrackerJpa;
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.applib.IsisBookmarkConverter;
@@ -52,7 +52,7 @@ import org.apache.isis.persistence.jpa.metamodel.IsisModulePersistenceJpaMetamod
// @Service's
JpaSupportServiceUsingSpring.class,
- PersistenceMetricsServiceJpa.class,
+ EntityChangeTrackerJpa.class,
})
@EntityScan(basePackageClasses = {
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/EntityChangeTrackerJpa.java
similarity index 75%
copy from persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java
copy to persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/EntityChangeTrackerJpa.java
index cb2427003b..2cee271ff1 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/EntityChangeTrackerJdo.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/EntityChangeTrackerJpa.java
@@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.persistence.jdo.integration.changetracking;
+package org.apache.isis.persistence.jpa.integration.changetracking;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -33,6 +34,7 @@ import javax.inject.Provider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.apache.isis.applib.annotation.EntityChangeKind;
@@ -48,6 +50,7 @@ import org.apache.isis.applib.services.publishing.spi.EntityPropertyChange;
import org.apache.isis.applib.services.xactn.TransactionId;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.commons.internal.collections._Maps;
import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -71,7 +74,6 @@ import org.apache.isis.core.metamodel.services.objectlifecycle.PropertyChangeRec
import org.apache.isis.core.metamodel.services.objectlifecycle.PropertyValuePlaceholder;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
import org.apache.isis.core.metamodel.spec.feature.MixedIn;
import org.apache.isis.core.transaction.changetracking.EntityChangeTracker;
import org.apache.isis.core.transaction.changetracking.EntityChangesPublisher;
@@ -90,12 +92,12 @@ import lombok.extern.log4j.Log4j2;
* @since 2.0 {@index}
*/
@Service
-@Named("isis.transaction.EntityChangeTrackerJdo")
+@Named("isis.transaction.EntityChangeTrackerJpa")
@Priority(PriorityPrecedence.EARLY)
@Qualifier("jdo")
@InteractionScope
@Log4j2
-public class EntityChangeTrackerJdo
+public class EntityChangeTrackerJpa
extends PersistenceCallbackHandlerAbstract
implements
MetricsService,
@@ -103,27 +105,50 @@ implements
HasEnlistedEntityPropertyChanges,
HasEnlistedEntityChanges {
+ /**
+ * If provided by the ORM.
+ */
+ private final List<PropertyChangeRecord> enlistedPropertyChangesOfCreated = _Lists.newArrayList();
+ /**
+ * If provided by the ORM.
+ */
+ private final List<PropertyChangeRecord> enlistedPropertyChangesOfUpdated = _Lists.newArrayList();
+ /**
+ * If provided by the ORM.
+ */
+ private final List<PropertyChangeRecord> enlistedPropertyChangesOfDeleted = _Lists.newArrayList();
+
/**
* Contains initial change records having set the pre-values of every property of every object that was enlisted.
+ *
+ * <p>
+ * ONLY USED IF THE ENLISTED PROPERTY CHANGES ({@link #enlistedPropertyChangesOfCreated}, {@link #enlistedPropertyChangesOfUpdated}, {@link #enlistedPropertyChangesOfDeleted}) were not provided already.
+ * </p>
*/
private final Map<String, PropertyChangeRecord> propertyChangeRecordsById = _Maps.newLinkedHashMap();
/**
* Contains pre- and post- values of every property of every object that actually changed. A lazy snapshot,
* triggered by internal call to {@link #snapshotPropertyChangeRecords()}.
+ *
+ * <p>
+ * ONLY USED IF THE ENLISTED PROPERTY CHANGES ({@link #enlistedPropertyChangesOfCreated}, {@link #enlistedPropertyChangesOfUpdated}, {@link #enlistedPropertyChangesOfDeleted}) were not provided already.
+ * </p>
*/
private final _Lazy<Set<PropertyChangeRecord>> entityPropertyChangeRecordsForPublishing
= _Lazy.threadSafe(this::capturePostValuesAndDrain);
+
@Getter(AccessLevel.PACKAGE)
private final Map<Bookmark, EntityChangeKind> changeKindByEnlistedAdapter = _Maps.newLinkedHashMap();
+
private final EntityPropertyChangePublisher entityPropertyChangePublisher;
private final EntityChangesPublisher entityChangesPublisher;
private final Provider<InteractionProvider> interactionProviderProvider;
@Inject
- public EntityChangeTrackerJdo(
+ public EntityChangeTrackerJpa(
final EntityPropertyChangePublisher entityPropertyChangePublisher,
final EntityChangesPublisher entityChangesPublisher,
final EventBusService eventBusService,
@@ -140,30 +165,47 @@ implements
.orElse(false);
}
- private void enlistCreatedInternal(final @NonNull ManagedObject adapter) {
+ private void enlistCreatedInternal(final @NonNull ManagedObject adapter, @Nullable Can<PropertyChangeRecord> propertyChangeRecords) {
if(!isEntityEnabledForChangePublishing(adapter)) {
return;
}
enlistForChangeKindPublishing(adapter, EntityChangeKind.CREATE);
- enlistForPreAndPostValuePublishing(adapter, record->record.setPreValue(PropertyValuePlaceholder.NEW));
+ if (propertyChangeRecords != null) {
+ // provided by ORM
+ propertyChangeRecords.forEach(this.enlistedPropertyChangesOfCreated::add);
+ } else {
+ // home-grown approach
+ enlistForPreAndPostValuePublishing(adapter, record->record.setPreValue(PropertyValuePlaceholder.NEW));
+ }
}
- private void enlistUpdatingInternal(
- final @NonNull ManagedObject entity) {
+ private void enlistUpdatingInternal(final @NonNull ManagedObject entity, Can<PropertyChangeRecord> propertyChangeRecords) {
if(!isEntityEnabledForChangePublishing(entity)) {
return;
}
enlistForChangeKindPublishing(entity, EntityChangeKind.UPDATE);
- enlistForPreAndPostValuePublishing(entity, PropertyChangeRecord::updatePreValue);
+ if(propertyChangeRecords != null) {
+ // provided by ORM
+ propertyChangeRecords.forEach(this.enlistedPropertyChangesOfUpdated::add);
+ } else {
+ // home-grown approach
+ enlistForPreAndPostValuePublishing(entity, PropertyChangeRecord::updatePreValue);
+ }
}
- private void enlistDeletingInternal(final @NonNull ManagedObject adapter) {
+ private void enlistDeletingInternal(final @NonNull ManagedObject adapter, Can<PropertyChangeRecord> propertyChangeRecords) {
if(!isEntityEnabledForChangePublishing(adapter)) {
return;
}
final boolean enlisted = enlistForChangeKindPublishing(adapter, EntityChangeKind.DELETE);
if(enlisted) {
- enlistForPreAndPostValuePublishing(adapter, PropertyChangeRecord::updatePreValue);
+ if (propertyChangeRecords != null) {
+ // provided by ORM
+ propertyChangeRecords.forEach(this.enlistedPropertyChangesOfDeleted::add);
+ } else {
+ // home-grown approach
+ enlistForPreAndPostValuePublishing(adapter, PropertyChangeRecord::updatePreValue);
+ }
}
}
@@ -173,12 +215,17 @@ implements
return entityPropertyChangeRecordsForPublishing.get();
}
+ private boolean isOrmSuppliedChangeRecords() {
+ return !(enlistedPropertyChangesOfCreated.isEmpty() && enlistedPropertyChangesOfUpdated.isEmpty() && enlistedPropertyChangesOfDeleted.isEmpty());
+ }
+
private boolean isEntityEnabledForChangePublishing(final @NonNull ManagedObject adapter) {
if(!EntityChangePublishingFacet.isPublishingEnabled(adapter.getSpecification())) {
return false; // ignore entities that are not enabled for entity change publishing
}
+ // if home-grown
if(entityPropertyChangeRecordsForPublishing.isMemoized()) {
throw _Exceptions.illegalState("Cannot enlist additional changes for auditing, "
+ "since changedObjectPropertiesRef was already prepared (memoized) for auditing.");
@@ -213,9 +260,14 @@ implements
private void postPublishing() {
log.debug("purging entity change records");
- propertyChangeRecordsById.clear();
+ this.enlistedPropertyChangesOfCreated.clear();
+ this.enlistedPropertyChangesOfUpdated.clear();
+ this.enlistedPropertyChangesOfDeleted.clear();
+
+// propertyChangeRecordsById.clear();
changeKindByEnlistedAdapter.clear();
- entityPropertyChangeRecordsForPublishing.clear();
+// entityPropertyChangeRecordsForPublishing.clear();
+
entityChangeEventCount.reset();
numberEntitiesLoaded.reset();
}
@@ -240,7 +292,6 @@ implements
final java.sql.Timestamp timestamp,
final String userName,
final TransactionId txId) {
-
return snapshotPropertyChangeRecords().stream()
.map(propertyChangeRecord -> propertyChangeRecord.toEntityPropertyChange(timestamp, userName, txId))
.collect(Can.toCan());
@@ -316,20 +367,34 @@ implements
*/
private Set<PropertyChangeRecord> capturePostValuesAndDrain() {
- val records = propertyChangeRecordsById.values().stream()
- // set post values, which have been left empty up to now
- .peek(rec->{
- // assuming this check correctly detects deleted entities (JDO)
- if(EntityUtil.isDetachedOrRemoved(rec.getEntity())) {
- rec.updatePostValueAsDeleted();
- } else {
- rec.updatePostValueAsNonDeleted();
- }
- })
- .filter(managedProperty->managedProperty.getPreAndPostValue().shouldPublish())
- .collect(_Sets.toUnmodifiable());
-
- propertyChangeRecordsById.clear();
+ Set<PropertyChangeRecord> records;
+
+ if (isOrmSuppliedChangeRecords()) {
+ records = _Sets.newLinkedHashSet();
+ // TODO: might need to make this more sophisticated ?
+ records.addAll(enlistedPropertyChangesOfCreated);
+ records.addAll(enlistedPropertyChangesOfUpdated);
+ records.addAll(enlistedPropertyChangesOfDeleted);
+
+ enlistedPropertyChangesOfCreated.clear();
+ enlistedPropertyChangesOfUpdated.clear();
+ enlistedPropertyChangesOfDeleted.clear();
+ } else {
+ records = propertyChangeRecordsById.values().stream()
+ // set post values, which have been left empty up to now
+ .peek(rec->{
+ // assuming this check correctly detects deleted entities (JDO)
+ if(ManagedObjects.EntityUtil.isDetachedOrRemoved(rec.getEntity())) {
+ rec.updatePostValueAsDeleted();
+ } else {
+ rec.updatePostValueAsNonDeleted();
+ }
+ })
+ .filter(managedProperty->managedProperty.getPreAndPostValue().shouldPublish())
+ .collect(_Sets.toUnmodifiable());
+
+ propertyChangeRecordsById.clear();
+ }
return records;
@@ -356,9 +421,15 @@ implements
@Override
public void enlistCreated(final ManagedObject entity) {
+ enlistCreated(entity, null);
+ }
+
+
+ @Override
+ public void enlistCreated(ManagedObject entity, @Nullable final Can<PropertyChangeRecord> propertyChangeRecords) {
_Xray.enlistCreated(entity, interactionProviderProvider);
val hasAlreadyBeenEnlisted = isEnlisted(entity);
- enlistCreatedInternal(entity);
+ enlistCreatedInternal(entity, propertyChangeRecords);
if(!hasAlreadyBeenEnlisted) {
CallbackFacet.callCallback(entity, PersistedCallbackFacet.class);
@@ -368,19 +439,29 @@ implements
@Override
public void enlistDeleting(final ManagedObject entity) {
+ enlistDeleting(entity, null);
+ }
+
+ @Override
+ public void enlistDeleting(ManagedObject entity, final Can<PropertyChangeRecord> propertyChangeRecords) {
_Xray.enlistDeleting(entity, interactionProviderProvider);
- enlistDeletingInternal(entity);
+ enlistDeletingInternal(entity, propertyChangeRecords);
CallbackFacet.callCallback(entity, RemovingCallbackFacet.class);
postLifecycleEventIfRequired(entity, RemovingLifecycleEventFacet.class);
}
@Override
public void enlistUpdating(final ManagedObject entity) {
+ enlistUpdating(entity, null);
+ }
+
+ @Override
+ public void enlistUpdating(ManagedObject entity, final Can<PropertyChangeRecord> propertyChangeRecords) {
_Xray.enlistUpdating(entity, interactionProviderProvider);
val hasAlreadyBeenEnlisted = isEnlisted(entity);
// we call this come what may;
// additional properties may now have been changed, and the changeKind for publishing might also be modified
- enlistUpdatingInternal(entity);
+ enlistUpdatingInternal(entity, propertyChangeRecords);
if(!hasAlreadyBeenEnlisted) {
// prevent an infinite loop... don't call the 'updating()' callback on this object if we have already done so
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/PersistenceMetricsServiceJpa.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/PersistenceMetricsServiceJpa.java
deleted file mode 100644
index 407ce89282..0000000000
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/PersistenceMetricsServiceJpa.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.persistence.jpa.integration.changetracking;
-
-import javax.annotation.Priority;
-import javax.inject.Named;
-
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.applib.services.metrics.MetricsService;
-
-/**
- * @since 2.0 {@index}
- */
-@Service
-@Named("isis.transaction.PersistenceMetricsServiceJpa")
-@Priority(PriorityPrecedence.EARLY)
-@Qualifier("jpa")
-//@Log4j2
-public class PersistenceMetricsServiceJpa
-implements
- MetricsService {
-
- // -- METRICS
-
- @Override
- public int numberEntitiesLoaded() {
- return -1; // n/a
- }
-
- @Override
- public int numberEntitiesDirtied() {
- return -1; // n/a
- }
-
-}
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_ChangingEntitiesFactory.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_ChangingEntitiesFactory.java
new file mode 100644
index 0000000000..c3e142433f
--- /dev/null
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_ChangingEntitiesFactory.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.persistence.jpa.integration.changetracking;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.apache.isis.applib.annotation.EntityChangeKind;
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.publishing.spi.EntityChanges;
+import org.apache.isis.core.metamodel.execution.InteractionInternal;
+import org.apache.isis.schema.chg.v2.ChangesDto;
+import org.apache.isis.schema.chg.v2.ObjectsDto;
+import org.apache.isis.schema.common.v2.OidsDto;
+
+import lombok.val;
+
+final class _ChangingEntitiesFactory {
+
+ public static Optional<EntityChanges> createChangingEntities(
+ final java.sql.Timestamp completedAt,
+ final String userName,
+ final EntityChangeTrackerJpa entityChangeTracker) {
+
+ if(entityChangeTracker.getChangeKindByEnlistedAdapter().isEmpty()) {
+ return Optional.empty();
+ }
+
+ // take a copy of enlisted adapters ... the JDO implementation of the PublishingService
+ // creates further entities which would be enlisted;
+ // taking copy of the map avoids ConcurrentModificationException
+ val changeKindByEnlistedAdapter = new HashMap<>(
+ entityChangeTracker.getChangeKindByEnlistedAdapter());
+
+ val changingEntities = newChangingEntities(
+ completedAt,
+ userName,
+ entityChangeTracker.currentInteraction(),
+ entityChangeTracker.numberEntitiesLoaded(),
+ // side-effect: it locks the result for this transaction,
+ // such that cannot enlist on top of it
+ entityChangeTracker.snapshotPropertyChangeRecords().size(),
+ changeKindByEnlistedAdapter);
+
+ return Optional.of(changingEntities);
+ }
+
+ // -- HELPER
+
+ private static EntityChanges newChangingEntities(
+ final java.sql.Timestamp completedAt,
+ final String userName,
+ final Interaction interaction,
+ final int numberEntitiesLoaded,
+ final int numberEntityPropertiesModified,
+ final Map<Bookmark, EntityChangeKind> changeKindByEnlistedAdapter) {
+
+ val interactionId = interaction.getInteractionId();
+ final int nextEventSequence = ((InteractionInternal) interaction).getThenIncrementTransactionSequence();
+
+ return new _SimpleChangingEntities(
+ interactionId, nextEventSequence,
+ userName, completedAt,
+ numberEntitiesLoaded,
+ numberEntityPropertiesModified,
+ ()->newDto(
+ interactionId, nextEventSequence,
+ userName, completedAt,
+ numberEntitiesLoaded,
+ numberEntityPropertiesModified,
+ changeKindByEnlistedAdapter));
+ }
+
+ private static ChangesDto newDto(
+ final UUID interactionId, final int transactionSequenceNum,
+ final String userName, final java.sql.Timestamp completedAt,
+ final int numberEntitiesLoaded,
+ final int numberEntityPropertiesModified,
+ final Map<Bookmark, EntityChangeKind> changeKindByEnlistedEntity) {
+
+ val objectsDto = new ObjectsDto();
+ objectsDto.setCreated(new OidsDto());
+ objectsDto.setUpdated(new OidsDto());
+ objectsDto.setDeleted(new OidsDto());
+
+ changeKindByEnlistedEntity.forEach((bookmark, kind)->{
+ val oidDto = bookmark.toOidDto();
+ if(oidDto==null) {
+ return;
+ }
+ switch(kind) {
+ case CREATE:
+ objectsDto.getCreated().getOid().add(oidDto);
+ return;
+ case UPDATE:
+ objectsDto.getUpdated().getOid().add(oidDto);
+ return;
+ case DELETE:
+ objectsDto.getDeleted().getOid().add(oidDto);
+ return;
+ }
+ });
+
+ objectsDto.setLoaded(numberEntitiesLoaded);
+ objectsDto.setPropertiesModified(numberEntityPropertiesModified);
+
+ val changesDto = new ChangesDto();
+
+ changesDto.setMajorVersion("2");
+ changesDto.setMinorVersion("0");
+
+ changesDto.setInteractionId(interactionId.toString());
+ changesDto.setSequence(transactionSequenceNum);
+
+ changesDto.setUsername(userName);
+ changesDto.setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(completedAt));
+
+ changesDto.setObjects(objectsDto);
+ return changesDto;
+ }
+
+
+}
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_SimpleChangingEntities.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_SimpleChangingEntities.java
new file mode 100644
index 0000000000..addff06fb0
--- /dev/null
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_SimpleChangingEntities.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.persistence.jpa.integration.changetracking;
+
+import java.sql.Timestamp;
+import java.util.UUID;
+import java.util.function.Supplier;
+
+import org.apache.isis.applib.services.publishing.spi.EntityChanges;
+import org.apache.isis.schema.chg.v2.ChangesDto;
+
+import lombok.NonNull;
+import lombok.ToString;
+
+/**
+ * Captures which objects were created, updated or deleted in the course of a transaction.
+ */
+@ToString
+final class _SimpleChangingEntities implements EntityChanges {
+
+ private UUID transactionUuid;
+ private final int sequence;
+ private final String userName;
+ private final Timestamp completedAt;
+ private final int numberEntitiesLoaded;
+ private final int numberEntityPropertiesModified;
+
+ @ToString.Exclude
+ private final Supplier<ChangesDto> changesDtoSupplier;
+
+ public _SimpleChangingEntities(
+ final @NonNull UUID transactionUuid,
+ final int sequence,
+ final @NonNull String userName,
+ final @NonNull Timestamp completedAt,
+ final int numberEntitiesLoaded,
+ final int numberEntityPropertiesModified,
+ final @NonNull Supplier<ChangesDto> changesDtoSupplier) {
+
+ this.transactionUuid = transactionUuid;
+ this.sequence = sequence;
+ this.userName = userName;
+ this.completedAt = completedAt;
+ this.numberEntitiesLoaded = numberEntitiesLoaded;
+ this.numberEntityPropertiesModified = numberEntityPropertiesModified;
+ this.changesDtoSupplier = changesDtoSupplier;
+ }
+
+ @Override
+ public UUID getInteractionId() {
+ return transactionUuid;
+ }
+
+ @Override
+ public int getSequence() {
+ return sequence;
+ }
+
+ /**
+ * The date/time at which this set of enlisted objects was created
+ * (approx the completion time of the transaction).
+ */
+ @Override
+ public Timestamp getCompletedAt() {
+ return completedAt;
+ }
+
+ @Override
+ public String getUsername() {
+ return userName;
+ }
+
+ private ChangesDto dto;
+
+ @Override
+ public ChangesDto getDto() {
+ return dto != null ? dto : (dto = changesDtoSupplier.get());
+ }
+
+ @Override
+ public int getNumberLoaded() {
+ return numberEntitiesLoaded;
+ }
+
+ @Override
+ public int getNumberCreated() {
+ return getDto().getObjects().getCreated().getOid().size();
+ }
+
+ @Override
+ public int getNumberUpdated() {
+ return getDto().getObjects().getUpdated().getOid().size();
+ }
+
+ @Override
+ public int getNumberDeleted() {
+ return getDto().getObjects().getDeleted().getOid().size();
+ }
+
+ @Override
+ public int getNumberPropertiesModified() {
+ return numberEntityPropertiesModified;
+ }
+
+}
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_Xray.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_Xray.java
new file mode 100644
index 0000000000..50955f25fb
--- /dev/null
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/changetracking/_Xray.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.persistence.jpa.integration.changetracking;
+
+import java.awt.Color;
+
+import javax.inject.Provider;
+
+import org.apache.isis.applib.services.iactn.InteractionProvider;
+import org.apache.isis.commons.internal.debug._XrayEvent;
+import org.apache.isis.commons.internal.debug.xray.XrayUi;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
+import org.apache.isis.core.security.util.XrayUtil;
+
+import lombok.val;
+
+final class _Xray {
+
+ public static void publish(
+ final EntityChangeTrackerJpa entityChangeTrackerDefault,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+
+ if(!XrayUi.isXrayEnabled()) {
+ return;
+ }
+
+ final long propertyChangeRecordCount = entityChangeTrackerDefault.countPotentialPropertyChangeRecords();
+
+ val enteringLabel = String.format("consider %d entity change records for publishing",
+ propertyChangeRecordCount);
+
+ XrayUtil.createSequenceHandle(interactionProviderProvider.get(), "ec-tracker")
+ .ifPresent(handle->{
+
+ handle.submit(sequenceData->{
+
+ sequenceData.alias("ec-tracker", "EntityChange-\nTracker-\n(Default)");
+
+ if(propertyChangeRecordCount==0) {
+ sequenceData.setConnectionArrowColor(Color.GRAY);
+ sequenceData.setConnectionLabelColor(Color.GRAY);
+ }
+
+ val callee = handle.getCallees().getFirstOrFail();
+ sequenceData.enter(handle.getCaller(), callee, enteringLabel);
+ //sequenceData.activate(callee);
+ });
+
+ });
+ }
+
+ public static void enlistCreated(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("enlistCreated", entity, interactionProviderProvider);
+ }
+
+ public static void enlistDeleting(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("enlistDeleting", entity, interactionProviderProvider);
+ }
+
+ public static void enlistUpdating(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("enlistUpdating", entity, interactionProviderProvider);
+ }
+
+ public static void recognizeLoaded(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("recognizeLoaded", entity, interactionProviderProvider);
+ }
+
+ public static void recognizePersisting(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("recognizePersisting", entity, interactionProviderProvider);
+ }
+
+ public static void recognizeUpdating(
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+ addSequence("recognizeUpdating", entity, interactionProviderProvider);
+ }
+
+ // -- HELPER
+
+ private static void addSequence(
+ final String what,
+ final ManagedObject entity,
+ final Provider<InteractionProvider> interactionProviderProvider) {
+
+ if(!XrayUi.isXrayEnabled()) {
+ return;
+ }
+
+ val enteringLabel = String.format("%s %s",
+ what,
+ ManagedObjects.isNullOrUnspecifiedOrEmpty(entity)
+ ? "<empty>"
+ : String.format("%s:\n%s",
+ entity.getSpecification().getLogicalTypeName(),
+ "" + entity.getPojo()));
+
+ _XrayEvent.event(enteringLabel);
+
+ XrayUtil.createSequenceHandle(interactionProviderProvider.get(), "ec-tracker")
+ .ifPresent(handle->{
+
+ handle.submit(sequenceData->{
+
+ sequenceData.alias("ec-tracker", "EntityChange-\nTracker-\n(Default)");
+
+ val callee = handle.getCallees().getFirstOrFail();
+ sequenceData.enter(handle.getCaller(), callee, enteringLabel);
+ //sequenceData.activate(callee);
+ });
+
+ });
+
+ }
+
+
+
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/common/bootstrap/css/bootstrap-overrides-all-v2.css b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/common/bootstrap/css/bootstrap-overrides-all-v2.css
index de3fb3caa0..28c87ea119 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/common/bootstrap/css/bootstrap-overrides-all-v2.css
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/common/bootstrap/css/bootstrap-overrides-all-v2.css
@@ -1011,6 +1011,11 @@ footer .footer-image {
/*padding-bottom: 7px;*/
}
+.actionParametersForm .alert {
+ margin-top: 10px;
+}
+
+
.propertyEditForm .buttons .wicket-ajax-indicator,
.actionParametersForm .buttons .wicket-ajax-indicator,
.additionalLinkList .wicket-ajax-indicator {
[isis] 01/02: ISIS-2965: small improvements to build.sh
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-3110
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 55e8afb76d6c12a867830b0483c0f0408d82aa85
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Aug 3 09:34:39 2022 +0100
ISIS-2965: small improvements to build.sh
---
build.sh | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/build.sh b/build.sh
index e9d9ad3cea..dbdd67feea 100644
--- a/build.sh
+++ b/build.sh
@@ -50,6 +50,7 @@ usage() {
echo " -k use 'package' rather than 'install'. Does not run integ tests. Cannot combine with '-y'" >&2
echo " -y use 'verify' rather than 'install'. Cannot combine with '-k'" >&2
echo " -O do NOT add '-o' (offline) flag, ie bring down any new dependencies" >&2
+ echo " -I append '-Dmodule-all-except-incubator" >&2
echo " -F do NOT search for Failures and Errors at the end" >&2
echo " -S do NOT print summary or last 50 lines at the end" >&2
echo " -w whatif - don't run the command but do print it out. Implies -v (verbose)" >&2
@@ -68,12 +69,13 @@ WHATIF=false
SINGLE_THREADED=false
SKIP_SEARCH_FOR_FAILURES=false
SKIP_SUMMARY=false
+ALL_EXCEPT_INCUBATOR=false
EDIT=false
VERBOSE=false
MVN_LOG=/tmp/$BASENAME_0.$$.log
-while getopts 'prctlkyOFSwveh' opt
+while getopts 'prctlkyIOFSwveh' opt
do
case $opt in
p) export GIT_PULL=true ;;
@@ -83,6 +85,7 @@ do
l) export SINGLE_THREADED=true ;;
k) export PACKAGE_ONLY=true ;;
y) export VERIFY_ONLY=true ;;
+ I) export ALL_EXCEPT_INCUBATOR=true ;;
F) export SKIP_SEARCH_FOR_FAILURES=true ;;
S) export SKIP_SUMMARY=true ;;
w) export WHATIF=true ;;
@@ -110,6 +113,7 @@ if [ "$VERBOSE" = "true" ]; then
echo "-k PACKAGE_ONLY : $PACKAGE_ONLY"
echo "-y VERIFY_ONLY : $VERIFY_ONLY"
echo "-O SKIP_OFFLINE : $SKIP_OFFLINE"
+ echo "-I ALL_EXCEPT_INCUBATOR : $ALL_EXCEPT_INCUBATOR"
echo "-F SKIP_SEARCH_FOR_FAILURES : $SKIP_SEARCH_FOR_FAILURES"
echo "-S SKIP_SUMMARY : $SKIP_SUMMARY"
echo "-w WHATIF : $WHATIF"
@@ -140,6 +144,10 @@ if [ "$TIMELINE" = "true" ]; then
OPTS="$OPTS -Dmaven-timeline.version=1.8-SNAPSHOT"
fi
+if [ "$ALL_EXCEPT_INCUBATOR" = "true" ]; then
+ OPTS="$OPTS -Dmodule-all-except-incubator"
+fi
+
if [ "$SKIP_OFFLINE" = "false" ]; then
OPTS="$OPTS -o"
fi