All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vlingo.lattice.query.StateObjectQueryActor Maven / Gradle / Ivy

Go to download

Tooling for reactive Domain-Driven Design projects that are highly concurrent. Includes compute grid, actor caching, spaces, cross-node cluster messaging, CQRS, and Event Sourcing support.

There is a newer version: 1.7.5
Show newest version
// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.lattice.query;

import java.util.Collections;
import java.util.Optional;
import java.util.function.Function;

import io.vlingo.actors.Actor;
import io.vlingo.common.Completes;
import io.vlingo.common.Outcome;
import io.vlingo.lattice.model.CompletionTranslator;
import io.vlingo.lattice.query.QueryAttempt.Cardinality;
import io.vlingo.symbio.store.Result;
import io.vlingo.symbio.store.StorageException;
import io.vlingo.symbio.store.object.ObjectStore;
import io.vlingo.symbio.store.object.ObjectStoreReader.QueryMultiResults;
import io.vlingo.symbio.store.object.ObjectStoreReader.QueryResultInterest;
import io.vlingo.symbio.store.object.ObjectStoreReader.QuerySingleResult;
import io.vlingo.symbio.store.object.QueryExpression;

/**
 * An building-block {@code Actor} that queries asynchronously and provides a translated outcome.
 */
public abstract class StateObjectQueryActor extends Actor implements QueryResultInterest {
  private final ObjectStore objectStore;
  private final QueryResultInterest queryResultInterest;

  /**
   * Construct my state.
   * @param objectStore the ObjectStore the query
   */
  protected StateObjectQueryActor(final ObjectStore objectStore) {
    this.objectStore = objectStore;
    this.queryResultInterest = selfAs(QueryResultInterest.class);
  }

  /**
   * Answer {@code Optional} that should be thrown
   * and handled by my {@code Supervisor}, unless it is empty. The default
   * behavior is to answer the given {@code exception}, which will be thrown.
   * Must override to change default behavior.
   * @param exception the QueryFailedException
   * @return {@code Optional}
   */
  protected Optional afterQueryFailed(final ObjectQueryFailedException exception) {
    return Optional.of(exception);
  }

  /**
   * Answer the {@code Completes} through which the queried and translated result is provided.
   * @param stateObjectType the {@code Class} of the type of the translated result elements
   * @param query the QueryExpression used to execute the query
   * @param andThen the {@code Function} used to translate the O outcome to the R result
   * @return {@code Completes}
   * @param  the type of the StateObject being queried
   * @param  the type of the outcome of the query
   * @param  the final result, being a {@code List}
   */
  protected  Completes queryAll(
          final Class stateObjectType,
          final QueryExpression query,
          final Function andThen) {

    objectStore.queryAll(
            query,
            queryResultInterest,
            QueryAttempt.with(Cardinality.All, stateObjectType, query, CompletionTranslator.translatorOrNull(andThen, completesEventually())));

    return completes();
  }

  protected  Completes queryObject(
          final Class stateObjectType,
          final QueryExpression query,
          final Function andThen) {

    objectStore.queryObject(
            query,
            queryResultInterest,
            QueryAttempt.with(Cardinality.Object, stateObjectType, query, CompletionTranslator.translatorOrNull(andThen, completesEventually())));

    return completes();
  }

  /**
   * @see io.vlingo.symbio.store.object.ObjectStoreReader.QueryResultInterest#queryAllResultedIn(io.vlingo.common.Outcome, io.vlingo.symbio.store.object.ObjectStoreReader.QueryMultiResults, java.lang.Object)
   */
  @Override
  final public void queryAllResultedIn(
          final Outcome outcome,
          final QueryMultiResults queryResults,
          final Object attempt) {
    outcome
      .andThen(result -> {
        completeUsing(attempt, queryResults.stateObjects);
        return result;
      })
      .otherwise(cause -> {
        switch (cause.result) {
        case NotFound:
          completeUsing(attempt, Collections.emptyList());
          return cause.result;
        default:
          break;
        }
        final String message = "Query failed because: " + cause.result + " with: " + cause.getMessage();
        final ObjectQueryFailedException exception = new ObjectQueryFailedException(QueryAttempt.from(attempt), message, cause);
        final Optional maybeException = afterQueryFailed(exception);
        if (maybeException.isPresent()) {
          logger().error(message, maybeException.get());
          throw maybeException.get();
        }
        logger().error(message, exception);
        return cause.result;
      });
  }

  /*
   * @see io.vlingo.symbio.store.object.ObjectStoreReader.QueryResultInterest#queryObjectResultedIn(io.vlingo.common.Outcome, io.vlingo.symbio.store.object.ObjectStoreReader.QuerySingleResult, java.lang.Object)
   */
  @Override
  final public void queryObjectResultedIn(
          final Outcome outcome,
          final QuerySingleResult queryResult,
          final Object attempt) {
    outcome
      .andThen(result -> {
        completeUsing(attempt, queryResult.stateObject);
        return result;
      })
      .otherwise(cause -> {
        switch (cause.result) {
        case NotFound:
          completeUsing(attempt, queryResult.stateObject);
          return cause.result;
        default:
          break;
        }
        final String message = "Query failed because: " + cause.result + " with: " + cause.getMessage();
        final ObjectQueryFailedException exception = new ObjectQueryFailedException(QueryAttempt.from(attempt), message, cause);
        final Optional maybeException = afterQueryFailed(exception);
        if (maybeException.isPresent()) {
          logger().error(message, maybeException.get());
          throw maybeException.get();
        }
        logger().error(message, exception);
        return cause.result;
      });
  }

  /**
   * Dispatches to the {@code translator} to complete my protocol
   * message that answers an eventual outcome.
   * @param translator the Object that is cast to a {@code CompletionTranslator} and then completed
   * @param outcome the O outcome to be translated for completion
   * @param  the type of outcome
   */
  private  void completeUsing(final Object attempt, final O outcome) {
    if (attempt != null) {
      QueryAttempt.from(attempt).completionTranslator.complete(outcome);
    }
  }
}