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 2013/04/20 10:32:44 UTC
git commit: ISIS-387: publish create and delete objects as well as
updates
Updated Branches:
refs/heads/master f6386b443 -> 7e6fbb337
ISIS-387: publish create and delete objects as well as updates
Changes to:
- applib (EventType enum)
- core (IsisTransaction, adding guards to prevent 'touching' deleted objects)
- jdo objectstore (enlisting changes)
- and restful (event serializer)
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/7e6fbb33
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/7e6fbb33
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/7e6fbb33
Branch: refs/heads/master
Commit: 7e6fbb33773b1e218fa9bd0e04a581f78acc6fe8
Parents: f6386b4
Author: Dan Haywood <da...@apache.org>
Authored: Sat Apr 20 09:32:28 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Sat Apr 20 09:32:28 2013 +0100
----------------------------------------------------------------------
.../applib/service/audit/AuditingServiceJdo.java | 5 +
.../service/publish/PublishingServiceJdo.java | 3 -
.../persistence/FrameworkSynchronizer.java | 37 +++-
.../persistence/IsisLifecycleListener.java | 9 +-
.../isis/applib/annotation/PublishedObject.java | 10 +-
.../publish/EventPayloadForActionInvocation.java | 2 +-
.../publish/EventPayloadForObjectChanged.java | 2 +-
.../isis/applib/services/publish/EventType.java | 4 +-
...blishingServiceWithDefaultPayloadFactories.java | 47 ++++-
.../system/transaction/IsisTransaction.java | 169 ++++++++++-----
.../system/transaction/IsisTransactionManager.java | 3 +-
.../dom/todo/ToDoItemChangedPayloadFactory.java | 3 +-
.../src/main/webapp/WEB-INF/isis.properties | 7 +-
13 files changed, 227 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
index ccd1511..43b2af0 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
@@ -21,11 +21,16 @@ package org.apache.isis.objectstore.jdo.applib.service.audit;
import java.util.List;
import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.ActionSemantics;
import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
import org.apache.isis.objectstore.jdo.applib.AuditService;
+@Named("Auditing")
public class AuditingServiceJdo extends AbstractFactoryAndRepository implements AuditService {
+ @ActionSemantics(Of.SAFE)
public List<AuditEntry> list() {
return allInstances(AuditEntry.class);
}
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishingServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishingServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishingServiceJdo.java
index e8ba8a8..06f6522 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishingServiceJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishingServiceJdo.java
@@ -5,17 +5,14 @@ import java.util.List;
import org.apache.isis.applib.AbstractService;
import org.apache.isis.applib.annotation.ActionSemantics;
import org.apache.isis.applib.annotation.ActionSemantics.Of;
-import org.apache.isis.applib.annotation.Bulk;
import org.apache.isis.applib.annotation.Hidden;
import org.apache.isis.applib.annotation.MemberOrder;
import org.apache.isis.applib.annotation.Named;
-import org.apache.isis.applib.annotation.NotInServiceMenu;
import org.apache.isis.applib.query.QueryDefault;
import org.apache.isis.applib.services.publish.EventMetadata;
import org.apache.isis.applib.services.publish.EventPayload;
import org.apache.isis.applib.services.publish.EventSerializer;
import org.apache.isis.applib.services.publish.PublishingService;
-import org.apache.isis.objectstore.jdo.applib.service.publish.PublishedEvent.State;
/**
* An implementation of {@link PublishingService} that persists events as
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
index 4703c05..35e6099 100644
--- a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
+++ b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
@@ -50,6 +50,7 @@ import org.apache.isis.core.runtime.system.persistence.OidGenerator;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore;
+import org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.CalledFrom;
public class FrameworkSynchronizer {
@@ -62,7 +63,7 @@ public class FrameworkSynchronizer {
* Just used for logging.
*/
public enum CalledFrom {
- EVENT_LOAD, EVENT_STORE, EVENT_PREDIRTY, OS_QUERY, OS_RESOLVE, OS_LAZILYLOADED
+ EVENT_LOAD, EVENT_STORE, EVENT_PREDIRTY, OS_QUERY, OS_RESOLVE, OS_LAZILYLOADED, EVENT_PREDELETE
}
@@ -131,13 +132,21 @@ public class FrameworkSynchronizer {
Class<? extends CallbackFacet> callbackFacetClass;
if (isisOid.isTransient()) {
+ // persisting
final RootOid persistentOid = getOidGenerator().createPersistent(pojo, isisOid);
getPersistenceSession().remapAsPersistent(adapter, persistentOid);
callbackFacetClass = PersistedCallbackFacet.class;
+
+ final IsisTransaction transaction = getCurrentTransaction();
+ transaction.enlistCreated(adapter);
} else {
+ // updating
callbackFacetClass = UpdatedCallbackFacet.class;
+
+ // no need to call transaction.enlist(..);
+ // already called in preDirty and the post value is captured lazily
}
Utils.clearDirtyFor(adapter);
@@ -146,6 +155,7 @@ public class FrameworkSynchronizer {
adapter.setVersion(versionIfAny);
CallbackUtils.callCallback(adapter, callbackFacetClass);
+
ensureFrameworksInAgreement(pojo);
}
}, calledFrom);
@@ -155,9 +165,7 @@ public class FrameworkSynchronizer {
withLogging(pojo, new Runnable() {
@Override
public void run() {
- final IsisTransaction transaction = getCurrentTransaction();
ObjectAdapter adapter = getAdapterManager().getAdapterFor(pojo);
-
if (adapter == null) {
// seen this happen in the case when a parent entity (LeaseItem) has a collection of children
// objects (LeaseTerm) for which we haven't had a loaded callback fired and so are not yet
@@ -180,7 +188,8 @@ public class FrameworkSynchronizer {
// hasn't yet executed, so thinks that the adapter is still transient.
return;
}
- transaction.auditDirty(adapter);
+ final IsisTransaction transaction = getCurrentTransaction();
+ transaction.enlistUpdating(adapter);
ensureRootObject(pojo);
ensureFrameworksInAgreement(pojo);
@@ -204,6 +213,22 @@ public class FrameworkSynchronizer {
}, calledFrom);
}
+
+ public void preDeleteProcessingFor(final PersistenceCapable pojo, final CalledFrom calledFrom) {
+ withLogging(pojo, new Runnable() {
+ @Override
+ public void run() {
+ ObjectAdapter adapter = getAdapterManager().getAdapterFor(pojo);
+
+ final IsisTransaction transaction = getCurrentTransaction();
+ transaction.enlistDeleting(adapter);
+
+ ensureFrameworksInAgreement(pojo);
+ }
+ }, calledFrom);
+
+ }
+
// /////////////////////////////////////////////////////////
// Helpers
// /////////////////////////////////////////////////////////
@@ -244,7 +269,7 @@ public class FrameworkSynchronizer {
// /////////////////////////////////////////////////////////
- // Helpers
+ // More Helpers...
// /////////////////////////////////////////////////////////
void ensureFrameworksInAgreement(final PersistenceCapable pojo) {
@@ -350,4 +375,6 @@ public class FrameworkSynchronizer {
}
+
+
}
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/IsisLifecycleListener.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/IsisLifecycleListener.java b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/IsisLifecycleListener.java
index 41266c6..c9118a8 100644
--- a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/IsisLifecycleListener.java
+++ b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/IsisLifecycleListener.java
@@ -119,7 +119,14 @@ public class IsisLifecycleListener implements AttachLifecycleListener, ClearLife
@Override
public void preDelete(InstanceLifecycleEvent event) {
- withLogging(Phase.PRE, event, new RunnableEnsureFrameworksInAgreement(event));
+
+ withLogging(Phase.PRE, event, new RunnableAbstract(event){
+ @Override
+ protected void doRun() {
+ final PersistenceCapable pojo = Utils.persistenceCapableFor(event);
+ synchronizer.preDeleteProcessingFor(pojo, CalledFrom.EVENT_PREDELETE);
+ }
+ });
}
@Override
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedObject.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedObject.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedObject.java
index f67c9bb..2d493b5 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedObject.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedObject.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.publish.EventPayload;
import org.apache.isis.applib.services.publish.PublishingService;
/**
- * Indicates that changes to the object's (properties) should be published.
+ * Indicates that changes to an object should be published.
*
* <p>
* Requires that an implementation of the {@link PublishingService} is registered with the framework.
@@ -39,9 +39,15 @@ import org.apache.isis.applib.services.publish.PublishingService;
@Retention(RetentionPolicy.RUNTIME)
public @interface PublishedObject {
+ public enum ChangeKind {
+ CREATE,
+ UPDATE,
+ DELETE
+ }
+
public interface PayloadFactory {
@Programmatic
- public EventPayload payloadFor(Object changedObject);
+ public EventPayload payloadFor(Object changedObject, ChangeKind changeKind);
}
Class<? extends PayloadFactory> value() default PayloadFactory.class;
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForActionInvocation.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForActionInvocation.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForActionInvocation.java
index df7b63b..4ea80bb 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForActionInvocation.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForActionInvocation.java
@@ -135,7 +135,7 @@ public class EventPayloadForActionInvocation<T> implements EventPayload {
}
final StringBuilder buf = new StringBuilder();
- buf.append(EventType.ACTION_INVOCATION + ":").append(getActionName());
+ buf.append(getActionName());
buf.append("\n target=").append(stringifier.toString(target));
buf.append("\n args=[");
for (Object arg : arguments) {
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForObjectChanged.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForObjectChanged.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForObjectChanged.java
index c52e0a6..395b935 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForObjectChanged.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayloadForObjectChanged.java
@@ -44,6 +44,6 @@ public class EventPayloadForObjectChanged<T> implements EventPayload {
if(stringifier == null) {
throw new IllegalStateException("ObjectStringifier has not been injected");
}
- return EventType.OBJECT_CHANGED + ":"+ stringifier.toString(changed);
+ return stringifier.toString(changed);
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventType.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventType.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventType.java
index 31f4166..26d9e64 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventType.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventType.java
@@ -2,5 +2,7 @@ package org.apache.isis.applib.services.publish;
public enum EventType {
ACTION_INVOCATION,
- OBJECT_CHANGED
+ OBJECT_CREATED,
+ OBJECT_UPDATED,
+ OBJECT_DELETED,
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithDefaultPayloadFactories.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithDefaultPayloadFactories.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithDefaultPayloadFactories.java
index aecbb38..fad9eba 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithDefaultPayloadFactories.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithDefaultPayloadFactories.java
@@ -1,7 +1,14 @@
package org.apache.isis.core.runtime.persistence.objectstore.transaction;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
import org.apache.isis.applib.annotation.PublishedAction;
import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
import org.apache.isis.applib.services.publish.EventMetadata;
import org.apache.isis.applib.services.publish.EventPayload;
import org.apache.isis.applib.services.publish.ObjectStringifier;
@@ -9,6 +16,8 @@ import org.apache.isis.applib.services.publish.PublishingService;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet.CurrentInvocation;
import org.apache.isis.core.metamodel.spec.ObjectAdapterUtils;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
/**
* Wrapper around {@link PublishingService} that also includes the
@@ -19,6 +28,23 @@ public class PublishingServiceWithDefaultPayloadFactories {
private final PublishingService publishingService;
private final PublishedObject.PayloadFactory defaultObjectPayloadFactory;
private final PublishedAction.PayloadFactory defaultActionPayloadFactory;
+
+ private final static Function<ObjectAdapter, ObjectAdapter> NOT_DESTROYED_ELSE_EMPTY = new Function<ObjectAdapter, ObjectAdapter>() {
+ public ObjectAdapter apply(ObjectAdapter adapter) {
+ if (!adapter.isDestroyed()) {
+ return adapter;
+ }
+ // objectstores such as JDO prevent the underlying pojo from being touched once it has been deleted.
+ // we therefore replace that pojo with an 'empty' one.
+ Object replacementObject = adapter.getSpecification().createObject();
+ getPersistenceSession().remapRecreatedPojo(adapter, replacementObject);
+ return adapter;
+ }
+ protected PersistenceSession getPersistenceSession() {
+ return IsisContext.getPersistenceSession();
+ }
+
+ };
public PublishingServiceWithDefaultPayloadFactories (
final PublishingService publishingService,
@@ -33,12 +59,14 @@ public class PublishingServiceWithDefaultPayloadFactories {
final PublishedObject.PayloadFactory payloadFactoryIfAny,
final EventMetadata metadata,
final ObjectAdapter changedAdapter,
+ final ChangeKind changeKind,
final ObjectStringifier stringifier) {
final PublishedObject.PayloadFactory payloadFactoryToUse =
payloadFactoryIfAny != null
? payloadFactoryIfAny
: defaultObjectPayloadFactory;
- final EventPayload payload = payloadFactoryToUse.payloadFor(ObjectAdapterUtils.unwrapObject(changedAdapter));
+ final EventPayload payload = payloadFactoryToUse.payloadFor(
+ ObjectAdapterUtils.unwrapObject(undeletedElseEmpty(changedAdapter)), changeKind);
payload.withStringifier(stringifier);
publishingService.publish(metadata, payload);
}
@@ -52,12 +80,23 @@ public class PublishingServiceWithDefaultPayloadFactories {
payloadFactoryIfAny != null
? payloadFactoryIfAny
: defaultActionPayloadFactory;
+ ObjectAdapter target = currentInvocation.getTarget();
+ ObjectAdapter result = currentInvocation.getResult();
+ List<ObjectAdapter> parameters = currentInvocation.getParameters();
final EventPayload payload = payloadFactoryToUse.payloadFor(
currentInvocation.getAction().getIdentifier(),
- ObjectAdapterUtils.unwrapObject(currentInvocation.getTarget()),
- ObjectAdapterUtils.unwrapObjects(currentInvocation.getParameters()),
- ObjectAdapterUtils.unwrapObject(currentInvocation.getResult()));
+ ObjectAdapterUtils.unwrapObject(undeletedElseEmpty(target)),
+ ObjectAdapterUtils.unwrapObjects(undeletedElseEmpty(parameters)),
+ ObjectAdapterUtils.unwrapObject(undeletedElseEmpty(result)));
payload.withStringifier(stringifier);
publishingService.publish(metadata, payload);
}
+
+ private static List<ObjectAdapter> undeletedElseEmpty(List<ObjectAdapter> parameters) {
+ return Lists.newArrayList(Iterables.transform(parameters, NOT_DESTROYED_ELSE_EMPTY));
+ }
+
+ private static ObjectAdapter undeletedElseEmpty(ObjectAdapter adapter) {
+ return NOT_DESTROYED_ELSE_EMPTY.apply(adapter);
+ }
}
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
index 0e77422..162a526 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
@@ -32,17 +32,19 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
+import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.google.common.net.MediaType;
import org.apache.log4j.Logger;
import org.apache.isis.applib.annotation.PublishedAction;
import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
import org.apache.isis.applib.clock.Clock;
import org.apache.isis.applib.services.audit.AuditingService;
import org.apache.isis.applib.services.publish.EventMetadata;
@@ -74,6 +76,8 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.Publishi
import org.apache.isis.core.runtime.persistence.objectstore.transaction.SaveObjectCommand;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.TransactionalResource;
import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.transaction.IsisTransaction.AdapterAndProperty;
+import org.apache.isis.core.runtime.system.transaction.IsisTransaction.PreAndPostValues;
/**
* Used by the {@link IsisTransactionManager} to captures a set of changes to be
@@ -175,7 +179,6 @@ public class IsisTransaction implements TransactionScopedComponent {
private static final Logger LOG = Logger.getLogger(IsisTransaction.class);
-
private final TransactionalResource objectStore;
private final List<PersistenceCommand> commands = Lists.newArrayList();
private final IsisTransactionManager transactionManager;
@@ -196,6 +199,7 @@ public class IsisTransaction implements TransactionScopedComponent {
private final UUID guid;
+
private int eventSequence;
public IsisTransaction(final IsisTransactionManager transactionManager, final org.apache.isis.core.commons.authentication.MessageBroker messageBroker, final UpdateNotifier updateNotifier, final TransactionalResource objectStore, final AuditingService auditingService, PublishingServiceWithDefaultPayloadFactories publishingService) {
@@ -209,7 +213,8 @@ public class IsisTransaction implements TransactionScopedComponent {
this.updateNotifier = updateNotifier;
this.auditingService = auditingService;
this.publishingService = publishingService;
-
+
+
this.guid = UUID.randomUUID();
this.eventSequence = 0;
@@ -386,28 +391,19 @@ public class IsisTransaction implements TransactionScopedComponent {
// else
final String currentUser = getTransactionManager().getAuthenticationSession().getUserName();
- final long currentTimestampEpoch = currentTimestampEpoch();
+ final long currentTimestampEpoch = currentTimestamp();
for (Entry<AdapterAndProperty, PreAndPostValues> auditEntry : changedObjectProperties) {
auditChangedProperty(currentUser, currentTimestampEpoch, auditEntry);
}
}
- protected void doPublish(final Set<ObjectAdapter> changedAdapters) {
+
+ protected void publishActionIfRequired(final String currentUser, final long currentTimestampEpoch) {
+
if(publishingService == null) {
return;
}
- // else
- final String currentUser = getTransactionManager().getAuthenticationSession().getUserName();
- final long currentTimestampEpoch = currentTimestampEpoch();
-
- publishActionIfRequired(currentUser, currentTimestampEpoch);
- publishedChangedObjects(changedAdapters, currentUser, currentTimestampEpoch);
- }
-
- protected void publishActionIfRequired(final String currentUser, final long currentTimestampEpoch) {
- // TODO: need some transaction handling here
-
try {
final CurrentInvocation currentInvocation = ActionInvocationFacet.currentInvocation.get();
if(currentInvocation == null) {
@@ -426,26 +422,45 @@ public class IsisTransaction implements TransactionScopedComponent {
final EventMetadata metadata = newEventMetadata(EventType.ACTION_INVOCATION, currentUser, currentTimestampEpoch, title);
publishingService.publishAction(payloadFactory, metadata, currentInvocation, objectStringifier());
} finally {
+ // ensures that cannot publish this action more than once
ActionInvocationFacet.currentInvocation.set(null);
}
}
- protected void publishedChangedObjects(final Set<ObjectAdapter> changedAdapters, final String currentUser, final long currentTimestampEpoch) {
- for (final ObjectAdapter changedAdapter : changedAdapters) {
- final PublishedObjectFacet publishedObjectFacet = changedAdapter.getSpecification().getFacet(PublishedObjectFacet.class);
+ protected void publishedChangedObjectsIfRequired(final String currentUser, final long currentTimestampEpoch) {
+ if(publishingService == null) {
+ return;
+ }
+
+ for (final ObjectAdapter enlistedAdapter : changeKindByEnlistedAdapter.keySet()) {
+ final ChangeKind changeKind = changeKindByEnlistedAdapter.get(enlistedAdapter);
+ final PublishedObjectFacet publishedObjectFacet = enlistedAdapter.getSpecification().getFacet(PublishedObjectFacet.class);
if(publishedObjectFacet == null) {
continue;
}
final PublishedObject.PayloadFactory payloadFactory = publishedObjectFacet.value();
-
- final RootOid adapterOid = (RootOid) changedAdapter.getOid();
+
+ final RootOid adapterOid = (RootOid) enlistedAdapter.getOid();
final String oidStr = getOidMarshaller().marshal(adapterOid);
final String title = oidStr;
+
+ final EventMetadata metadata = newEventMetadata(eventTypeFor(changeKind), currentUser, currentTimestampEpoch, title);
+
+ publishingService.publishObject(payloadFactory, metadata, enlistedAdapter, changeKind, objectStringifier());
+ }
+ }
- final EventMetadata metadata = newEventMetadata(EventType.OBJECT_CHANGED, currentUser, currentTimestampEpoch, title);
-
- publishingService.publishObject(payloadFactory, metadata, changedAdapter, objectStringifier());
+ private static EventType eventTypeFor(ChangeKind changeKind) {
+ if(changeKind == ChangeKind.UPDATE) {
+ return EventType.OBJECT_UPDATED;
+ }
+ if(changeKind == ChangeKind.CREATE) {
+ return EventType.OBJECT_CREATED;
}
+ if(changeKind == ChangeKind.DELETE) {
+ return EventType.OBJECT_DELETED;
+ }
+ throw new IllegalArgumentException("unknown ChangeKind '" + changeKind + "'");
}
protected ObjectStringifier objectStringifier() {
@@ -476,7 +491,7 @@ public class IsisTransaction implements TransactionScopedComponent {
return objectStringifier;
}
- private static long currentTimestampEpoch() {
+ private static long currentTimestamp() {
return Clock.getTime();
}
@@ -534,11 +549,19 @@ public class IsisTransaction implements TransactionScopedComponent {
return;
}
+
try {
doAudit(getChangedObjectProperties());
+
+ final String currentUser = getTransactionManager().getAuthenticationSession().getUserName();
+ final long endTimestamp = currentTimestamp();
+
+ publishActionIfRequired(currentUser, endTimestamp);
doFlush();
- doPublish(getChangedObjects());
+
+ publishedChangedObjectsIfRequired(currentUser, endTimestamp);
doFlush();
+
setState(State.COMMITTED);
} catch (final RuntimeException ex) {
setAbortCause(new IsisTransactionManagerException(ex));
@@ -766,7 +789,7 @@ public class IsisTransaction implements TransactionScopedComponent {
return referencedAdapter == null ? null : referencedAdapter.getObject();
}
}
-
+
////////////////////////////////////////////////////////////////////////
// Auditing/Publishing object tracking
@@ -815,51 +838,92 @@ public class IsisTransaction implements TransactionScopedComponent {
}
+ private final Map<ObjectAdapter,ChangeKind> changeKindByEnlistedAdapter = Maps.newLinkedHashMap();
private final Map<AdapterAndProperty, PreAndPostValues> changedObjectProperties = Maps.newLinkedHashMap();
- private final Set<ObjectAdapter> changedObjects = Sets.newLinkedHashSet();
-
private ObjectStringifier objectStringifier;
-
+
+
/**
- * For object stores to record the current values of an {@link ObjectAdapter} that has enlisted
- * into the transaction, prior to updating its values.
+ * Auditing and publishing support: for object stores to enlist an object that has just been created,
+ * capturing a dummy value <tt>'[NEW]'</tt> for the pre-modification value.
*
* <p>
- * The values of the {@link ObjectAdapter} after being updated are captured when the
- * audit entries are requested, in {@link #getChangedObjectProperties()}.
+ * The post-modification values are captured in as a side-effect of calling {@link #getChangedObjectProperties()},
+ * which returns the pre- and post- values for each {@link ObjectAdapter} in a map.
*
* <p>
* Supported by the JDO object store; check documentation for support in other objectstores.
*/
- public void auditDirty(ObjectAdapter adapter) {
+ public void enlistCreated(ObjectAdapter adapter) {
+ enlist(adapter, ChangeKind.CREATE);
for (ObjectAssociation property : adapter.getSpecification().getAssociations(ObjectAssociationFilters.PROPERTIES)) {
- changedObjectProperty(adapter, property);
+ final AdapterAndProperty aap = AdapterAndProperty.of(adapter, property);
+ PreAndPostValues papv = PreAndPostValues.pre("[NEW]");
+ changedObjectProperties.put(aap, papv);
}
}
-
- private void changedObjectProperty(ObjectAdapter adapter, ObjectAssociation property) {
- final AdapterAndProperty aap = AdapterAndProperty.of(adapter, property);
- PreAndPostValues papv = PreAndPostValues.pre(aap.getPropertyValue());
- changedObjectProperties.put(aap, papv);
- changedObjects.add(adapter);
+
+ /**
+ * Auditing and publishing support: for object stores to enlist an object that is about to be updated,
+ * capturing the pre-modification values of the properties of the {@link ObjectAdapter}.
+ *
+ * <p>
+ * The post-modification values are captured in as a side-effect of calling {@link #getChangedObjectProperties()},
+ * which returns the pre- and post- values for each {@link ObjectAdapter} in a map.
+ *
+ * <p>
+ * Supported by the JDO object store; check documentation for support in other objectstores.
+ */
+ public void enlistUpdating(ObjectAdapter adapter) {
+ enlist(adapter, ChangeKind.UPDATE);
+ for (ObjectAssociation property : adapter.getSpecification().getAssociations(ObjectAssociationFilters.PROPERTIES)) {
+ final AdapterAndProperty aap = AdapterAndProperty.of(adapter, property);
+ PreAndPostValues papv = PreAndPostValues.pre(aap.getPropertyValue());
+ changedObjectProperties.put(aap, papv);
+ }
+ }
+
+ /**
+ * Auditing and 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 ObjectAdapter}.
+ *
+ * <p>
+ * The post-modification values are captured in as a side-effect of calling {@link #getChangedObjectProperties()}.
+ * In the case of deleted objects, a dummy value <tt>'[DELETED]'</tt> is used as the post-modification value.
+ *
+ * <p>
+ * Supported by the JDO object store; check documentation for support in other objectstores.
+ */
+ public void enlistDeleting(ObjectAdapter adapter) {
+ enlist(adapter, ChangeKind.DELETE);
+ for (ObjectAssociation property : adapter.getSpecification().getAssociations(ObjectAssociationFilters.PROPERTIES)) {
+ final AdapterAndProperty aap = AdapterAndProperty.of(adapter, property);
+ PreAndPostValues papv = PreAndPostValues.pre(aap.getPropertyValue());
+ changedObjectProperties.put(aap, papv);
+ }
}
+ private void enlist(ObjectAdapter adapter, ChangeKind changeKind) {
+ changeKindByEnlistedAdapter.put(adapter, changeKind);
+ }
+
+
/**
* Returns the pre- and post-values of all {@link ObjectAdapter}s that were enlisted and dirtied
* in this transaction.
*
* <p>
- * This requires that the object store called {@link #auditDirty(ObjectAdapter)} for each object being
+ * This requires that the object store called {@link #enlistUpdating(ObjectAdapter)} for each object being
* enlisted.
*
* <p>
- * Supported by the JDO object store (since it calls {@link #auditDirty(ObjectAdapter)});
+ * Supported by the JDO object store (since it calls {@link #enlistUpdating(ObjectAdapter)});
* check documentation for support in other object stores.
*/
- public Set<Entry<AdapterAndProperty, PreAndPostValues>> getChangedObjectProperties() {
+ private Set<Entry<AdapterAndProperty, PreAndPostValues>> getChangedObjectProperties() {
updatePostValues(changedObjectProperties.entrySet());
return Collections.unmodifiableSet(Sets.filter(changedObjectProperties.entrySet(), PreAndPostValues.CHANGED));
@@ -869,15 +933,17 @@ public class IsisTransaction implements TransactionScopedComponent {
for (Entry<AdapterAndProperty, PreAndPostValues> entry : entrySet) {
final AdapterAndProperty aap = entry.getKey();
final PreAndPostValues papv = entry.getValue();
-
- papv.setPost(aap.getPropertyValue());
+ ObjectAdapter adapter = aap.getAdapter();
+ if(adapter.isDestroyed()) {
+ // don't touch the object!!!
+ // JDO, for example, will complain otherwise...
+ papv.setPost("[DELETED]");
+ } else {
+ papv.setPost(aap.getPropertyValue());
+ }
}
}
- private Set<ObjectAdapter> getChangedObjects() {
- return changedObjects;
- }
-
////////////////////////////////////////////////////////////////////////
// Dependencies (from context)
@@ -892,5 +958,6 @@ public class IsisTransaction implements TransactionScopedComponent {
}
+
}
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
index 01c3fe3..b85fde7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
@@ -33,6 +33,7 @@ import org.apache.log4j.Logger;
import org.apache.isis.applib.Identifier;
import org.apache.isis.applib.annotation.PublishedAction;
import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
import org.apache.isis.applib.services.audit.AuditingService;
import org.apache.isis.applib.services.publish.EventPayload;
import org.apache.isis.applib.services.publish.EventPayloadForActionInvocation;
@@ -461,7 +462,7 @@ public class IsisTransactionManager implements SessionScopedComponent {
protected PublishedObject.PayloadFactory newDefaultObjectPayloadFactory() {
return new PublishedObject.PayloadFactory() {
@Override
- public EventPayload payloadFor(final Object changedObject) {
+ public EventPayload payloadFor(final Object changedObject, ChangeKind changeKind) {
return new EventPayloadForObjectChanged<Object>(changedObject);
}
};
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
index b714d1a..38fc51a 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
@@ -1,5 +1,6 @@
package dom.todo;
+import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
import org.apache.isis.applib.annotation.PublishedObject.PayloadFactory;
import org.apache.isis.applib.services.publish.EventPayload;
import org.apache.isis.applib.services.publish.EventPayloadForObjectChanged;
@@ -17,7 +18,7 @@ public class ToDoItemChangedPayloadFactory implements PayloadFactory{
}
}
@Override
- public EventPayload payloadFor(Object changedObject) {
+ public EventPayload payloadFor(Object changedObject, ChangeKind changeKind) {
return new ToDoItemPayload((ToDoItem) changedObject);
}
http://git-wip-us.apache.org/repos/asf/isis/blob/7e6fbb33/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
index 7117145..3effdbd 100644
--- a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
+++ b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
@@ -165,9 +165,10 @@ isis.services = objstore.jdo.todo.ToDoItemsJdo,\
org.apache.isis.objectstore.jdo.service.RegisterEntities,\
org.apache.isis.objectstore.jdo.applib.service.exceprecog.ExceptionRecognizerCompositeForJdoObjectStore,\
org.apache.isis.viewer.restfulobjects.rendering.eventserializer.RestfulObjectsSpecEventSerializer,\
- org.apache.isis.objectstore.jdo.applib.service.publish.PublishingServiceJdo
- #org.apache.isis.applib.services.publish.PublishingService$Stderr
- #com.danhaywood.isis.publishingservice.activemq.ra.PublishingServiceUsingActiveMqRa
+ org.apache.isis.applib.services.audit.AuditingService$Stdout,\
+ org.apache.isis.applib.services.publish.PublishingService$Stderr
+ #org.apache.isis.objectstore.jdo.applib.service.audit.AuditingServiceJdo,\
+ #org.apache.isis.objectstore.jdo.applib.service.publish.PublishingServiceJdo
# Specify the (optional) test fixtures