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

com.shapestone.session.adapters.DynamoSessionRepository Maven / Gradle / Ivy

The newest version!
package com.shapestone.session.adapters;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.handlers.AsyncHandler;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClient;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.QueryResult;
import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
import com.shapestone.dynamo.*;
import com.shapestone.dynamo.util.DynamoClientData;
import com.shapestone.session.Session;
import com.shapestone.session.SessionRepository;
import org.slf4j.Logger;
import rx.Observable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.amazonaws.services.dynamodbv2.model.AttributeAction.PUT;
import static com.amazonaws.services.dynamodbv2.model.ComparisonOperator.EQ;
import static com.amazonaws.services.dynamodbv2.model.ComparisonOperator.GE;
import static com.amazonaws.services.dynamodbv2.model.ReturnValue.ALL_NEW;
import static com.shapestone.dynamo.util.IndexNameGenerator.createIndexName;
import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.slf4j.LoggerFactory.getLogger;
import static org.springframework.util.StringUtils.isEmpty;
import static rx.Observable.create;
import static rx.schedulers.Schedulers.io;

/**
 * Name: Michael Williams
 * Date: 9/11/16.
 */
public class DynamoSessionRepository implements SessionRepository {

  private static final Logger log = getLogger(DynamoSessionRepository.class.getName());

  private final AmazonDynamoDBAsyncClient asyncClient;

  private static DynamoSessionRepositoryData repositoryData = DefaultDynamoSessionRepositoryData.builder()
    .sessionIdCapacity(new Capacity(5, 5))
    .partyIdCapacity(new Capacity(5, 1))
    .modifiedDateCapacity(new Capacity(5, 1))
    .ownerPartyIdCapacity(new Capacity(5, 1))
    .build();

  private static final String SESSIONS = "sessions";

  //  private static final String PARTY_ID_MODIFIED_DATE_INDEX = "partyId-modifiedDate-index";

  private static final HashKey SESSION_ID = new HashKey("sessionId", "S");
  private static final HashKey PARTY_ID = new HashKey("partyId", "S");
  private static final NameType FINGER_PRINT = new NameType("fingerPrint", "S");
  private static final NameType IP_ADDRESS = new NameType("ipAddress", "S");
  private static final NameType LANGUAGE = new NameType("language", "S");
  private static final NameType USER_AGENT = new NameType("userAgent", "S");
  private static final HashKey OWNER_PARTY_ID = new HashKey("ownerPartyId", "S");
  private static final RangeKey MODIFIED_DATE = new RangeKey("modifiedDate", "N");
  private static final NameType CREATED_DATE = new NameType("createdDate", "N");

  public DynamoSessionRepository() {
    final ProfileCredentialsProvider profileCredentialsProvider = new ProfileCredentialsProvider();
    asyncClient = new AmazonDynamoDBAsyncClient(profileCredentialsProvider);
  }

  public DynamoSessionRepository(AWSCredentials awsCredentials) {
    asyncClient = new AmazonDynamoDBAsyncClient(awsCredentials);
  }

  public DynamoSessionRepository(DynamoClientData dynamoClientData) {
    this((AWSCredentials)dynamoClientData);
    if (dynamoClientData.isDatabaseLocal()) {
      this.asyncClient.withEndpoint(dynamoClientData.getDatabaseLocalEndPoint());
    }

    if (isNotEmpty(dynamoClientData.getRegion())) {
      this.asyncClient.withRegion(Regions.fromName(dynamoClientData.getRegion()));
    }
  }

  public DynamoSessionRepository(AWSCredentials awsCredentials, DynamoSessionRepositoryData repositoryData) {
    asyncClient = new AmazonDynamoDBAsyncClient(awsCredentials);
    DynamoSessionRepository.repositoryData = repositoryData;
  }

  public DynamoSessionRepository(DynamoClientData dynamoClientData, DynamoSessionRepositoryData repositoryData) {
    this(dynamoClientData);
    DynamoSessionRepository.repositoryData = repositoryData;
  }

  public static String getSessionsTableName() {
    return SESSIONS;
  }

