<commit_before>/*
 * Copyright 2018, TeamDev Ltd. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.core;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.protobuf.Duration;
import com.google.protobuf.Message;
import com.google.protobuf.Timestamp;
import io.spine.Identifier;
import io.spine.annotation.Internal;
import io.spine.base.ThrowableMessage;
import io.spine.protobuf.AnyPacker;
import io.spine.string.Stringifier;
import io.spine.string.StringifierRegistry;
import io.spine.time.Timestamps2;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.Identifier.EMPTY_ID;
import static io.spine.core.CommandContext.Schedule;
import static io.spine.validate.Validate.isNotDefault;

/**
 * Client-side utilities for working with commands.
 *
 * @author <NAME>
 */
public final class Commands {

    private static final Stringifier<CommandId> idStringifier = new CommandIdStringifier();

    static {
        StringifierRegistry.getInstance()
                           .register(idStringifier(), CommandId.class);
    }

    private Commands() {
        // Prevent instantiation of this utility class.
    }

    /**
     * Creates a new {@link CommandId} based on random UUID.
     *
     * @return new command ID
     */
    public static CommandId generateId() {
        final String value = UUID.randomUUID()
                                 .toString();
        return CommandId.newBuilder()
                        .setUuid(value)
                        .build();
    }

    /**
     * Extracts the message from the passed {@code Command} instance.
     *
     * @param command a command to extract a message from
     * @param <M>     a type of the command message
     * @return an unpacked message
     */
    public static <M extends Message> M getMessage(Command command) {
        checkNotNull(command);
        final M result = AnyPacker.unpack(command.getMessage());
        return result;
    }

    /**
     * Extracts a command message if the passed instance is a {@link Command} object or
     * {@link com.google.protobuf.Any Any}, otherwise returns the passed message.
     */
    public static Message ensureMessage(Message commandOrMessage) {
        checkNotNull(commandOrMessage);
        if (commandOrMessage instanceof Command) {
            return getMessage((Command) commandOrMessage);
        }
        return io.spine.protobuf.Messages.ensureMessage(commandOrMessage);
    }

    /**
     * Obtains a tenant ID from the command.
     */
    public static TenantId getTenantId(Command command) {
        checkNotNull(command);
        final TenantId result = getTenantId(command.getContext());
        return result;
    }

    /**
     * Obtains a {@link TenantId} from the given {@link Event}.
     *
     * <p>The {@code TenantId} is retrieved by traversing the passed {@code Event}s context. It is
     * stored in the initial {@link CommandContext} and can be retrieved from the events origin 
     * command or rejection context. 
     */
    @Internal
    public static TenantId getTenantId(Event event) {
        checkNotNull(event);

        final Optional<CommandContext> commandContext = getCommandContext(event);

        if (!commandContext.isPresent()) {
            return TenantId.getDefaultInstance();
        }

        final TenantId result = getTenantId(commandContext.get());
        return result;
    }

    /**
     * Obtains a {@link TenantId} from the {@link CommandContext}.
     *
     * <p>The {@link CommandContext} is accessible from the {@link Event} if the {@code Event} was 
     * created as a result of some command or its rejection. This makes the {@code CommandContext}
     * a valid {@code TenantId} source inside of the {@code Event}.
     */
    private static TenantId getTenantId(CommandContext context) {
        return context.getActorContext()
                      .getTenantId();
    }

