/*
 * Copyright 2017, 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.server.integration;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Message;
import io.spine.core.ExternalMessageEnvelope;
import io.spine.core.Rejection;
import io.spine.core.RejectionClass;
import io.spine.core.RejectionEnvelope;
import io.spine.server.reflect.RejectionSubscriberMethod;
import io.spine.server.rejection.RejectionSubscriber;
import io.spine.string.Stringifiers;
import io.spine.type.MessageClass;
import io.spine.util.Logging;
import org.slf4j.Logger;

import java.util.Objects;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.core.Rejections.isExternal;
import static io.spine.util.Exceptions.newIllegalStateException;
import static java.lang.String.format;

/**
 * A wrapper class, which exposes a {@link RejectionSubscriber}
 * as an {@link ExternalMessageDispatcher}.
 *
 * <p>Allows to register {@code RejectionSubscriber}s as dispatchers of
 * {@code IntegrationBus}.
 *
 * @author Alex Tymchenko
 */
class ExternalRejectionSubscriber implements ExternalMessageDispatcher<String> {

    /** Lazily initialized logger. */
    private final Supplier<Logger> loggerSupplier = Logging.supplyFor(getClass());

    private final RejectionSubscriber delegate;

    /**
     * Set of the external event classes this subscriber is subscribed to.
     */
    private final Set<RejectionClass> rejectionClasses;

    ExternalRejectionSubscriber(RejectionSubscriber delegate) {
        this.delegate = delegate;
        this.rejectionClasses = RejectionSubscriberMethod.inspectExternal(delegate.getClass());
    }

    @Override
    public Set<MessageClass> getMessageClasses() {
        return ImmutableSet.<MessageClass>copyOf(rejectionClasses);
    }

    @Override
    public Set<String> dispatch(ExternalMessageEnvelope envelope) {
        final Message outerObject = envelope.getOuterObject();
        if (!(outerObject instanceof Rejection)) {
            throw newIllegalStateException("Unexpected object %s while dispatching the external " +
                                                   "rejection to the rejection subscriber.",
                                           Stringifiers.toString(outerObject));
        }
        final Rejection rejection = (Rejection) outerObject;
        checkArgument(isExternal(rejection.getContext()),
                      "External rejection expected, but got %s",
                      Stringifiers.toString(rejection));
        return delegate.dispatch(RejectionEnvelope.of(rejection));
    }

    @Override
    public void onError(ExternalMessageEnvelope envelope, RuntimeException exception) {
        checkNotNull(envelope);
        checkNotNull(exception);

        final MessageClass messageClass = envelope.getMessageClass();
        final String messageId = Stringifiers.toString(envelope.getId());
        final String errorMessage =
                format("Error handling external rejection subscription (class: %s id: %s).",
                       messageClass, messageId);
        log().error(errorMessage, exception);
    }

    private Logger log() {
        return loggerSupplier.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ExternalRejectionSubscriber that = (ExternalRejectionSubscriber) o;
        return Objects.equals(delegate, that.delegate) &&
                Objects.equals(rejectionClasses, that.rejectionClasses);
    }

    @Override
    public int hashCode() {
        return Objects.hash(delegate, rejectionClasses);
    }
}

@@ -2440,13 +2440,17 @@
 nal 
-event
+rejection
  cla

Fix minor Javadoc copy-paste typo.