<commit_before>/**
 *  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.core.runtime.services.background;

import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;

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.annotation.DomainService;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.Programmatic;
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.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.applib.services.xactn.Transaction2;
import org.apache.isis.applib.services.xactn.TransactionService3;
import org.apache.isis.applib.services.xactn.TransactionState;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
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.metamodel.specloader.SpecificationLoader;
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.IsisSessionFactory;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
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.CollectionDto;
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.ValueDto;
import org.apache.isis.schema.common.v1.ValueType;
import org.apache.isis.schema.common.v1.ValueWithTypeDto;
import org.apache.isis.schema.utils.CommandDtoUtils;
import org.apache.isis.schema.utils.CommonDtoUtils;

@DomainService(nature = NatureOfService.DOMAIN)
public class CommandExecutorServiceDefault implements CommandExecutorService {

    private final static Logger LOG = LoggerFactory.getLogger(CommandExecutorServiceDefault.class);

    @Programmatic
    public void executeCommand(
            final CommandExecutorService.SudoPolicy sudoPolicy,
            final Command command) {

        // make sure that the service has been called with a 'in progress' transaction already set up
        ensureTransactionInProgress();

        switch (sudoPolicy) {
        case NO_SWITCH:
            executeCommand(command);
            break;
        case SWITCH:
            final String user = command.getUser();
            sudoService.sudo(user, new Runnable() {
                @Override
                public void run() {
                    executeCommand(command);
                }
            });
            break;
        default:
            throw new IllegalStateException("Probable framework error, unrecognized sudoPolicy: " + sudoPolicy);
        }

        // double check that we've ended up in the same state
        ensureTransactionInProgress();
    }

    private void ensureTransactionInProgress() {
        final Transaction2 currentTransaction = transactionService.currentTransaction();
        if(currentTransaction == null) {
            throw new IllegalStateException("No current transaction");
        }
        final TransactionState transactionState = currentTransaction.getTransactionState();
        if(!transactionState.canCommit()) {
            throw new IllegalStateException("Current transaction is not in a state to be committed, is: " + transactionState);
        }
    }

    protected void executeCommand(final Command command) {

        // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
        final Interaction interaction = 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;

        try {
            command.setExecutor(Command.Executor.BACKGROUND);

            // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or
            // 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.<commit_msg>ISIS-1569: adds more info to logging statement of CommandExecutorServiceDefault (xactnId and timestamp)<commit_after>/**
 *  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.core.runtime.services.background;

import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;

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.annotation.DomainService;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.Programmatic;
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.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.applib.services.xactn.Transaction2;
import org.apache.isis.applib.services.xactn.TransactionService3;
import org.apache.isis.applib.services.xactn.TransactionState;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
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.metamodel.specloader.SpecificationLoader;
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.IsisSessionFactory;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
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.CollectionDto;
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.ValueDto;
import org.apache.isis.schema.common.v1.ValueType;
import org.apache.isis.schema.common.v1.ValueWithTypeDto;
import org.apache.isis.schema.utils.CommandDtoUtils;
import org.apache.isis.schema.utils.CommonDtoUtils;

@DomainService(nature = NatureOfService.DOMAIN)
public class CommandExecutorServiceDefault implements CommandExecutorService {

    private final static Logger LOG = LoggerFactory.getLogger(CommandExecutorServiceDefault.class);

    @Programmatic
    public void executeCommand(
            final CommandExecutorService.SudoPolicy sudoPolicy,
            final Command command) {

        // make sure that the service has been called with a 'in progress' transaction already set up
        ensureTransactionInProgress();

        switch (sudoPolicy) {
        case NO_SWITCH:
            executeCommand(command);
            break;
        case SWITCH:
            final String user = command.getUser();
            sudoService.sudo(user, new Runnable() {
                @Override
                public void run() {
                    executeCommand(command);
                }
            });
            break;
        default:
            throw new IllegalStateException("Probable framework error, unrecognized sudoPolicy: " + sudoPolicy);
        }

        // double check that we've ended up in the same state
        ensureTransactionInProgress();
    }

    private void ensureTransactionInProgress() {
        final Transaction2 currentTransaction = transactionService.currentTransaction();
        if(currentTransaction == null) {
            throw new IllegalStateException("No current transaction");
        }
        final TransactionState transactionState = currentTransaction.getTransactionState();
        if(!transactionState.canCommit()) {
            throw new IllegalStateException("Current transaction is not in a state to be committed, is: " + transactionState);
        }
    }

    protected void executeCommand(final Command command) {

        // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
        final Interaction interaction = interactionContext.getInteraction();

        final String memento = command.getMemento();

        org.apache.isis.applib.annotation.Command.ExecuteIn executeIn = command.getExecuteIn();

        LOG.info("Executing: {} {} {} {}", executeIn, command.getMemberIdentifier(), command.getTimestamp(), command.getTransactionId());

        RuntimeException exceptionIfAny = null;

        try {
            command.setExecutor(Command.Executor.BACKGROUND);

            // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or
            // 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.
{'fraction_non_alphanumeric': 0.09078233927188226, 'fraction_numerical': 0.0038729666924864447, 'mean_word_length': 3.873914684786712, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5049685', 'n_tokens_mistral': 3683, 'n_tokens_neox': 3583, 'n_words': 828}