  @SuppressWarnings("Duplicates")
  public static List getSessionColumnTypes() {
    final List nameTypes = new ArrayList<>();
    nameTypes.add(SESSION_ID);
    nameTypes.add(PARTY_ID);
    nameTypes.add(FINGER_PRINT);
    nameTypes.add(IP_ADDRESS);
    nameTypes.add(LANGUAGE);
    nameTypes.add(USER_AGENT);
    nameTypes.add(OWNER_PARTY_ID);
    nameTypes.add(MODIFIED_DATE);
    nameTypes.add(CREATED_DATE);
    return nameTypes;
  }

  public static TableIndex getSessionsTableIndex() {
    return TableIndex.builder()
        .partitionKey(new IndexKey(SESSION_ID, repositoryData.getSessionIdCapacity()))
        .firstGlobalIndexKey(new IndexKey(PARTY_ID, MODIFIED_DATE, repositoryData.getPartyIdCapacity()))
        .secondGlobalIndexKey(new IndexKey(OWNER_PARTY_ID, repositoryData.getOwnerPartyIdCapacity()))
        .build();
  }

  public static IndexKey getSessionTablePrimaryKey() {
    return new IndexKey(SESSION_ID, repositoryData.getSessionIdCapacity());
  }

  public Observable addSession(Session session) {
    //noinspection Duplicates
    final Observable storeObservable = create(subscriber -> {
      PutItemRequest request = new PutItemRequest()
        .withTableName(SESSIONS);

      request = addItemEntry(request, session);

      request.addExpectedEntry(SESSION_ID.getName(), new ExpectedAttributeValue(false));

      asyncClient.putItemAsync(request, new AsyncHandler() {
        @Override
        public void onError(Exception exception) {
          // Signal about the error to subscriber
          subscriber.onError(exception);

          // Signal about the completion subscriber;
          subscriber.onCompleted();

          log.error("Store Session Exception Caught: ", exception);
        }

        @Override
        public void onSuccess(PutItemRequest request, PutItemResult putItemResult) {
          // Pass on the data to subscriber
          subscriber.onNext(session);

          // Signal about the completion subscriber;
          subscriber.onCompleted();
        }
      });

    });

    return storeObservable.subscribeOn(io());
  }

  private PutItemRequest addItemEntry(PutItemRequest putItemRequest, Session session) {
    putItemRequest = putItemRequest.addItemEntry(SESSION_ID.getName(), new AttributeValue(session.getSessionId()));
    putItemRequest = putItemRequest.addItemEntry(PARTY_ID.getName(), new AttributeValue(session.getPartyId()));

    final String fingerPrint = session.getFingerPrint();
    if (!isEmpty(fingerPrint)) {
      putItemRequest = putItemRequest.addItemEntry(FINGER_PRINT.getName(), new AttributeValue(fingerPrint));
    }

    final String ipAddress = session.getIpAddress();
    if (!isEmpty(ipAddress)) {
      putItemRequest = putItemRequest.addItemEntry(IP_ADDRESS.getName(), new AttributeValue(ipAddress));
    }

    final String language = session.getLanguage();
    if (!isEmpty(language)) {
      putItemRequest = putItemRequest.addItemEntry(LANGUAGE.getName(), new AttributeValue(language));
    }

    final String userAgent = session.getUserAgent();
    if (!isEmpty(userAgent)) {
      putItemRequest = putItemRequest.addItemEntry(USER_AGENT.getName(), new AttributeValue(userAgent));
    }

    putItemRequest = putItemRequest.addItemEntry(OWNER_PARTY_ID.getName(), new AttributeValue(session.getCustomerPartyId()));

    putItemRequest = putItemRequest.addItemEntry(MODIFIED_DATE.getName(), new AttributeValue().withN(String.valueOf(session.getModifiedDate())));
    putItemRequest = putItemRequest.addItemEntry(CREATED_DATE.getName(), new AttributeValue().withN(String.valueOf(session.getCreatedDate())));

    return putItemRequest;
  }

