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 2016/05/26 16:30:05 UTC
[2/4] isis git commit: ISIS-1414: moving the @RequestScoped
initialization/close stuff out of IsisTransactionManager and IsisTransaction,
and into PersistenceSession.
ISIS-1414: moving the @RequestScoped initialization/close stuff out of IsisTransactionManager and IsisTransaction, and into PersistenceSession.
Also:
- CommandService#startTransaction is no longer called.
- remove unused code/hashmap in PersistenceSession
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/21b27fe4
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/21b27fe4
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/21b27fe4
Branch: refs/heads/ISIS-1414
Commit: 21b27fe49790adc78a3fe7804ff4feba7790bbed
Parents: 0d32721
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu May 26 16:22:19 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu May 26 17:26:54 2016 +0100
----------------------------------------------------------------------
.../guides/_rgsvc_spi_CommandService.adoc | 2 +-
core/applib/pom.xml | 4 +
.../services/command/spi/CommandService.java | 2 +
core/pom.xml | 6 +
.../runtime/services/ServiceInstantiator.java | 36 +--
.../changes/ChangedObjectsServiceInternal.java | 1 +
.../system/persistence/PersistenceSession.java | 271 ++++++++++++++-----
.../system/transaction/IsisTransaction.java | 225 +++++----------
.../transaction/IsisTransactionManager.java | 134 ++-------
9 files changed, 312 insertions(+), 369 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
index ee3885b..a795586 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
@@ -56,7 +56,7 @@ public interface CommandService {
<1> Instantiate the appropriate instance of the `Command` (as defined by the
xref:rgsvc.adoc#_rgsvc_api_CommandContext[`CommandContext`] service). Its members will be populated automatically by
the framework.
-<2> (as of `1.13.0-SNAPSHOT`) is deprecated: the framework automatically populates the ``Command``'s `timestamp`,
+<2> (as of `1.13.0-SNAPSHOT`) is *NO LONGER CALLED* and is deprecated: the framework automatically populates the ``Command``'s `timestamp`,
`user` and `transactionId` fields, so there is no need for the service implementation to initialize any of these. In
particular, the ``Command`` will already have been initialized with the provided `transactionId` argument.
<3> Set the hint that the `Command` should be persisted if possible (when completed, see below).
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/applib/pom.xml
----------------------------------------------------------------------
diff --git a/core/applib/pom.xml b/core/applib/pom.xml
index 4cb78cd..a38461c 100644
--- a/core/applib/pom.xml
+++ b/core/applib/pom.xml
@@ -102,6 +102,10 @@
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>transaction-api</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
index da7434e..5d018de 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
@@ -34,6 +34,8 @@ public interface CommandService {
Command create();
/**
+ * DEPRECATED - this method is no longer called by the framework.
+ *
* @deprecated - the framework automatically populates the {@link Command}'s {@link Command#getTimestamp()}, {@link Command#getUser()} and {@link Command#getTransactionId()}, so there is no need for the service implementation to initialize any of these. In particular, the {@link Command} will already have been initialized with the provided <tt>transactionId</tt> argument.
*/
@Deprecated
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 6770b0d..611c6bb 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -175,6 +175,7 @@
<geronimo-jcdi_1.0_spec.version>1.0</geronimo-jcdi_1.0_spec.version>
<validation-api.version>1.1.0.Final</validation-api.version>
+ <transaction-api.version>1.2</transaction-api.version>
<javax-mail.version>1.4.7</javax-mail.version>
@@ -1890,6 +1891,11 @@ ${license.additional-notes}
<artifactId>validation-api</artifactId>
<version>${validation-api.version}</version>
</dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>transaction-api</artifactId>
+ <version>${transaction-api.version}</version>
+ </dependency>
<!-- DataNucleus -->
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
index 27ee048..bda20bd 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
@@ -19,22 +19,21 @@
package org.apache.isis.core.runtime.services;
-import javassist.util.proxy.MethodFilter;
-import javassist.util.proxy.MethodHandler;
-import javassist.util.proxy.ProxyFactory;
-import javassist.util.proxy.ProxyObject;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
+
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
+
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import org.apache.isis.core.commons.config.IsisConfiguration;
import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.commons.factory.InstanceCreationClassException;
@@ -44,6 +43,11 @@ import org.apache.isis.core.commons.lang.MethodExtensions;
import org.apache.isis.core.metamodel.services.ServicesInjector;
import org.apache.isis.core.metamodel.specloader.classsubstitutor.JavassistEnhanced;
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.ProxyFactory;
+import javassist.util.proxy.ProxyObject;
+
/**
* Instantiates the service, taking into account whether the service is annotated with
* {@link RequestScoped} or not.
@@ -75,13 +79,6 @@ public final class ServiceInstantiator {
// //////////////////////////////////////
- private boolean ignoreFailures;
- public void setIgnoreFailures(boolean ignoreFailures) {
- this.ignoreFailures = ignoreFailures;
- }
-
- // //////////////////////////////////////
-
/**
* initially null, but checked before first use that has been set (through {@link #setConfiguration(org.apache.isis.core.commons.config.IsisConfiguration)}).
@@ -116,9 +113,6 @@ public final class ServiceInstantiator {
//return Thread.currentThread().getContextClassLoader().loadClass(className);
return Class.forName(className);
} catch (final ClassNotFoundException ex) {
- if(ignoreFailures) {
- return null;
- }
throw new InitialisationException(String.format("Cannot find class '%s' for service", className));
}
}
@@ -219,21 +213,17 @@ public final class ServiceInstantiator {
} else {
T service = serviceByThread.get();
if(service == null) {
- // ignore; this could potentially happen during an application-level init (PersistenceSessionFactory#init)
- // it has also happened in past when enabling debugging, though the
- // new hashCode(), equals() and toString() checks above should mitigate.
- return null;
+ // shouldn't happen...
+ throw new IllegalStateException("No service of type " + cls + " is available on this ");
}
- final Object proxiedReturn = proxyMethod.invoke(service, args);
+ final Object proxiedReturn = proxyMethod.invoke(service, args);
return proxiedReturn;
}
}
});
return newInstance;
- } catch (final InstantiationException e) {
- throw new IsisException(e);
- } catch (final IllegalAccessException e) {
+ } catch (final InstantiationException | IllegalAccessException e) {
throw new IsisException(e);
}
}
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
index fd5b618..8001b6b 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
@@ -260,6 +260,7 @@ public class ChangedObjectsServiceInternal {
@Programmatic
public void clearChangedObjectProperties() {
enlistedObjectProperties.clear();
+ changedObjectProperties = null;
}
private static final Predicate<ObjectAdapter> IS_TRANSACTION_ID = new Predicate<ObjectAdapter>() {
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
index f2eecbd..9cdd8cb 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
@@ -20,6 +20,7 @@ package org.apache.isis.core.runtime.system.persistence;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
+import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
@@ -29,6 +30,7 @@ import javax.jdo.FetchGroup;
import javax.jdo.FetchPlan;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.listener.InstanceLifecycleListener;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -38,15 +40,26 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.annotation.Bulk;
import org.apache.isis.applib.profiles.Localization;
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.applib.services.bookmark.BookmarkService2;
+import org.apache.isis.applib.services.clock.ClockService;
import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.Command2;
+import org.apache.isis.applib.services.command.Command3;
+import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.command.spi.CommandService;
import org.apache.isis.applib.services.eventbus.AbstractLifecycleEvent;
import org.apache.isis.applib.services.eventbus.EventBusService;
import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer2;
+import org.apache.isis.applib.services.factory.FactoryService;
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.iactn.InteractionContext;
+import org.apache.isis.applib.services.metrics.MetricsService;
+import org.apache.isis.applib.services.user.UserService;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.components.SessionScopedComponent;
import org.apache.isis.core.commons.config.IsisConfiguration;
@@ -112,8 +125,8 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.Transact
import org.apache.isis.core.runtime.persistence.query.PersistenceQueryFindAllInstances;
import org.apache.isis.core.runtime.persistence.query.PersistenceQueryFindUsingApplibQueryDefault;
import org.apache.isis.core.runtime.runner.opts.OptionHandlerFixtureAbstract;
+import org.apache.isis.core.runtime.services.RequestScopedService;
import org.apache.isis.core.runtime.services.changes.ChangedObjectsServiceInternal;
-import org.apache.isis.core.runtime.services.metrics.MetricsServiceDefault;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.adaptermanager.OidAdapterHashMap;
import org.apache.isis.core.runtime.system.persistence.adaptermanager.PojoAdapterHashMap;
@@ -176,6 +189,20 @@ public class PersistenceSession implements
private final AuthenticationSession authenticationSession;
private final ServicesInjector servicesInjector;
+
+ private final CommandContext commandContext;
+ private final CommandService commandService;
+
+ private final InteractionContext interactionContext;
+ private final EventBusService eventBusService ;
+ private final ChangedObjectsServiceInternal changedObjectsServiceInternal;
+ private final FactoryService factoryService;
+ private final MetricsService metricsService;
+ private final ClockService clockService;
+ private final UserService userService;
+ private final Bulk.InteractionContext bulkInteractionContext;
+
+
/**
* Used to create the {@link #persistenceManager} when {@link #open()}ed.
*/
@@ -196,7 +223,6 @@ public class PersistenceSession implements
*/
private final Map<Class<?>, PersistenceQueryProcessor<?>> persistenceQueryProcessorByClass = Maps.newHashMap();
- private final Map<ObjectSpecId, RootOid> registeredServices = Maps.newHashMap();
private final boolean concurrencyCheckingGloballyEnabled;
@@ -217,21 +243,32 @@ public class PersistenceSession implements
LOG.debug("creating " + this);
}
+ this.servicesInjector = servicesInjector;
+ this.jdoPersistenceManagerFactory = jdoPersistenceManagerFactory;
+ this.fixturesInstalledFlag = fixturesInstalledFlag;
+
// injected
this.configuration = configuration;
this.specificationLoader = specificationLoader;
this.authenticationSession = authenticationSession;
- this.fixturesInstalledFlag = fixturesInstalledFlag;
- this.servicesInjector = servicesInjector;
- this.jdoPersistenceManagerFactory = jdoPersistenceManagerFactory;
+ this.commandContext = lookupService(CommandContext.class);
+ this.commandService = lookupService(CommandService.class);
+ this.interactionContext = lookupService(InteractionContext.class);
+ this.eventBusService = lookupService(EventBusService.class);
+ this.changedObjectsServiceInternal = lookupService(ChangedObjectsServiceInternal.class);
+ this.metricsService = lookupService(MetricsService.class);
+ this.factoryService = lookupService(FactoryService.class);
+ this.clockService = lookupService(ClockService.class);
+ this.userService = lookupService(UserService.class);
+ this.bulkInteractionContext = lookupService(Bulk.InteractionContext.class);
// sub-components
final AdapterManager adapterManager = this;
this.persistenceQueryFactory = new PersistenceQueryFactory(adapterManager, specificationLoader);
this.transactionManager = new IsisTransactionManager(this, servicesInjector);
- setState(State.NOT_INITIALIZED);
+ this.state = State.NOT_INITIALIZED;
final boolean concurrencyCheckingGloballyDisabled =
configuration.getBoolean("isis.persistor.disableConcurrencyChecking", false);
@@ -285,39 +322,86 @@ public class PersistenceSession implements
new PersistenceQueryFindUsingApplibQueryProcessor(this));
initServices();
+ startRequestOnRequestScopedServices();
+
+ if(metricsService instanceof InstanceLifecycleListener) {
+ final InstanceLifecycleListener metricsService = (InstanceLifecycleListener) this.metricsService;
+ persistenceManager.addInstanceLifecycleListener(metricsService, (Class[]) null);
+ }
+
+
+ final Command command = createCommand();
+ final UUID transactionId = UUID.randomUUID();
+ final Interaction interaction = factoryService.instantiate(Interaction.class);
+
+ final Timestamp timestamp = clockService.nowAsJavaSqlTimestamp();
+ final String userName = userService.getUser().getName();
+
+ command.setTimestamp(timestamp);
+ command.setUser(userName);
+ command.setTransactionId(transactionId);
+
+ interaction.setTransactionId(transactionId);
- final MetricsServiceDefault metricsServiceDefault = servicesInjector.lookupService(MetricsServiceDefault.class);
- persistenceManager.addInstanceLifecycleListener(metricsServiceDefault, (Class[])null);
+ commandContext.setCommand(command);
+ interactionContext.setInteraction(interaction);
- setState(State.OPEN);
+ Bulk.InteractionContext.current.set(bulkInteractionContext);
+
+ this.state = State.OPEN;
}
+
+ private void startRequestOnRequestScopedServices() {
+
+ final List<Object> registeredServices = servicesInjector.getRegisteredServices();
+
+ // tell the proxy of all request-scoped services to instantiate the underlying
+ // services, store onto the thread-local and inject into them...
+ for (final Object service : registeredServices) {
+ if(service instanceof RequestScopedService) {
+ ((RequestScopedService)service).__isis_startRequest(servicesInjector);
+ }
+ }
+ // ... and invoke all @PostConstruct
+ for (final Object service : registeredServices) {
+ if(service instanceof RequestScopedService) {
+ ((RequestScopedService)service).__isis_postConstruct();
+ }
+ }
+ }
+
/**
- * Creates {@link ObjectAdapter adapters} for the service list.
+ * Creates {@link ObjectAdapter adapters} for the service list, ensuring that these are mapped correctly,
+ * and have the same OIDs as in any previous sessions.
*/
private void initServices() {
final List<Object> registeredServices = servicesInjector.getRegisteredServices();
+
for (final Object service : registeredServices) {
final ObjectSpecification serviceSpecification =
specificationLoader.loadSpecification(service.getClass());
serviceSpecification.markAsService();
- final RootOid existingOid = getOidForService(serviceSpecification);
- final ObjectAdapter serviceAdapter =
- existingOid == null
- ? adapterFor(service)
- : mapRecreatedPojo(existingOid, service);
- if (serviceAdapter.getOid().isTransient()) {
- remapAsPersistent(serviceAdapter, null);
- }
- if (existingOid == null) {
- final RootOid persistentOid = (RootOid) serviceAdapter.getOid();
- this.registeredServices.put(persistentOid.getObjectSpecId(), persistentOid);
- }
+ final ObjectAdapter serviceAdapter = adapterFor(service);
+ remapAsPersistentIfRequired(serviceAdapter);
}
}
+ private void remapAsPersistentIfRequired(final ObjectAdapter serviceAdapter) {
+ if (serviceAdapter.getOid().isTransient()) {
+ remapAsPersistent(serviceAdapter, null);
+ }
+ }
+
+ private Command createCommand() {
+ final Command command = commandService.create();
+
+ servicesInjector.injectServicesInto(command);
+ return command;
+ }
+
//endregion
//region > close
@@ -335,11 +419,18 @@ public class PersistenceSession implements
*/
public void close() {
- if (getState() == State.CLOSED) {
+ if (state == State.CLOSED) {
// nothing to do
return;
}
+ completeCommandFromInteractionAndClearDomainEvents();
+ transactionManager.flushTransaction();
+
+ Bulk.InteractionContext.current.set(null);
+
+ endRequestOnRequestScopeServices();
+
try {
final IsisTransaction currentTransaction = transactionManager.getTransaction();
if (currentTransaction != null && !currentTransaction.getState().isComplete()) {
@@ -361,8 +452,6 @@ public class PersistenceSession implements
LOG.error(
"close: failed to close JDO persistenceManager; continuing to avoid memory leakage");
}
- // TODO: REVIEW ... ??? this is a guess: don't set to null, because we need for -> transactionManager -> transaction -> messageBroker
- // persistenceManager = null;
try {
oidAdapterMap.close();
@@ -378,9 +467,66 @@ public class PersistenceSession implements
LOG.error("close: pojoAdapterMap#close() failed; continuing to avoid memory leakage");
}
- setState(State.CLOSED);
+ this.state = State.CLOSED;
+ }
+
+ private void endRequestOnRequestScopeServices() {
+ // tell the proxy of all request-scoped services to invoke @PreDestroy
+ // (if any) on all underlying services stored on their thread-locals...
+ for (final Object service : servicesInjector.getRegisteredServices()) {
+ if(service instanceof RequestScopedService) {
+ ((RequestScopedService)service).__isis_preDestroy();
+ }
+ }
+
+ // ... and then remove those underlying services from the thread-local
+ for (final Object service : servicesInjector.getRegisteredServices()) {
+ if(service instanceof RequestScopedService) {
+ ((RequestScopedService)service).__isis_endRequest();
+ }
+ }
+ }
+
+ private void completeCommandFromInteractionAndClearDomainEvents() {
+
+ final Command command = commandContext.getCommand();
+ final Interaction interaction = interactionContext.getInteraction();
+
+ if(command.getStartedAt() != null && command.getCompletedAt() == null) {
+ // the guard is in case we're here as the result of a redirect following a previous exception;just ignore.
+
+
+ // copy over from the most recent (which will be the top-level) interaction
+ Interaction.Execution priorExecution = interaction.getPriorExecution();
+ final Timestamp completedAt = priorExecution.getCompletedAt();
+ command.setCompletedAt(completedAt);
+ }
+
+ // ensureCommandsPersistedIfDirtyXactn
+
+ // ensure that any changed objects means that the command should be persisted
+ if(command.getMemberIdentifier() != null) {
+ if(metricsService.numberObjectsDirtied() > 0) {
+ command.setPersistHint(true);
+ }
+ }
+
+
+ commandService.complete(command);
+
+ if(command instanceof Command3) {
+ final Command3 command3 = (Command3) command;
+ command3.flushActionDomainEvents();
+ } else
+ if(command instanceof Command2) {
+ final Command2 command2 = (Command2) command;
+ command2.flushActionInteractionEvents();
+ }
+
+ interaction.clear();
}
+
//endregion
//region > QuerySubmitter impl, findInstancesInTransaction
@@ -484,16 +630,8 @@ public class PersistenceSession implements
private State state;
- private State getState() {
- return state;
- }
-
- private void setState(final State state) {
- this.state = state;
- }
-
protected void ensureNotOpened() {
- if (getState() != State.NOT_INITIALIZED) {
+ if (state != State.NOT_INITIALIZED) {
throw new IllegalStateException("Persistence session has already been initialized");
}
}
@@ -510,7 +648,6 @@ public class PersistenceSession implements
}
-
//endregion
//region > createTransientInstance, createViewModelInstance
@@ -657,31 +794,15 @@ public class PersistenceSession implements
final List<Object> services = servicesInjector.getRegisteredServices();
final List<ObjectAdapter> serviceAdapters = Lists.newArrayList();
for (final Object servicePojo : services) {
- serviceAdapters.add(getService(servicePojo));
+ ObjectAdapter serviceAdapter = getAdapterFor(servicePojo);
+ if(serviceAdapter == null) {
+ throw new IllegalStateException("ObjectAdapter for service " + servicePojo + " does not exist?!?");
+ }
+ serviceAdapters.add(serviceAdapter);
}
return serviceAdapters;
}
- private ObjectAdapter getService(final Object servicePojo) {
- final ObjectSpecification serviceSpecification =
- specificationLoader.loadSpecification(servicePojo.getClass());
- final RootOid oid = getOidForService(serviceSpecification);
- final ObjectAdapter serviceAdapter = mapRecreatedPojo(oid, servicePojo);
-
- return serviceAdapter;
- }
-
- /**
- * Returns the OID for the adapted service. This allows a service object to
- * be given the same OID that it had when it was created in a different
- * session.
- */
- private RootOid getOidForService(final ObjectSpecification serviceSpec) {
- final ObjectSpecId serviceSpecId = serviceSpec.getSpecId();
- final RootOid oid = this.registeredServices.get(serviceSpecId);
- return oid;
- }
-
//endregion
//region > helper: postEvent
@@ -699,7 +820,6 @@ public class PersistenceSession implements
}
void postEvent(final AbstractLifecycleEvent<Object> event, final Object pojo) {
- final EventBusService eventBusService = getServicesInjector().lookupService(EventBusService.class);
event.setSource(pojo);
eventBusService.post(event);
}
@@ -851,7 +971,8 @@ public class PersistenceSession implements
result = persistenceManager.getObjectById(cls, jdoObjectId);
} catch (final RuntimeException e) {
- final List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+ Class<ExceptionRecognizer> serviceClass = ExceptionRecognizer.class;
+ final List<ExceptionRecognizer> exceptionRecognizers = lookupServices(serviceClass);
for (ExceptionRecognizer exceptionRecognizer : exceptionRecognizers) {
if(exceptionRecognizer instanceof ExceptionRecognizer2) {
final ExceptionRecognizer2 recognizer = (ExceptionRecognizer2) exceptionRecognizer;
@@ -1967,9 +2088,6 @@ public class PersistenceSession implements
public void enlistDeletingAndInvokeIsisRemovingCallbackFacet(final Persistable pojo) {
ObjectAdapter adapter = adapterFor(pojo);
- final ChangedObjectsServiceInternal changedObjectsServiceInternal =
- getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
changedObjectsServiceInternal.enlistDeleting(adapter);
CallbackFacet.Util.callCallback(adapter, RemovingCallbackFacet.class);
@@ -2159,10 +2277,6 @@ public class PersistenceSession implements
CallbackFacet.Util.callCallback(adapter, PersistedCallbackFacet.class);
postLifecycleEventIfRequired(adapter, PersistedLifecycleEventFacet.class);
-
- final ChangedObjectsServiceInternal changedObjectsServiceInternal =
- getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
changedObjectsServiceInternal.enlistCreated(adapter);
} else {
@@ -2207,10 +2321,6 @@ public class PersistenceSession implements
CallbackFacet.Util.callCallback(adapter, UpdatingCallbackFacet.class);
postLifecycleEventIfRequired(adapter, UpdatingLifecycleEventFacet.class);
-
- final ChangedObjectsServiceInternal changedObjectsServiceInternal =
- getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
changedObjectsServiceInternal.enlistUpdating(adapter);
ensureRootObject(pojo);
@@ -2275,6 +2385,25 @@ public class PersistenceSession implements
//endregion
+ //region > helpers: lookupService, lookupServices
+
+ private <T> T lookupService(Class<T> serviceType) {
+ T service = lookupServiceIfAny(serviceType);
+ if(service == null) {
+ throw new IllegalStateException("Could not locate service of type '" + serviceType + "'");
+ }
+ return service;
+ }
+
+ private <T> T lookupServiceIfAny(final Class<T> serviceType) {
+ return servicesInjector.lookupService(serviceType);
+ }
+
+ private <T> List<T> lookupServices(final Class<T> serviceClass) {
+ return servicesInjector.lookupServices(serviceClass);
+ }
+ //endregion
+
//region > toString
@Override
@@ -2285,6 +2414,8 @@ public class PersistenceSession implements
//endregion
+
+
}
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/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 516bcb6..98535f7 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
@@ -19,7 +19,6 @@
package org.apache.isis.core.runtime.system.transaction;
-import java.sql.Timestamp;
import java.util.List;
import java.util.UUID;
@@ -28,15 +27,6 @@ import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.isis.applib.annotation.Bulk;
-import org.apache.isis.applib.services.actinvoc.ActionInvocationContext;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.Command2;
-import org.apache.isis.applib.services.command.Command3;
-import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.InteractionContext;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.authentication.MessageBroker;
import org.apache.isis.core.commons.components.TransactionScopedComponent;
@@ -137,14 +127,6 @@ public class IsisTransaction implements TransactionScopedComponent {
/**
- * Whether it is valid to {@link IsisTransaction#flush() flush} this
- * {@link IsisTransaction transaction}.
- */
- public boolean canFlush() {
- return this == IN_PROGRESS;
- }
-
- /**
* Whether it is valid to {@link IsisTransaction#commit() commit} this
* {@link IsisTransaction transaction}.
*/
@@ -177,32 +159,24 @@ public class IsisTransaction implements TransactionScopedComponent {
}
}
-
private static final Logger LOG = LoggerFactory.getLogger(IsisTransaction.class);
+ //region > constructor, fields
+
private final List<PersistenceCommand> persistenceCommands = Lists.newArrayList();
private final IsisTransactionManager transactionManager;
private final MessageBroker messageBroker;
private final ServicesInjector servicesInjector;
- private final CommandContext commandContext;
- private final CommandService commandService;
-
- private final InteractionContext interactionContext;
private final PublishingServiceInternal publishingServiceInternal;
private final AuditingServiceInternal auditingServiceInternal;
private final ChangedObjectsServiceInternal changedObjectsServiceInternal;
-
private final UUID transactionId;
- private State state;
private IsisException abortCause;
-
-
-
public IsisTransaction(
final IsisTransactionManager transactionManager,
final MessageBroker messageBroker,
@@ -217,11 +191,6 @@ public class IsisTransaction implements TransactionScopedComponent {
this.messageBroker = messageBroker;
this.servicesInjector = servicesInjector;
- this.commandContext = lookupService(CommandContext.class);
- this.commandService = lookupService(CommandService.class);
-
- this.interactionContext = lookupService(InteractionContext.class);
-
this.publishingServiceInternal = lookupService(PublishingServiceInternal.class);
this.auditingServiceInternal = lookupService(AuditingServiceInternal.class);
this.changedObjectsServiceInternal = lookupService(ChangedObjectsServiceInternal.class);
@@ -236,19 +205,19 @@ public class IsisTransaction implements TransactionScopedComponent {
}
}
+ //endregion
- // ////////////////////////////////////////////////////////////////
- // GUID
- // ////////////////////////////////////////////////////////////////
+ //region > transactionId
public final UUID getTransactionId() {
return transactionId;
}
-
-
- // ////////////////////////////////////////////////////////////////
- // State
- // ////////////////////////////////////////////////////////////////
+
+ //endregion
+
+ //region > state
+
+ private State state;
public State getState() {
return state;
@@ -258,10 +227,10 @@ public class IsisTransaction implements TransactionScopedComponent {
this.state = state;
}
-
- // //////////////////////////////////////////////////////////
- // Commands
- // //////////////////////////////////////////////////////////
+ //endregion
+
+ //region > commands
+
/**
* Add the non-null command to the list of commands to execute at the end of
@@ -298,11 +267,41 @@ public class IsisTransaction implements TransactionScopedComponent {
persistenceCommands.add(command);
}
+ private boolean alreadyHasCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+ return getCommand(commandClass, onObject) != null;
+ }
+
+ private boolean alreadyHasCreate(final ObjectAdapter onObject) {
+ return alreadyHasCommand(CreateObjectCommand.class, onObject);
+ }
+
+ private boolean alreadyHasDestroy(final ObjectAdapter onObject) {
+ return alreadyHasCommand(DestroyObjectCommand.class, onObject);
+ }
+
+ private PersistenceCommand getCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+ for (final PersistenceCommand command : persistenceCommands) {
+ if (command.onAdapter().equals(onObject)) {
+ if (commandClass.isAssignableFrom(command.getClass())) {
+ return command;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void removeCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+ final PersistenceCommand toDelete = getCommand(commandClass, onObject);
+ persistenceCommands.remove(toDelete);
+ }
+ private void removeCreate(final ObjectAdapter onObject) {
+ removeCommand(CreateObjectCommand.class, onObject);
+ }
- // ////////////////////////////////////////////////////////////////
- // flush
- // ////////////////////////////////////////////////////////////////
+ //endregion
+
+ //region > flush
public synchronized final void flush() {
@@ -382,10 +381,9 @@ public class IsisTransaction implements TransactionScopedComponent {
}
+ //endregion
- // ////////////////////////////////////////////////////////////////
- // preCommit, commit
- // ////////////////////////////////////////////////////////////////
+ //region > preCommit, commit
synchronized void preCommit() {
ensureThatState(getState().canCommit(), is(true), "state is: " + getState());
@@ -403,68 +401,20 @@ public class IsisTransaction implements TransactionScopedComponent {
}
try {
- // ensureCommandsPersistedIfDirtyXactn
- final Command command = commandContext.getCommand();
-
- // ensure that any changed objects means that the command should be persisted
- final boolean hasChangedAdapters = changedObjectsServiceInternal.hasChangedAdapters();
- if(hasChangedAdapters && command.getMemberIdentifier() != null) {
- command.setPersistHint(true);
- }
-
auditingServiceInternal.audit();
publishingServiceInternal.publishObjects();
doFlush();
- final ActionInvocationContext actionInvocationContext = lookupService(ActionInvocationContext.class);
- if(actionInvocationContext != null) {
- Bulk.InteractionContext.current.set(null);
- }
-
- completeCommandAndInteractionAndClearDomainEvents();
- doFlush();
-
} catch (final RuntimeException ex) {
setAbortCause(new IsisTransactionManagerException(ex));
- completeCommandAndInteractionAndClearDomainEvents();
throw ex;
} finally {
changedObjectsServiceInternal.clearChangedObjectProperties();
}
}
- private void completeCommandAndInteractionAndClearDomainEvents() {
-
- final Command command = commandContext.getCommand();
- final Interaction interaction = interactionContext.getInteraction();
-
- if(command.getStartedAt() != null && command.getCompletedAt() == null) {
- // the guard is in case we're here as the result of a redirect following a previous exception;just ignore.
-
- // copy over from the most recent interaction
- Interaction.Execution priorExecution = interaction.getPriorExecution();
- final Timestamp completedAt = priorExecution.getCompletedAt();
- command.setCompletedAt(completedAt);
- }
-
- commandService.complete(command);
-
- if(command instanceof Command3) {
- final Command3 command3 = (Command3) command;
- command3.flushActionDomainEvents();
- } else
- if(command instanceof Command2) {
- final Command2 command2 = (Command2) command;
- command2.flushActionInteractionEvents();
- }
-
- interaction.clear();
- }
-
-
- // ////////////////////////////////////////////////////////////////
public synchronized void commit() {
ensureThatState(getState().canCommit(), is(true), "state is: " + getState());
@@ -485,12 +435,14 @@ public class IsisTransaction implements TransactionScopedComponent {
}
-
- // ////////////////////////////////////////////////////////////////
- // markAsAborted
- // ////////////////////////////////////////////////////////////////
+ //endregion
- public synchronized final void markAsAborted() {
+ //region > abortCause, markAsAborted
+
+ /**
+ * internal API called by IsisTransactionManager only
+ */
+ synchronized final void markAsAborted() {
ensureThatState(getState().canAbort(), is(true), "state is: " + getState());
if (LOG.isInfoEnabled()) {
LOG.info("abort transaction " + this);
@@ -499,12 +451,6 @@ public class IsisTransaction implements TransactionScopedComponent {
setState(State.ABORTED);
}
-
-
- /////////////////////////////////////////////////////////////////////////
- // handle exceptions on load, flush or commit
- /////////////////////////////////////////////////////////////////////////
-
/**
* Indicate that the transaction must be aborted, and that there is
@@ -532,63 +478,25 @@ public class IsisTransaction implements TransactionScopedComponent {
abortCause = null;
}
-
- // //////////////////////////////////////////////////////////
- // Helpers
- // //////////////////////////////////////////////////////////
- private boolean alreadyHasCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
- return getCommand(commandClass, onObject) != null;
- }
+ //endregion
- private boolean alreadyHasCreate(final ObjectAdapter onObject) {
- return alreadyHasCommand(CreateObjectCommand.class, onObject);
- }
-
- private boolean alreadyHasDestroy(final ObjectAdapter onObject) {
- return alreadyHasCommand(DestroyObjectCommand.class, onObject);
- }
-
- private PersistenceCommand getCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
- for (final PersistenceCommand command : persistenceCommands) {
- if (command.onAdapter().equals(onObject)) {
- if (commandClass.isAssignableFrom(command.getClass())) {
- return command;
- }
- }
- }
- return null;
- }
-
- private void removeCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
- final PersistenceCommand toDelete = getCommand(commandClass, onObject);
- persistenceCommands.remove(toDelete);
- }
-
- private void removeCreate(final ObjectAdapter onObject) {
- removeCommand(CreateObjectCommand.class, onObject);
- }
-
- // ////////////////////////////////////////////////////////////////
- // toString
- // ////////////////////////////////////////////////////////////////
+ //region > toString
@Override
public String toString() {
return appendTo(new ToString(this)).toString();
}
- protected ToString appendTo(final ToString str) {
+ private ToString appendTo(final ToString str) {
str.append("state", state);
str.append("commands", persistenceCommands.size());
return str;
}
+ //endregion
- // ////////////////////////////////////////////////////////////////
- // Depenendencies (from constructor)
- // ////////////////////////////////////////////////////////////////
-
+ //region > getMessageBroker
/**
* The {@link org.apache.isis.core.commons.authentication.MessageBroker} for this transaction.
@@ -602,11 +510,9 @@ public class IsisTransaction implements TransactionScopedComponent {
return messageBroker;
}
+ //endregion
- ////////////////////////////////////////////////////////////////////////
- // Dependencies (lookup)
- ////////////////////////////////////////////////////////////////////////
-
+ //region > helpers: lookupService etc
private <T> T lookupService(Class<T> serviceType) {
T service = lookupServiceIfAny(serviceType);
if(service == null) {
@@ -618,4 +524,9 @@ public class IsisTransaction implements TransactionScopedComponent {
private <T> T lookupServiceIfAny(final Class<T> serviceType) {
return servicesInjector.lookupService(serviceType);
}
+
+ //endregion
+
}
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/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 deb0072..6589cb0 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
@@ -19,22 +19,16 @@
package org.apache.isis.core.runtime.system.transaction;
-import java.sql.Timestamp;
-import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.isis.applib.annotation.Bulk;
-import org.apache.isis.applib.services.clock.ClockService;
import org.apache.isis.applib.services.command.Command;
import org.apache.isis.applib.services.command.CommandContext;
import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.iactn.Interaction;
import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.applib.services.user.UserService;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.authentication.MessageBroker;
import org.apache.isis.core.commons.components.SessionScopedComponent;
@@ -42,7 +36,6 @@ import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
import org.apache.isis.core.metamodel.services.ServicesInjector;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
-import org.apache.isis.core.runtime.services.RequestScopedService;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.core.runtime.system.session.IsisSession;
@@ -68,15 +61,9 @@ public class IsisTransactionManager implements SessionScopedComponent {
private final ServicesInjector servicesInjector;
- private final FactoryService factoryService;
private final CommandContext commandContext;
- private final CommandService commandService;
-
private final InteractionContext interactionContext;
- private final ClockService clockService;
- private final UserService userService;
-
// ////////////////////////////////////////////////////////////////
// constructor
@@ -89,14 +76,8 @@ public class IsisTransactionManager implements SessionScopedComponent {
this.persistenceSession = persistenceSession;
this.servicesInjector = servicesInjector;
- this.factoryService = lookupService(FactoryService.class);
this.commandContext = lookupService(CommandContext.class);
- this.commandService = lookupService(CommandService.class);
-
this.interactionContext = lookupService(InteractionContext.class);
-
- this.clockService = lookupService(ClockService.class);
- this.userService = lookupService(UserService.class);
}
public PersistenceSession getPersistenceSession() {
@@ -262,40 +243,29 @@ public class IsisTransactionManager implements SessionScopedComponent {
if (getTransaction() == null || getTransaction().getState().isComplete()) {
noneInProgress = true;
- startRequestOnRequestScopedServices();
+ // previously we called __isis_startRequest here on all RequestScopedServices. This is now
+ // done earlier, in PersistenceSession#open(). If we introduce support for @TransactionScoped
+ // services, then this would be the place to initialize them.
- // note that at this point there may not be an EventBusService initialized. The PersistenceSession has
- // logic to suppress the posting of the ObjectCreatedEvent for the special case of Command objects.
- final Command command;
- final UUID transactionId;
+ // allow the command to be overridden (if running as a background command with a parent command supplied)
+
+ final Interaction interaction = interactionContext.getInteraction();
+ final Command command;
if (existingCommandIfAny != null) {
- command = existingCommandIfAny;
- transactionId = command.getTransactionId();
- }
- else {
- command = createCommand();
- transactionId = UUID.randomUUID();
+ commandContext.setCommand(existingCommandIfAny);
+ interaction.setTransactionId(existingCommandIfAny.getTransactionId());
}
- final Interaction interaction = factoryService.instantiate(Interaction.class);
-
- initCommandAndInteraction(transactionId, command, interaction);
+ command = commandContext.getCommand();
+ final UUID transactionId = command.getTransactionId();
- commandContext.setCommand(command);
- interactionContext.setInteraction(interaction);
-
- initOtherApplibServicesIfConfigured();
final MessageBroker messageBroker = MessageBroker.acquire(getAuthenticationSession());
this.transaction = new IsisTransaction(this, messageBroker, servicesInjector, transactionId);
transactionLevel = 0;
persistenceSession.startTransaction();
-
- // a no-op; the command will have been populated already
- // in the earlier call to #createCommandAndInitAndSetAsContext(...).
- commandService.startTransaction(command, transactionId);
}
transactionLevel++;
@@ -305,80 +275,6 @@ public class IsisTransactionManager implements SessionScopedComponent {
}
}
- private void initOtherApplibServicesIfConfigured() {
-
- final Bulk.InteractionContext bic = lookupServiceIfAny(Bulk.InteractionContext.class);
- if(bic != null) {
- Bulk.InteractionContext.current.set(bic);
- }
- }
-
- private void startRequestOnRequestScopedServices() {
-
- final List<Object> registeredServices = servicesInjector.getRegisteredServices();
-
- // tell the proxy of all request-scoped services to instantiate the underlying
- // services, store onto the thread-local and inject into them...
- for (final Object service : registeredServices) {
- if(service instanceof RequestScopedService) {
- ((RequestScopedService)service).__isis_startRequest(servicesInjector);
- }
- }
- // ... and invoke all @PostConstruct
- for (final Object service : registeredServices) {
- if(service instanceof RequestScopedService) {
- ((RequestScopedService)service).__isis_postConstruct();
- }
- }
- }
-
- private void endRequestOnRequestScopeServices() {
- // tell the proxy of all request-scoped services to invoke @PreDestroy
- // (if any) on all underlying services stored on their thread-locals...
- for (final Object service : servicesInjector.getRegisteredServices()) {
- if(service instanceof RequestScopedService) {
- ((RequestScopedService)service).__isis_preDestroy();
- }
- }
-
- // ... and then remove those underlying services from the thread-local
- for (final Object service : servicesInjector.getRegisteredServices()) {
- if(service instanceof RequestScopedService) {
- ((RequestScopedService)service).__isis_endRequest();
- }
- }
- }
-
- private Command createCommand() {
- final Command command = commandService.create();
-
- servicesInjector.injectServicesInto(command);
- return command;
- }
-
- /**
- * Sets up {@link Command#getTransactionId()}, {@link Command#getUser()} and {@link Command#getTimestamp()}.
- *
- * The remaining properties are set further down the call-stack, if an action is actually performed
- * @param transactionId
- * @param interaction
- */
- private void initCommandAndInteraction(
- final UUID transactionId,
- final Command command,
- final Interaction interaction) {
-
- final Timestamp timestamp = clockService.nowAsJavaSqlTimestamp();
- final String userName = userService.getUser().getName();
-
- command.setTimestamp(timestamp);
- command.setUser(userName);
- command.setTransactionId(transactionId);
-
- interaction.setTransactionId(transactionId);
- }
-
-
// //////////////////////////////////////////////////////
// flush
// //////////////////////////////////////////////////////
@@ -498,9 +394,11 @@ public class IsisTransactionManager implements SessionScopedComponent {
transactionLevel = 1; // because the transactionLevel was decremented earlier
}
}
-
-
- endRequestOnRequestScopeServices();
+
+
+ // previously we called __isis_endRequest here on all RequestScopedServices. This is now
+ // done later, in PersistenceSession#close(). If we introduce support for @TransactionScoped
+ // services, then this would be the place to finalize them.
if(abortCause != null) {