This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch maint-1.16.1 in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/maint-1.16.1 by this push: new 7585283 ISIS-1569: refactors for different implementation of replay 7585283 is described below commit 7585283a6b66f30960642bc0863052d4398fbaec Author: Dan Haywood <d...@haywood-associates.co.uk> AuthorDate: Fri Feb 2 16:21:22 2018 +0000 ISIS-1569: refactors for different implementation of replay specifically: - factors out CommandExecutionAbstract from BackgroundCommandExecution, and simplifies the latter (removes concept of an OnExceptionPolicy previously introduced) - Command#executeIn no longer overloaded to hold state (CommandJdo introduces replayState, not part of API) - introduces new CommandDtoProcessorService SPI to globally postprocess CommandDto's; dogfood this within ContentMappingServiceForCommandDto (copying over details) also - removes legacy support within BackgroundCommandExecution/CommandExecutionAbstract - made some methods of AbstractIsisSessionTemplate final - lets SimpleSession be subclassable - allows Clock to be replaceable always --- .../org/apache/isis/applib/annotation/Command.java | 10 +- .../java/org/apache/isis/applib/clock/Clock.java | 12 +- .../conmap/ContentMappingServiceForCommandDto.java | 102 ++-- .../ContentMappingServiceForCommandsDto.java | 7 +- .../conmap/spi/CommandDtoProcessorService.java | 38 ++ .../authentication/standard/SimpleSession.java | 2 +- .../background/BackgroundCommandExecution.java | 512 +-------------------- ...xecution.java => CommandExecutionAbstract.java} | 274 +++-------- .../AbstractIsisSessionTemplate.java | 8 +- 9 files changed, 195 insertions(+), 770 deletions(-) diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Command.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Command.java index 1defbbb..39cc97f 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Command.java +++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Command.java @@ -87,19 +87,11 @@ public @interface Command { * @deprecated - use {@link CommandExecuteIn#REPLAYABLE} */ @Deprecated - REPLAYABLE, - /** - * For framework use, not intended to be used in application code. - * - * @deprecated - use {@link CommandExecuteIn#EXCLUDED} - */ - @Deprecated - EXCLUDED; + REPLAYABLE; public boolean isForeground() { return this == FOREGROUND; } public boolean isBackground() { return this == BACKGROUND; } public boolean isReplayable() { return this == REPLAYABLE; } - public boolean isExcluded() { return this == EXCLUDED; } } diff --git a/core/applib/src/main/java/org/apache/isis/applib/clock/Clock.java b/core/applib/src/main/java/org/apache/isis/applib/clock/Clock.java index 90ae270..cd7c6c9 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/clock/Clock.java +++ b/core/applib/src/main/java/org/apache/isis/applib/clock/Clock.java @@ -29,7 +29,6 @@ import org.joda.time.LocalDate; import org.joda.time.LocalDateTime; import org.apache.isis.applib.Defaults; -import org.apache.isis.applib.RecoverableException; import org.apache.isis.applib.fixtures.FixtureClock; /** @@ -50,7 +49,6 @@ import org.apache.isis.applib.fixtures.FixtureClock; */ public abstract class Clock { protected static Clock instance; - private static boolean isReplaceable = true; /** * Returns the (singleton) instance of {@link Clock}. @@ -65,7 +63,6 @@ public abstract class Clock { public final static Clock getInstance() { if (!isInitialized()) { instance = new SystemClock(); - isReplaceable = false; } return instance; } @@ -126,11 +123,6 @@ public abstract class Clock { return new DateTime(getTime(), Defaults.getTimeZone()); } - private static void ensureReplaceable() { - if (!isReplaceable && instance != null) { - throw new RecoverableException("Clock already set up"); - } - } public static Timestamp getTimeAsJavaSqlTimestamp() { return new java.sql.Timestamp(getTimeAsDateTime().getMillis()); @@ -142,7 +134,6 @@ public abstract class Clock { * @return whether a clock was removed. */ protected static boolean remove() { - ensureReplaceable(); if (instance == null) { return false; } @@ -151,7 +142,6 @@ public abstract class Clock { } protected Clock() { - ensureReplaceable(); instance = this; } @@ -174,6 +164,8 @@ public abstract class Clock { } final class SystemClock extends Clock { + + SystemClock() {} @Override protected long time() { return System.currentTimeMillis(); diff --git a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java index a11b9d3..00f7541 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java +++ b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java @@ -27,7 +27,9 @@ import javax.ws.rs.core.MediaType; import org.apache.isis.applib.annotation.DomainService; import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.Programmatic; +import org.apache.isis.applib.conmap.spi.CommandDtoProcessorService; import org.apache.isis.applib.services.bookmark.Bookmark; +import org.apache.isis.applib.services.command.Command; import org.apache.isis.applib.services.command.CommandDtoProcessor; import org.apache.isis.applib.services.command.CommandWithDto; import org.apache.isis.applib.services.metamodel.MetaModelService5; @@ -49,7 +51,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService return null; } - return asProcessedDto(object, metaModelService); + return asProcessedDto(object); } /** @@ -57,27 +59,30 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService */ @Programmatic public CommandDto map(final CommandWithDto commandWithDto) { - return asProcessedDto(commandWithDto, metaModelService); + return asProcessedDto(commandWithDto); } - static CommandDto asProcessedDto( - final Object object, - final MetaModelService5 metaModelService) { - + CommandDto asProcessedDto(final Object object) { if (!(object instanceof CommandWithDto)) { return null; } final CommandWithDto commandWithDto = (CommandWithDto) object; - return asProcessedDto(commandWithDto, metaModelService); + return asProcessedDto(commandWithDto); } - private static CommandDto asProcessedDto( - CommandWithDto commandWithDto, - final MetaModelService5 metaModelService) { - final CommandDto commandDto = commandWithDto.asDto(); + private CommandDto asProcessedDto(final CommandWithDto commandWithDto) { + CommandDto commandDto = commandWithDto.asDto(); - copyOver(commandWithDto, commandDto); + // global processors + for (final CommandDtoProcessorService commandDtoProcessorService : commandDtoProcessorServices) { + commandDto = commandDtoProcessorService.process(commandWithDto, commandDto); + if(commandDto == null) { + // any processor could return null, effectively breaking the chain. + return null; + } + } + // specific processors for this specific member (action or property) final CommandDtoProcessor commandDtoProcessor = metaModelService.commandDtoProcessorFor(commandDto.getMember().getLogicalMemberIdentifier()); if (commandDtoProcessor == null) { @@ -86,39 +91,58 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService return commandDtoProcessor.process(commandWithDto, commandDto); } - private static void copyOver(final CommandWithDto commandWithDto, final CommandDto commandDto) { - // for some reason this isn't being persisted initially, so patch it in. TODO: should fix this - commandDto.setUser(commandWithDto.getUser()); + /** + * Uses the SPI infrastructure to copy over standard properties from {@link Command} to {@link CommandDto}. + */ + @DomainService( + nature = NatureOfService.DOMAIN, + // specify quite a high priority since custom processors will probably want to run after this one + // (but can choose to run before if they wish) + menuOrder = "1000" + ) + public static class CopyOverFromCommand implements CommandDtoProcessorService { + + public CommandDto process(final Command command, CommandDto commandDto) { + + // for some reason this isn't being persisted initially, so patch it in. TODO: should fix this + commandDto.setUser(command.getUser()); + + // the timestamp field was only introduced in v1.4 of cmd.xsd, so there's no guarantee + // it will have been populated. We therefore copy the value in from CommandWithDto entity. + if(commandDto.getTimestamp() == null) { + final Timestamp timestamp = command.getTimestamp(); + commandDto.setTimestamp(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp)); + } + + CommandDtoUtils.setUserData(commandDto, + CommandWithDto.USERDATA_KEY_TARGET_CLASS, command.getTargetClass()); + CommandDtoUtils.setUserData(commandDto, + CommandWithDto.USERDATA_KEY_TARGET_ACTION, command.getTargetAction()); + CommandDtoUtils.setUserData(commandDto, + CommandWithDto.USERDATA_KEY_ARGUMENTS, command.getArguments()); + + final Bookmark result = command.getResult(); + CommandDtoUtils.setUserData(commandDto, + CommandWithDto.USERDATA_KEY_RETURN_VALUE, result != null ? result.toString() : null); + // knowing whether there was an exception is on the master is used to determine whether to + // continue when replayed on the slave if an exception occurs there also + CommandDtoUtils.setUserData(commandDto, + CommandWithDto.USERDATA_KEY_EXCEPTION, command.getException()); + + PeriodDto timings = CommandDtoUtils.timingsFor(commandDto); + timings.setStartedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getStartedAt())); + timings.setCompletedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getCompletedAt())); - // the timestamp field was only introduced in v1.4 of cmd.xsd, so there's no guarantee - // it will have been populated. We therefore copy the value in from CommandWithDto entity. - if(commandDto.getTimestamp() == null) { - final Timestamp timestamp = commandWithDto.getTimestamp(); - commandDto.setTimestamp(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp)); + return commandDto; } - - CommandDtoUtils.setUserData(commandDto, - CommandWithDto.USERDATA_KEY_TARGET_CLASS, commandWithDto.getTargetClass()); - CommandDtoUtils.setUserData(commandDto, - CommandWithDto.USERDATA_KEY_TARGET_ACTION, commandWithDto.getTargetAction()); - CommandDtoUtils.setUserData(commandDto, - CommandWithDto.USERDATA_KEY_ARGUMENTS, commandWithDto.getArguments()); - - final Bookmark result = commandWithDto.getResult(); - CommandDtoUtils.setUserData(commandDto, - CommandWithDto.USERDATA_KEY_RETURN_VALUE, result != null ? result.toString() : null); - // knowing whether there was an exception is on the master is used to determine whether to - // continue when replayed on the slave if an exception occurs there also - CommandDtoUtils.setUserData(commandDto, - CommandWithDto.USERDATA_KEY_EXCEPTION, commandWithDto.getException()); - - PeriodDto timings = CommandDtoUtils.timingsFor(commandDto); - timings.setStartedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(commandWithDto.getStartedAt())); - timings.setCompletedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(commandWithDto.getCompletedAt())); } + @Inject MetaModelService5 metaModelService; + @Inject + List<CommandDtoProcessorService> commandDtoProcessorServices; + } diff --git a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java index 4ba434e..95ba22a 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java +++ b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java @@ -81,11 +81,14 @@ public class ContentMappingServiceForCommandsDto implements ContentMappingServic return new CommandsDto(); } - private static CommandDto asDto(final Object object, MetaModelService5 metaModelService5) { - return ContentMappingServiceForCommandDto.asProcessedDto(object, metaModelService5); + private CommandDto asDto(final Object object, MetaModelService5 metaModelService5) { + return contentMappingServiceForCommandDto.asProcessedDto(object); } @Inject MetaModelService5 metaModelService5; + @Inject + ContentMappingServiceForCommandDto contentMappingServiceForCommandDto; + } diff --git a/core/applib/src/main/java/org/apache/isis/applib/conmap/spi/CommandDtoProcessorService.java b/core/applib/src/main/java/org/apache/isis/applib/conmap/spi/CommandDtoProcessorService.java new file mode 100644 index 0000000..4fe8c69 --- /dev/null +++ b/core/applib/src/main/java/org/apache/isis/applib/conmap/spi/CommandDtoProcessorService.java @@ -0,0 +1,38 @@ +/* + * 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.applib.conmap.spi; + +import org.apache.isis.applib.annotation.Programmatic; +import org.apache.isis.applib.conmap.ContentMappingServiceForCommandDto; +import org.apache.isis.applib.services.command.Command; +import org.apache.isis.applib.services.command.CommandDtoProcessor; +import org.apache.isis.schema.cmd.v1.CommandDto; + +/** + * Optional SPI called by {@link ContentMappingServiceForCommandDto}. + * + * Similar to {@link CommandDtoProcessor}, but applied to all {@link CommandDto}s globally. + */ +public interface CommandDtoProcessorService { + + @Programmatic + CommandDto process(final Command command, CommandDto commandDto); + + +} diff --git a/core/metamodel/src/main/java/org/apache/isis/core/runtime/authentication/standard/SimpleSession.java b/core/metamodel/src/main/java/org/apache/isis/core/runtime/authentication/standard/SimpleSession.java index ca6e8c4..8e5c416 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/runtime/authentication/standard/SimpleSession.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/runtime/authentication/standard/SimpleSession.java @@ -26,7 +26,7 @@ import java.util.List; import org.apache.isis.core.commons.authentication.AuthenticationSessionAbstract; import org.apache.isis.core.commons.encoding.DataInputExtended; -public final class SimpleSession extends AuthenticationSessionAbstract { +public class SimpleSession extends AuthenticationSessionAbstract { private static final long serialVersionUID = 1L; diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java index 9127933..f42bd6c 100644 --- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java +++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java @@ -16,56 +16,17 @@ */ package org.apache.isis.core.runtime.services.background; -import java.sql.Timestamp; -import java.util.Collections; import java.util.List; -import java.util.concurrent.Callable; -import com.google.common.base.Function; -import com.google.common.base.Throwables; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.isis.applib.services.background.ActionInvocationMemento; -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.Command.Executor; -import org.apache.isis.applib.services.command.CommandWithDto; -import org.apache.isis.applib.services.iactn.Interaction; -import org.apache.isis.applib.services.iactn.InteractionContext; -import org.apache.isis.applib.services.jaxb.JaxbService; -import org.apache.isis.applib.services.sudo.SudoService; -import org.apache.isis.core.metamodel.adapter.ObjectAdapter; -import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy; -import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil; -import org.apache.isis.core.metamodel.spec.ObjectSpecification; -import org.apache.isis.core.metamodel.spec.feature.Contributed; -import org.apache.isis.core.metamodel.spec.feature.ObjectAction; -import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; -import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; -import org.apache.isis.core.runtime.services.memento.MementoServiceDefault; -import org.apache.isis.core.runtime.sessiontemplate.AbstractIsisSessionTemplate; import org.apache.isis.core.runtime.system.persistence.PersistenceSession; import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager; import org.apache.isis.core.runtime.system.transaction.TransactionalClosure; -import org.apache.isis.core.runtime.system.transaction.TransactionalClosureWithReturn; -import org.apache.isis.schema.cmd.v1.ActionDto; -import org.apache.isis.schema.cmd.v1.CommandDto; -import org.apache.isis.schema.cmd.v1.MemberDto; -import org.apache.isis.schema.cmd.v1.ParamDto; -import org.apache.isis.schema.cmd.v1.ParamsDto; -import org.apache.isis.schema.cmd.v1.PropertyDto; -import org.apache.isis.schema.common.v1.InteractionType; -import org.apache.isis.schema.common.v1.OidDto; -import org.apache.isis.schema.common.v1.OidsDto; -import org.apache.isis.schema.common.v1.ValueWithTypeDto; -import org.apache.isis.schema.utils.CommandDtoUtils; -import org.apache.isis.schema.utils.CommonDtoUtils; /** * Intended to be used as a base class for executing queued up {@link Command background action}s. @@ -74,55 +35,19 @@ import org.apache.isis.schema.utils.CommonDtoUtils; * This implementation uses the {@link #findBackgroundCommandsToExecute() hook method} so that it is * independent of the location where the actions have actually been persisted to. */ -public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemplate { +public abstract class BackgroundCommandExecution extends CommandExecutionAbstract { private final static Logger LOG = LoggerFactory.getLogger(BackgroundCommandExecution.class); - public enum OnExceptionPolicy { - /** - * For example, regular background commands. - */ - CONTINUE, - /** - * For example, replayable commands. - * - * To be precise, replay will quit only if there is an exception on the slave where there - * was none on the master. Put another way, a replicated command that failed on the master - * will not cause the slave to stop executing if it caused an exception. - */ - QUIT, - } - - public enum SudoPolicy { - /** - * For example, regular background commands. - */ - NO_SWITCH, - /** - * For example, replayable commands. - */ - SWITCH, - } - - private final MementoServiceDefault mementoService; - private final OnExceptionPolicy onExceptionPolicy; - private final SudoPolicy sudoPolicy; - /** * Defaults to the historical defaults * for running background commands. */ public BackgroundCommandExecution() { - this(OnExceptionPolicy.CONTINUE, SudoPolicy.NO_SWITCH); + this(SudoPolicy.NO_SWITCH); } - public BackgroundCommandExecution( - final OnExceptionPolicy onExceptionPolicy, - final SudoPolicy sudoPolicy) { - this.onExceptionPolicy = onExceptionPolicy; - this.sudoPolicy = sudoPolicy; - - // same as configured by BackgroundServiceDefault - mementoService = new MementoServiceDefault().withNoEncoding(); + public BackgroundCommandExecution(final SudoPolicy sudoPolicy) { + super(sudoPolicy); } // ////////////////////////////////////// @@ -140,15 +65,10 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp } }); - LOG.debug("{}: Found {} to execute", getClass().getName(), commands.size()); + LOG.debug("Found {} to execute", commands.size()); for (final Command command : commands) { - - final boolean shouldContinue = execute(transactionManager, command); - if(!shouldContinue) { - LOG.info("NOT continuing to process any further commands, quitting execution"); - return; - } + execute(transactionManager, command); } } @@ -157,425 +77,5 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp */ protected abstract List<? extends Command> findBackgroundCommandsToExecute(); - // ////////////////////////////////////// - - /** - * @return - whether to process any further commands. - */ - private boolean execute( - final IsisTransactionManager transactionManager, - final Command command) { - - try { - return executeCommandWithinTran(transactionManager, command); - } catch (final RuntimeException ex) { - - // attempting to commit the xactn itself could cause an issue - // so we need extra exception handling here, it seems. - - org.apache.isis.applib.annotation.Command.ExecuteIn executeIn = command.getExecuteIn(); - LOG.warn("Exception when committing for: {} {}", executeIn, command.getMemberIdentifier(), ex); - - // - // the previous transaction will have been aborted as part of the recovery handling within - // TransactionManager's executeCommandWithinTran - // - // we therefore start a new xactn in order to make sure that this background command is marked as a failure - // so it won't be attempted again. - // - transactionManager.executeWithinTransaction(new TransactionalClosure(){ - @Override - public void execute() { - - final Interaction backgroundInteraction = interactionContext.getInteraction(); - final Interaction.Execution currentExecution = backgroundInteraction.getCurrentExecution(); - command.setStartedAt( - currentExecution != null - ? currentExecution.getStartedAt() - : clockService.nowAsJavaSqlTimestamp()); - - command.setCompletedAt(clockService.nowAsJavaSqlTimestamp()); - command.setException(Throwables.getStackTraceAsString(ex)); - } - }); - - return determineIfContinue(ex); - } - } - - /** - * @return - whether to process any further commands. - */ - private Boolean executeCommandWithinTran( - final IsisTransactionManager transactionManager, - final Command command) { - - return transactionManager.executeWithinTransaction( - command, - new TransactionalClosureWithReturn<Boolean>() { - @Override - public Boolean execute() { - - return executeCommandPerSudoPolicy(transactionManager, command); - } - }); - } - - /** - * @return - whether to process any further commands. - */ - private Boolean executeCommandPerSudoPolicy( - final IsisTransactionManager transactionManager, - final Command command) { - - switch (sudoPolicy) { - case NO_SWITCH: - return executeCommand(transactionManager, command); - case SWITCH: - final String user = command.getUser(); - return sudoService.sudo(user, new Callable<Boolean>() { - @Override - public Boolean call() { - return executeCommand(transactionManager, command); - } - }); - default: - throw new IllegalStateException("Unrecognized sudoPolicy: " + sudoPolicy); - } - } - - /** - * Simply delegates to {@link #doExecuteCommand(IsisTransactionManager, Command)}. - * - * Overridable, so execution policy can be adjusted if required. - * - * @return - whether to process any further commands. - */ - protected Boolean executeCommand( - final IsisTransactionManager transactionManager, - final Command command) { - return doExecuteCommand(transactionManager, command); - } - - /** - * Not overrideable, but intended to be called by {@link #executeCommand(IsisTransactionManager, Command)} (which is). - * - * @return - whether to process any further commands. - */ - protected final Boolean doExecuteCommand( - final IsisTransactionManager transactionManager, - final Command command) { - - // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand - final Interaction backgroundInteraction = interactionContext.getInteraction(); - - final String memento = command.getMemento(); - - org.apache.isis.applib.annotation.Command.ExecuteIn executeIn = command.getExecuteIn(); - - LOG.info("Executing: {} {}", executeIn, command.getMemberIdentifier()); - - RuntimeException exceptionIfAny = null; - String origExceptionIfAny = null; - - try { - command.setExecutor(Executor.BACKGROUND); - - // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or - // PropertySetterFacet, but tthis is run if the domain object was found. If the domain object is - // thrown then we would have a command with only completedAt, which is inconsistent. - // Therefore instead we copy down from the backgroundInteraction (similar to how we populate the - // completedAt at the end) - final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution(); - - final Timestamp startedAt = priorExecution != null - ? priorExecution.getStartedAt() - : clockService.nowAsJavaSqlTimestamp(); - final Timestamp completedAt = - priorExecution != null - ? priorExecution.getCompletedAt() - : clockService.nowAsJavaSqlTimestamp(); // close enough... - - command.setStartedAt(startedAt); - command.setCompletedAt(completedAt); - - final boolean legacy = memento.startsWith("<memento"); - if(legacy) { - - final ActionInvocationMemento aim = new ActionInvocationMemento(mementoService, memento); - - final String actionId = aim.getActionId(); - - final Bookmark targetBookmark = aim.getTarget(); - final Object targetObject = bookmarkService.lookup( - targetBookmark, BookmarkService2.FieldResetPolicy.RESET); - - final ObjectAdapter targetAdapter = adapterFor(targetObject); - final ObjectSpecification specification = targetAdapter.getSpecification(); - - final ObjectAction objectAction = findActionElseNull(specification, actionId); - if(objectAction == null) { - throw new RuntimeException(String.format("Unknown action '%s'", actionId)); - } - - // TODO: background commands won't work for mixin actions... - // ... we obtain the target from the bookmark service (above), which will - // simply fail for a mixin. Instead we would need to serialize out the mixedInAdapter - // and also capture the mixinType within the aim memento. - final ObjectAdapter mixedInAdapter = null; - - final ObjectAdapter[] argAdapters = argAdaptersFor(aim); - final ObjectAdapter resultAdapter = objectAction.execute( - targetAdapter, mixedInAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK); - - if(resultAdapter != null) { - Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter); - command.setResult(resultBookmark); - backgroundInteraction.getCurrentExecution().setReturned(resultAdapter.getObject()); - } - - } else { - - final CommandDto dto = jaxbService.fromXml(CommandDto.class, memento); - - // if the command being executed was replayed, then in its userData it will holds - // details of any exception that might have occurred. - origExceptionIfAny = CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_EXCEPTION); - - final MemberDto memberDto = dto.getMember(); - final String memberId = memberDto.getMemberIdentifier(); - - final OidsDto oidsDto = CommandDtoUtils.targetsFor(dto); - final List<OidDto> targetOidDtos = oidsDto.getOid(); - - final InteractionType interactionType = memberDto.getInteractionType(); - if(interactionType == InteractionType.ACTION_INVOCATION) { - - final ActionDto actionDto = (ActionDto) memberDto; - - for (OidDto targetOidDto : targetOidDtos) { - - final ObjectAdapter targetAdapter = adapterFor(targetOidDto); - final ObjectAction objectAction = findObjectAction(targetAdapter, memberId); - - // we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then - // it will switch the targetAdapter to be the mixedInAdapter transparently - final ObjectAdapter[] argAdapters = argAdaptersFor(actionDto); - final ObjectAdapter resultAdapter = objectAction.execute( - targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK); - - // - // for the result adapter, we could alternatively have used... - // (priorExecution populated by the push/pop within the interaction object) - // - // final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution(); - // Object unused = priorExecution.getReturned(); - // - - // REVIEW: this doesn't really make sense if >1 action - // in any case, the capturing of the action interaction should be the - // responsibility of auditing/profiling - if(resultAdapter != null) { - Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter); - command.setResult(resultBookmark); - } - } - } else { - - final PropertyDto propertyDto = (PropertyDto) memberDto; - - for (OidDto targetOidDto : targetOidDtos) { - - final Bookmark bookmark = Bookmark.from(targetOidDto); - final Object targetObject = bookmarkService.lookup(bookmark); - - final ObjectAdapter targetAdapter = adapterFor(targetObject); - - final OneToOneAssociation property = findOneToOneAssociation(targetAdapter, memberId); - - final ObjectAdapter newValueAdapter = newValueAdapterFor(propertyDto); - - property.set(targetAdapter, newValueAdapter, InteractionInitiatedBy.FRAMEWORK); - // there is no return value for property modifications. - } - } - - } - - } catch (RuntimeException ex) { - - LOG.warn("Exception for: {} {}", executeIn, command.getMemberIdentifier(), ex); - - // hmmm, this doesn't really make sense if >1 action - // - // in any case, the capturing of the result of the action invocation should be the - // responsibility of the interaction... - command.setException(Throwables.getStackTraceAsString(ex)); - - // lower down the stack the IsisTransactionManager will have set the transaction to abort - // however, we don't want that to occur (because any changes made to the backgroundCommand itself - // would also be rolled back, and it would keep getting picked up again by a scheduler for - // processing); instead we clear the abort cause and ensure we can continue. - transactionManager.getCurrentTransaction().clearAbortCauseAndContinue(); - - // checked at the end - exceptionIfAny = ex; - - } - - // it's possible that there is no priorExecution, specifically if there was an exception - // invoking the action. We therefore need to guard that case. - final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution(); - final Timestamp completedAt = - priorExecution != null - ? priorExecution.getCompletedAt() - : clockService.nowAsJavaSqlTimestamp(); // close enough... - command.setCompletedAt(completedAt); - - // if we hit an exception processing this command but the master did not, then quit if instructed - return determineIfContinue(origExceptionIfAny, exceptionIfAny); - } - - private static ObjectAction findObjectAction( - final ObjectAdapter targetAdapter, - final String actionId) throws RuntimeException { - - final ObjectSpecification specification = targetAdapter.getSpecification(); - - final ObjectAction objectAction = findActionElseNull(specification, actionId); - if(objectAction == null) { - throw new RuntimeException(String.format("Unknown action '%s'", actionId)); - } - return objectAction; - } - - private static OneToOneAssociation findOneToOneAssociation( - final ObjectAdapter targetAdapter, - final String propertyId) throws RuntimeException { - - final ObjectSpecification specification = targetAdapter.getSpecification(); - - final OneToOneAssociation property = findOneToOneAssociationElseNull(specification, propertyId); - if(property == null) { - throw new RuntimeException(String.format("Unknown property '%s'", propertyId)); - } - return property; - } - - private boolean determineIfContinue( - final String origExceptionIfAny, - final RuntimeException exceptionIfAny) { - - if(origExceptionIfAny != null) { - return true; - } - - // there was no exception on master, so do we continue? - return determineIfContinue(exceptionIfAny); - } - - private boolean determineIfContinue(final RuntimeException exceptionIfAny) { - final boolean shouldQuit = exceptionIfAny != null && - onExceptionPolicy == OnExceptionPolicy.QUIT; - return !shouldQuit; - } - - private ObjectAdapter newValueAdapterFor(final PropertyDto propertyDto) { - final ValueWithTypeDto newValue = propertyDto.getNewValue(); - final Object arg = CommonDtoUtils.getValue(newValue); - return adapterFor(arg); - } - - private static ObjectAction findActionElseNull( - final ObjectSpecification specification, - final String actionId) { - final List<ObjectAction> objectActions = specification.getObjectActions(Contributed.INCLUDED); - for (final ObjectAction objectAction : objectActions) { - if(objectAction.getIdentifier().toClassAndNameIdentityString().equals(actionId)) { - return objectAction; - } - } - return null; - } - - private static OneToOneAssociation findOneToOneAssociationElseNull( - final ObjectSpecification specification, - final String propertyId) { - final List<ObjectAssociation> associations = specification.getAssociations(Contributed.INCLUDED); - for (final ObjectAssociation association : associations) { - if( association.getIdentifier().toClassAndNameIdentityString().equals(propertyId) && - association instanceof OneToOneAssociation) { - return (OneToOneAssociation) association; - } - } - return null; - } - - private ObjectAdapter[] argAdaptersFor(final ActionInvocationMemento aim) { - final int numArgs = aim.getNumArgs(); - final List<ObjectAdapter> argumentAdapters = Lists.newArrayList(); - for(int i=0; i<numArgs; i++) { - final ObjectAdapter argAdapter = argAdapterFor(aim, i); - argumentAdapters.add(argAdapter); - } - return argumentAdapters.toArray(new ObjectAdapter[]{}); - } - - private ObjectAdapter argAdapterFor(final ActionInvocationMemento aim, int num) { - final Class<?> argType; - try { - argType = aim.getArgType(num); - final Object arg = aim.getArg(num, argType); - if(arg == null) { - return null; - } - return adapterFor(arg); - - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - private ObjectAdapter[] argAdaptersFor(final ActionDto actionDto) { - final List<ParamDto> params = paramDtosFrom(actionDto); - final List<ObjectAdapter> args = Lists.newArrayList( - Iterables.transform(params, new Function<ParamDto, ObjectAdapter>() { - @Override - public ObjectAdapter apply(final ParamDto paramDto) { - final Object arg = CommonDtoUtils.getValue(paramDto); - return adapterFor(arg); - } - }) - ); - return args.toArray(new ObjectAdapter[]{}); - } - - private static List<ParamDto> paramDtosFrom(final ActionDto actionDto) { - final ParamsDto parameters = actionDto.getParameters(); - if (parameters != null) { - final List<ParamDto> parameterList = parameters.getParameter(); - if (parameterList != null) { - return parameterList; - } - } - return Collections.emptyList(); - } - - // ////////////////////////////////////// - - @javax.inject.Inject - BookmarkService2 bookmarkService; - - @javax.inject.Inject - JaxbService jaxbService; - - @javax.inject.Inject - InteractionContext interactionContext; - - @javax.inject.Inject - SudoService sudoService; - - @javax.inject.Inject - ClockService clockService; } diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutionAbstract.java similarity index 59% copy from core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java copy to core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutionAbstract.java index 9127933..188a9e2 100644 --- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java +++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutionAbstract.java @@ -35,7 +35,6 @@ 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.Command.Executor; -import org.apache.isis.applib.services.command.CommandWithDto; import org.apache.isis.applib.services.iactn.Interaction; import org.apache.isis.applib.services.iactn.InteractionContext; import org.apache.isis.applib.services.jaxb.JaxbService; @@ -48,9 +47,7 @@ import org.apache.isis.core.metamodel.spec.feature.Contributed; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; -import org.apache.isis.core.runtime.services.memento.MementoServiceDefault; import org.apache.isis.core.runtime.sessiontemplate.AbstractIsisSessionTemplate; -import org.apache.isis.core.runtime.system.persistence.PersistenceSession; import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager; import org.apache.isis.core.runtime.system.transaction.TransactionalClosure; import org.apache.isis.core.runtime.system.transaction.TransactionalClosureWithReturn; @@ -68,30 +65,10 @@ import org.apache.isis.schema.utils.CommandDtoUtils; import org.apache.isis.schema.utils.CommonDtoUtils; /** - * Intended to be used as a base class for executing queued up {@link Command background action}s. - * - * <p> - * This implementation uses the {@link #findBackgroundCommandsToExecute() hook method} so that it is - * independent of the location where the actions have actually been persisted to. */ -public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemplate { +public abstract class CommandExecutionAbstract extends AbstractIsisSessionTemplate { - private final static Logger LOG = LoggerFactory.getLogger(BackgroundCommandExecution.class); - - public enum OnExceptionPolicy { - /** - * For example, regular background commands. - */ - CONTINUE, - /** - * For example, replayable commands. - * - * To be precise, replay will quit only if there is an exception on the slave where there - * was none on the master. Put another way, a replicated command that failed on the master - * will not cause the slave to stop executing if it caused an exception. - */ - QUIT, - } + private final static Logger LOG = LoggerFactory.getLogger(CommandExecutionAbstract.class); public enum SudoPolicy { /** @@ -104,65 +81,30 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp SWITCH, } - private final MementoServiceDefault mementoService; - private final OnExceptionPolicy onExceptionPolicy; private final SudoPolicy sudoPolicy; - /** - * Defaults to the historical defaults * for running background commands. - */ - public BackgroundCommandExecution() { - this(OnExceptionPolicy.CONTINUE, SudoPolicy.NO_SWITCH); - } - - public BackgroundCommandExecution( - final OnExceptionPolicy onExceptionPolicy, - final SudoPolicy sudoPolicy) { - this.onExceptionPolicy = onExceptionPolicy; + protected CommandExecutionAbstract(final SudoPolicy sudoPolicy) { this.sudoPolicy = sudoPolicy; - - // same as configured by BackgroundServiceDefault - mementoService = new MementoServiceDefault().withNoEncoding(); - } - - // ////////////////////////////////////// - - - protected void doExecute(Object context) { - - final PersistenceSession persistenceSession = getPersistenceSession(); - final IsisTransactionManager transactionManager = getTransactionManager(persistenceSession); - final List<Command> commands = Lists.newArrayList(); - transactionManager.executeWithinTransaction(new TransactionalClosure() { - @Override - public void execute() { - commands.addAll(findBackgroundCommandsToExecute()); - } - }); - - LOG.debug("{}: Found {} to execute", getClass().getName(), commands.size()); - - for (final Command command : commands) { - - final boolean shouldContinue = execute(transactionManager, command); - if(!shouldContinue) { - LOG.info("NOT continuing to process any further commands, quitting execution"); - return; - } - } } - /** - * Mandatory hook method - */ - protected abstract List<? extends Command> findBackgroundCommandsToExecute(); - // ////////////////////////////////////// /** - * @return - whether to process any further commands. + * Executes the command within a transaction, and with respect to the specified {@link SudoPolicy} + * specified in the constructor. + * + * <p> + * Intended to be called from an override of {@link #doExecute(Object)}, + * not from {@link #doExecuteWithTransaction(Object)} (because the error handling is different). + * </p> + * + * <p> + * Subclasses can add additional policies (eg adjusting the clock) by overriding {@link #executeCommand(IsisTransactionManager, Command)} and delegating to {@link #doExecuteCommand(IsisTransactionManager, Command)} as required. + * </p> + * + * @return - any exception arising. We don't throw this exception, because an exception might be what is expected (eg if replaying a command that itself failed to execute). */ - private boolean execute( + protected final Exception execute( final IsisTransactionManager transactionManager, final Command command) { @@ -199,32 +141,26 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp } }); - return determineIfContinue(ex); + return ex; } } - /** - * @return - whether to process any further commands. - */ - private Boolean executeCommandWithinTran( + private Exception executeCommandWithinTran( final IsisTransactionManager transactionManager, final Command command) { return transactionManager.executeWithinTransaction( command, - new TransactionalClosureWithReturn<Boolean>() { + new TransactionalClosureWithReturn<Exception>() { @Override - public Boolean execute() { + public Exception execute() { return executeCommandPerSudoPolicy(transactionManager, command); } }); } - /** - * @return - whether to process any further commands. - */ - private Boolean executeCommandPerSudoPolicy( + private Exception executeCommandPerSudoPolicy( final IsisTransactionManager transactionManager, final Command command) { @@ -233,9 +169,9 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp return executeCommand(transactionManager, command); case SWITCH: final String user = command.getUser(); - return sudoService.sudo(user, new Callable<Boolean>() { + return sudoService.sudo(user, new Callable<Exception>() { @Override - public Boolean call() { + public Exception call() { return executeCommand(transactionManager, command); } }); @@ -247,22 +183,25 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp /** * Simply delegates to {@link #doExecuteCommand(IsisTransactionManager, Command)}. * - * Overridable, so execution policy can be adjusted if required. + * Overridable, so execution policy can be adjusted if required, + * eg when replaying, adjust the clock before executing the command. * - * @return - whether to process any further commands. + * @return - any exception arising */ - protected Boolean executeCommand( + protected Exception executeCommand( final IsisTransactionManager transactionManager, final Command command) { return doExecuteCommand(transactionManager, command); } /** - * Not overrideable, but intended to be called by {@link #executeCommand(IsisTransactionManager, Command)} (which is). + * Not overrideable, but intended to be called by + * {@link #executeCommand(IsisTransactionManager, Command)} (which is). * - * @return - whether to process any further commands. + * @return - any exception arising. We don't throw this exception, because an exception might be + * what is expected (eg if replaying a command that itself failed to execute). */ - protected final Boolean doExecuteCommand( + protected final Exception doExecuteCommand( final IsisTransactionManager transactionManager, final Command command) { @@ -276,13 +215,12 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp LOG.info("Executing: {} {}", executeIn, command.getMemberIdentifier()); RuntimeException exceptionIfAny = null; - String origExceptionIfAny = null; try { command.setExecutor(Executor.BACKGROUND); // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or - // PropertySetterFacet, but tthis is run if the domain object was found. If the domain object is + // PropertySetterFacet, but this is run if the domain object was found. If the domain object is // thrown then we would have a command with only completedAt, which is inconsistent. // Therefore instead we copy down from the backgroundInteraction (similar to how we populate the // completedAt at the end) @@ -299,107 +237,64 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp command.setStartedAt(startedAt); command.setCompletedAt(completedAt); - final boolean legacy = memento.startsWith("<memento"); - if(legacy) { - - final ActionInvocationMemento aim = new ActionInvocationMemento(mementoService, memento); - - final String actionId = aim.getActionId(); - - final Bookmark targetBookmark = aim.getTarget(); - final Object targetObject = bookmarkService.lookup( - targetBookmark, BookmarkService2.FieldResetPolicy.RESET); - - final ObjectAdapter targetAdapter = adapterFor(targetObject); - final ObjectSpecification specification = targetAdapter.getSpecification(); - - final ObjectAction objectAction = findActionElseNull(specification, actionId); - if(objectAction == null) { - throw new RuntimeException(String.format("Unknown action '%s'", actionId)); - } - - // TODO: background commands won't work for mixin actions... - // ... we obtain the target from the bookmark service (above), which will - // simply fail for a mixin. Instead we would need to serialize out the mixedInAdapter - // and also capture the mixinType within the aim memento. - final ObjectAdapter mixedInAdapter = null; - - final ObjectAdapter[] argAdapters = argAdaptersFor(aim); - final ObjectAdapter resultAdapter = objectAction.execute( - targetAdapter, mixedInAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK); - - if(resultAdapter != null) { - Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter); - command.setResult(resultBookmark); - backgroundInteraction.getCurrentExecution().setReturned(resultAdapter.getObject()); - } - - } else { - - final CommandDto dto = jaxbService.fromXml(CommandDto.class, memento); - - // if the command being executed was replayed, then in its userData it will holds - // details of any exception that might have occurred. - origExceptionIfAny = CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_EXCEPTION); + final CommandDto dto = jaxbService.fromXml(CommandDto.class, memento); - final MemberDto memberDto = dto.getMember(); - final String memberId = memberDto.getMemberIdentifier(); + final MemberDto memberDto = dto.getMember(); + final String memberId = memberDto.getMemberIdentifier(); - final OidsDto oidsDto = CommandDtoUtils.targetsFor(dto); - final List<OidDto> targetOidDtos = oidsDto.getOid(); + final OidsDto oidsDto = CommandDtoUtils.targetsFor(dto); + final List<OidDto> targetOidDtos = oidsDto.getOid(); - final InteractionType interactionType = memberDto.getInteractionType(); - if(interactionType == InteractionType.ACTION_INVOCATION) { + final InteractionType interactionType = memberDto.getInteractionType(); + if(interactionType == InteractionType.ACTION_INVOCATION) { - final ActionDto actionDto = (ActionDto) memberDto; + final ActionDto actionDto = (ActionDto) memberDto; - for (OidDto targetOidDto : targetOidDtos) { + for (OidDto targetOidDto : targetOidDtos) { - final ObjectAdapter targetAdapter = adapterFor(targetOidDto); - final ObjectAction objectAction = findObjectAction(targetAdapter, memberId); + final ObjectAdapter targetAdapter = adapterFor(targetOidDto); + final ObjectAction objectAction = findObjectAction(targetAdapter, memberId); - // we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then - // it will switch the targetAdapter to be the mixedInAdapter transparently - final ObjectAdapter[] argAdapters = argAdaptersFor(actionDto); - final ObjectAdapter resultAdapter = objectAction.execute( - targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK); + // we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then + // it will switch the targetAdapter to be the mixedInAdapter transparently + final ObjectAdapter[] argAdapters = argAdaptersFor(actionDto); + final ObjectAdapter resultAdapter = objectAction.execute( + targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK); - // - // for the result adapter, we could alternatively have used... - // (priorExecution populated by the push/pop within the interaction object) - // - // final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution(); - // Object unused = priorExecution.getReturned(); - // + // + // for the result adapter, we could alternatively have used... + // (priorExecution populated by the push/pop within the interaction object) + // + // final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution(); + // Object unused = priorExecution.getReturned(); + // - // REVIEW: this doesn't really make sense if >1 action - // in any case, the capturing of the action interaction should be the - // responsibility of auditing/profiling - if(resultAdapter != null) { - Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter); - command.setResult(resultBookmark); - } + // REVIEW: this doesn't really make sense if >1 action + // in any case, the capturing of the action interaction should be the + // responsibility of auditing/profiling + if(resultAdapter != null) { + Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter); + command.setResult(resultBookmark); } - } else { + } + } else { - final PropertyDto propertyDto = (PropertyDto) memberDto; + final PropertyDto propertyDto = (PropertyDto) memberDto; - for (OidDto targetOidDto : targetOidDtos) { + for (OidDto targetOidDto : targetOidDtos) { - final Bookmark bookmark = Bookmark.from(targetOidDto); - final Object targetObject = bookmarkService.lookup(bookmark); + final Bookmark bookmark = Bookmark.from(targetOidDto); + final Object targetObject = bookmarkService.lookup(bookmark); - final ObjectAdapter targetAdapter = adapterFor(targetObject); + final ObjectAdapter targetAdapter = adapterFor(targetObject); - final OneToOneAssociation property = findOneToOneAssociation(targetAdapter, memberId); + final OneToOneAssociation property = findOneToOneAssociation(targetAdapter, memberId); - final ObjectAdapter newValueAdapter = newValueAdapterFor(propertyDto); + final ObjectAdapter newValueAdapter = newValueAdapterFor(propertyDto); - property.set(targetAdapter, newValueAdapter, InteractionInitiatedBy.FRAMEWORK); - // there is no return value for property modifications. - } + property.set(targetAdapter, newValueAdapter, InteractionInitiatedBy.FRAMEWORK); + // there is no return value for property modifications. } - } } catch (RuntimeException ex) { @@ -432,8 +327,7 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp : clockService.nowAsJavaSqlTimestamp(); // close enough... command.setCompletedAt(completedAt); - // if we hit an exception processing this command but the master did not, then quit if instructed - return determineIfContinue(origExceptionIfAny, exceptionIfAny); + return exceptionIfAny; } private static ObjectAction findObjectAction( @@ -462,24 +356,6 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp return property; } - private boolean determineIfContinue( - final String origExceptionIfAny, - final RuntimeException exceptionIfAny) { - - if(origExceptionIfAny != null) { - return true; - } - - // there was no exception on master, so do we continue? - return determineIfContinue(exceptionIfAny); - } - - private boolean determineIfContinue(final RuntimeException exceptionIfAny) { - final boolean shouldQuit = exceptionIfAny != null && - onExceptionPolicy == OnExceptionPolicy.QUIT; - return !shouldQuit; - } - private ObjectAdapter newValueAdapterFor(final PropertyDto propertyDto) { final ValueWithTypeDto newValue = propertyDto.getNewValue(); final Object arg = CommonDtoUtils.getValue(newValue); diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/sessiontemplate/AbstractIsisSessionTemplate.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/sessiontemplate/AbstractIsisSessionTemplate.java index a554d7c..ac40524 100644 --- a/core/runtime/src/main/java/org/apache/isis/core/runtime/sessiontemplate/AbstractIsisSessionTemplate.java +++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/sessiontemplate/AbstractIsisSessionTemplate.java @@ -90,7 +90,7 @@ public abstract class AbstractIsisSessionTemplate { // ////////////////////////////////////// - protected ObjectAdapter adapterFor(final Object targetObject) { + protected final ObjectAdapter adapterFor(final Object targetObject) { if(targetObject instanceof OidDto) { final OidDto oidDto = (OidDto) targetObject; return adapterFor(oidDto); @@ -117,17 +117,17 @@ public abstract class AbstractIsisSessionTemplate { return getPersistenceSession().adapterFor(targetObject); } - protected ObjectAdapter adapterFor(final OidDto oidDto) { + protected final ObjectAdapter adapterFor(final OidDto oidDto) { final Bookmark bookmark = Bookmark.from(oidDto); return adapterFor(bookmark); } - protected ObjectAdapter adapterFor(final Bookmark bookmark) { + protected final ObjectAdapter adapterFor(final Bookmark bookmark) { final RootOid rootOid = RootOid.create(bookmark); return adapterFor(rootOid); } - protected ObjectAdapter adapterFor(final RootOid rootOid) { + protected final ObjectAdapter adapterFor(final RootOid rootOid) { return getPersistenceSession().adapterFor(rootOid); } -- To stop receiving notification emails like this one, please contact danhayw...@apache.org.