    /**
     * Obtains a context of the command, which lead to this event.
     *
     * <p> The context is obtained by traversing the events origin for a valid context source. 
     * There are can be two sources for the command context:
     * <ol>
     *     <li>The command context set as the event origin.</li>
     *     <li>The command set as a rejection property.</li>
     * </ol>
     *
     * <p>If at some point the event origin is not set the {@link Optional#absent()} is returned.
     */
    private static Optional<CommandContext> getCommandContext(Event event) {
        CommandContext commandContext = null;
        EventContext eventContext = event.getContext();

        while (commandContext == null) {

            switch (eventContext.getOriginCase()) {

                case EVENT_CONTEXT:
                    eventContext = eventContext.getEventContext();
                    break;

                case COMMAND_CONTEXT:
                    commandContext = eventContext.getCommandContext();
                    break;

                case REJECTION_CONTEXT:
                    commandContext = eventContext.getRejectionContext()
                                                 .getCommand()
                                                 .getContext();
                    break;<commit_msg>Rename getCommandContext to getOriginCommandContext.<commit_after>/*
 * Copyright 2018, TeamDev Ltd. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.core;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.protobuf.Duration;
import com.google.protobuf.Message;
import com.google.protobuf.Timestamp;
import io.spine.Identifier;
import io.spine.annotation.Internal;
import io.spine.base.ThrowableMessage;
import io.spine.protobuf.AnyPacker;
import io.spine.string.Stringifier;
import io.spine.string.StringifierRegistry;
import io.spine.time.Timestamps2;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.Identifier.EMPTY_ID;
import static io.spine.core.CommandContext.Schedule;
import static io.spine.validate.Validate.isNotDefault;

/**
 * Client-side utilities for working with commands.
 *
 * @author <NAME>
 */
public final class Commands {

    private static final Stringifier<CommandId> idStringifier = new CommandIdStringifier();

    static {
        StringifierRegistry.getInstance()
                           .register(idStringifier(), CommandId.class);
    }

    private Commands() {
        // Prevent instantiation of this utility class.
    }

    /**
     * Creates a new {@link CommandId} based on random UUID.
     *
     * @return new command ID
     */
    public static CommandId generateId() {
        final String value = UUID.randomUUID()
                                 .toString();
        return CommandId.newBuilder()
                        .setUuid(value)
                        .build();
    }

    /**
     * Extracts the message from the passed {@code Command} instance.
     *
     * @param command a command to extract a message from
     * @param <M>     a type of the command message
     * @return an unpacked message
     */
    public static <M extends Message> M getMessage(Command command) {
        checkNotNull(command);
        final M result = AnyPacker.unpack(command.getMessage());
        return result;
    }

    /**
     * Extracts a command message if the passed instance is a {@link Command} object or
     * {@link com.google.protobuf.Any Any}, otherwise returns the passed message.
     */
    public static Message ensureMessage(Message commandOrMessage) {
        checkNotNull(commandOrMessage);
        if (commandOrMessage instanceof Command) {
            return getMessage((Command) commandOrMessage);
        }
        return io.spine.protobuf.Messages.ensureMessage(commandOrMessage);
    }

    /**
     * Obtains a tenant ID from the command.
     */
    public static TenantId getTenantId(Command command) {
        checkNotNull(command);
        final TenantId result = getTenantId(command.getContext());
        return result;
    }

    /**
     * Obtains a {@link TenantId} from the given {@link Event}.
     *
     * <p>The {@code TenantId} is retrieved by traversing the passed {@code Event}s context. It is
     * stored in the initial {@link CommandContext} and can be retrieved from the events origin 
     * command or rejection context. 
     */
    @Internal
    public static TenantId getTenantId(Event event) {
        checkNotNull(event);

        final Optional<CommandContext> commandContext = getOriginCommandContext(event);

        if (!commandContext.isPresent()) {
            return TenantId.getDefaultInstance();
        }

        final TenantId result = getTenantId(commandContext.get());
        return result;
    }

    /**
     * Obtains a {@link TenantId} from the {@link CommandContext}.
     *
     * <p>The {@link CommandContext} is accessible from the {@link Event} if the {@code Event} was 
     * created as a result of some command or its rejection. This makes the {@code CommandContext}
     * a valid {@code TenantId} source inside of the {@code Event}.
     */
    private static TenantId getTenantId(CommandContext context) {
        return context.getActorContext()
                      .getTenantId();
    }

    /**
     * Obtains a context of the command, which lead to this event.
     *
     * <p> The context is obtained by traversing the events origin for a valid context source. 
     * There are can be two sources for the command context:
     * <ol>
     *     <li>The command context set as the event origin.</li>
     *     <li>The command set as a rejection property.</li>
     * </ol>
     *
     * <p>If at some point the event origin is not set the {@link Optional#absent()} is returned.
     */
    private static Optional<CommandContext> getOriginCommandContext(Event event) {
        CommandContext commandContext = null;
        EventContext eventContext = event.getContext();

        while (commandContext == null) {

            switch (eventContext.getOriginCase()) {

                case EVENT_CONTEXT:
                    eventContext = eventContext.getEventContext();
                    break;

                case COMMAND_CONTEXT:
                    commandContext = eventContext.getCommandContext();
                    break;

                case REJECTION_CONTEXT:
                    commandContext = eventContext.getRejectionContext()
                                                 .getCommand()
                                                 .getContext();
                    break;
{'fraction_non_alphanumeric': 0.08309675439269547, 'fraction_numerical': 0.0007672830507174097, 'mean_word_length': 2.5975710736958324, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6430869', 'n_tokens_mistral': 3418, 'n_tokens_neox': 3250, 'n_words': 1152}