  @Override
  public Observable> readSessionById(String sessionId) {
    final Observable> readSessionByIdObservable = create(subscriber -> {

      final Condition condition = new Condition()
        .withComparisonOperator(EQ)
        .withAttributeValueList(new AttributeValue(sessionId));

      final QueryRequest queryRequest = new QueryRequest(SESSIONS)
          .addKeyConditionsEntry(SESSION_ID.getName(), condition);

      //noinspection Duplicates
      this.asyncClient.queryAsync(queryRequest, new AsyncHandler() {

        @Override
        public void onError(Exception exception) {
          // Signal about the error to subscriber
          subscriber.onError(exception);

          // Signal about the completion subscriber;
          subscriber.onCompleted();
        }

        @Override
        public void onSuccess(QueryRequest request, QueryResult queryResult) {
          final List> items = queryResult.getItems();

          final List sessions = getSessions(items);

          // Pass on the data to subscriber
          subscriber.onNext(sessions);

          // Signal about the completion subscriber;
          subscriber.onCompleted();
        }

      });

    });

    return readSessionByIdObservable.subscribeOn(io());
  }

  private List getSessions(List> items) {
    final List sessions = new ArrayList<>();

    try {
      final Optional> first = items.stream().findFirst();

      if (first.isPresent()) {

        final Map stringAttributeValueMap = first.get();

        final Session session = getSession(stringAttributeValueMap);

        sessions.add(session);

      }
    } catch (Exception e) {
      log.error("Error converting item to \"Credential\":", e);
    }

    return sessions;
  }

  private Session getSession(Map stringAttributeValueMap) {
    final Session session = new Session();

    final AttributeValue sessionId = stringAttributeValueMap.get(SESSION_ID.getName());
    if (sessionId != null) {
      session.setSessionId(sessionId.getS());
    }

    final AttributeValue partyId = stringAttributeValueMap.get(PARTY_ID.getName());
    if (partyId != null) {
      session.setPartyId(partyId.getS());
    }

    final AttributeValue userAgent = stringAttributeValueMap.get(USER_AGENT.getName());
    if (userAgent != null) {
      session.setUserAgent(userAgent.getS());
    }

    final AttributeValue ipAddress = stringAttributeValueMap.get(IP_ADDRESS.getName());
    if (ipAddress != null) {
      session.setIpAddress(ipAddress.getS());
    }

    final AttributeValue language = stringAttributeValueMap.get(LANGUAGE.getName());
    if (language != null) {
      session.setLanguage(language.getS());
    }

    final AttributeValue fingerPrint = stringAttributeValueMap.get(FINGER_PRINT.getName());
    if (fingerPrint != null) {
      session.setFingerPrint(fingerPrint.getS());
    }

    final AttributeValue ownerPartyId = stringAttributeValueMap.get(OWNER_PARTY_ID.getName());
    if (ownerPartyId != null) {
      session.setCustomerPartyId(ownerPartyId.getS());
    }

    final AttributeValue modifiedDate = stringAttributeValueMap.get(MODIFIED_DATE.getName());
    if (modifiedDate != null) {
      session.setModifiedDate(Long.valueOf(modifiedDate.getN()));
    }

    final AttributeValue createdDate = stringAttributeValueMap.get(CREATED_DATE.getName());
    if (createdDate != null) {
      session.setCreatedDate(Long.valueOf(createdDate.getN()));
    }
    return session;
  }

  public Observable updateSession(Session session) {
    //noinspection Duplicates
    final Observable updateSessionObservable = create(subscriber -> {
        final String sessionId = session.getSessionId();
        final  UpdateItemRequest updateItemRequest = new UpdateItemRequest()
            .withTableName(SESSIONS)
            .withReturnValues(ALL_NEW)
            .addKeyEntry(SESSION_ID.getName(), new AttributeValue(sessionId))
            .addExpectedEntry(SESSION_ID.getName(), new ExpectedAttributeValue(true).withValue(new AttributeValue(sessionId)));

        final String userAgent = session.getUserAgent();
        if (!isEmpty(userAgent)) {
          updateItemRequest.addAttributeUpdatesEntry(
            USER_AGENT.getName(),
            new AttributeValueUpdate().withValue(new AttributeValue(userAgent)).withAction(PUT)
          );
        }

        final String ipAddress = session.getIpAddress();
        if (!isEmpty(ipAddress)) {
          updateItemRequest.addAttributeUpdatesEntry(
            IP_ADDRESS.getName(),
            new AttributeValueUpdate().withValue(new AttributeValue(ipAddress)).withAction(PUT)
          );
        }

        final String language = session.getLanguage();
        if (!isEmpty(language)) {
          updateItemRequest.addAttributeUpdatesEntry(
            LANGUAGE.getName(),
            new AttributeValueUpdate().withValue(new AttributeValue(language)).withAction(PUT)
          );
        }

        final String fingerPrint = session.getFingerPrint();
        if (!isEmpty(fingerPrint)) {
          updateItemRequest.addAttributeUpdatesEntry(
            FINGER_PRINT.getName(),
            new AttributeValueUpdate().withValue(new AttributeValue(fingerPrint)).withAction(PUT)
          );
        }

      final Long modifiedDate = session.getModifiedDate();
      updateItemRequest.addAttributeUpdatesEntry(
          MODIFIED_DATE.getName(),
          new AttributeValueUpdate().withValue(new AttributeValue().withN(String.valueOf(modifiedDate))).withAction(PUT)
        );

      //noinspection Duplicates
      asyncClient.updateItemAsync(updateItemRequest, new AsyncHandler() {
          @Override
          public void onError(Exception exception) {
            subscriber.onError(exception);
            subscriber.onCompleted();
            log.error("Update Session Exception Caught: ", exception);
          }

          @Override
          public void onSuccess(UpdateItemRequest request, UpdateItemResult updateItemResult) {
            final Map attributes = updateItemResult.getAttributes();
            final Session retSession = getSession(attributes);
            subscriber.onNext(retSession);
            subscriber.onCompleted();
          }
        });

    });

    return updateSessionObservable.subscribeOn(io());
  }

  @Override
  public Observable> readPartyActiveSessions(String partyId, long startTime) {
    final Observable> readSessionByPartyIdObservable = create(subscriber -> {

        final HashMap expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":partyId", new AttributeValue(partyId));
        expressionAttributeValues.put(":modifiedDate", new AttributeValue().withN(String.valueOf(startTime)));

        final QueryRequest queryRequest = new QueryRequest()
            .withTableName(SESSIONS)
            .withIndexName(createIndexName(PARTY_ID, MODIFIED_DATE))
            .withKeyConditionExpression("partyId=:partyId and modifiedDate >= :modifiedDate")
            .withExpressionAttributeValues(expressionAttributeValues);

        //noinspection Duplicates
        this.asyncClient.queryAsync(queryRequest, new AsyncHandler() {
          @Override
          public void onError(Exception exception) {
            // Signal about the error to subscriber
            subscriber.onError(exception);

            // Signal about the completion subscriber;
            subscriber.onCompleted();
          }

          @Override
          public void onSuccess(QueryRequest request, QueryResult queryResult) {
            final List> items = queryResult.getItems();

            final List credentialList = getSessions(items);

            subscriber.onNext(credentialList);

            // Signal about the completion subscriber;
            subscriber.onCompleted();
          }
        });

    });

    return readSessionByPartyIdObservable.subscribeOn(io());
  }

  @Override
  public Observable> readActiveSessions(String sessionId, long startTime) {
    final Observable> readSessionByPartyIdObservable = create(subscriber -> {

      final Condition condition = new Condition()
          .withComparisonOperator(EQ)
          .withAttributeValueList(new AttributeValue(sessionId));

      final Condition modifiedDateCondition = new Condition()
          .withComparisonOperator(GE)
          .withAttributeValueList(new AttributeValue().withN(String.valueOf(startTime)));

      final HashMap queryFilter = new HashMap<>();
      queryFilter.put(MODIFIED_DATE.getName(), modifiedDateCondition);

      final QueryRequest queryRequest = new QueryRequest()
          .withTableName(SESSIONS)
          .addKeyConditionsEntry(SESSION_ID.getName(), condition)
          .withQueryFilter(queryFilter);

      //noinspection Duplicates
      this.asyncClient.queryAsync(queryRequest, new AsyncHandler() {
        @Override
        public void onError(Exception exception) {
          // Signal about the error to subscriber
          subscriber.onError(exception);

          // Signal about the completion subscriber;
          subscriber.onCompleted();
        }

        @Override
        public void onSuccess(QueryRequest request, QueryResult queryResult) {
          final List> items = queryResult.getItems();

          final List credentialList = getSessions(items);

          subscriber.onNext(credentialList);

          // Signal about the completion subscriber;
          subscriber.onCompleted();
        }
      });

    });

    return readSessionByPartyIdObservable.subscribeOn(io());
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy