io.ignitr.dispatchr.manager.core.data.ClientRepository.java Source code

Java tutorial

Introduction

Here is the source code for io.ignitr.dispatchr.manager.core.data.ClientRepository.java

Source

/*
 * Copyright 2016 Greg Whitaker
 *
 * Licensed 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 io.ignitr.dispatchr.manager.core.data;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.AttributeUpdate;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.ScanOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.ScanSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.util.TableUtils;
import io.ignitr.dispatchr.manager.core.error.ClientAlreadyRegisteredException;
import io.ignitr.dispatchr.manager.core.error.ClientNotFoundException;
import io.ignitr.dispatchr.manager.domain.internal.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import rx.Observable;

import javax.annotation.PostConstruct;
import java.util.Arrays;

/**
 * Repository responsible for storing and retrieving information about Dispatchr clients in DynamoDB.
 */
@Component
public class ClientRepository {
    private static final Logger LOG = LoggerFactory.getLogger(ClientRepository.class);
    private static final String CLIENT_TABLE_NAME = "Dispatchr_Client";

    private final AmazonDynamoDBClient dynamoDBClient;
    private final DynamoDB dynamoDB;

    @Autowired
    public ClientRepository(AmazonDynamoDBClient dynamoDBClient) {
        this.dynamoDBClient = dynamoDBClient;
        this.dynamoDB = new DynamoDB(dynamoDBClient);
    }

    /**
     * Creates the DynamoDB tables that are used by this repository.
     *
     * @throws Exception
     */
    @PostConstruct
    private void initialize() throws Exception {
        LOG.info("Initializing DynamoDB tables for TopicRepository...");

        CreateTableRequest clientRequest = new CreateTableRequest(
                Arrays.asList(new AttributeDefinition("clientId", ScalarAttributeType.S)), CLIENT_TABLE_NAME,
                Arrays.asList(new KeySchemaElement("clientId", KeyType.HASH)), new ProvisionedThroughput(4L, 1L));

        if (TableUtils.createTableIfNotExists(dynamoDBClient, clientRequest)) {
            LOG.info("Creating DynamoDB table '{}'...", CLIENT_TABLE_NAME);
        } else {
            LOG.debug("DynamoDB table '{}' already exists!  Skipping table creation.", CLIENT_TABLE_NAME);
        }

        LOG.info("Waiting for DynamoDB table '{}' to become active...", CLIENT_TABLE_NAME);
        TableUtils.waitUntilActive(dynamoDBClient, CLIENT_TABLE_NAME);
        LOG.info("DynamoDB table '{}' is active", CLIENT_TABLE_NAME);
    }

    /**
     * Saves a new client in DynamoDB.
     *
     * @param clientId client identifier
     * @param ownerName name of the person who owns the client
     * @param ownerEmail email of the person who owns the client
     * @return an {@link Observable} that emits the newly saved client
     */
    public Observable<Client> save(String clientId, String ownerName, String ownerEmail) {
        return Observable.create(subscriber -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            if (clientTable.getItem("clientId", clientId) != null) {
                throw new ClientAlreadyRegisteredException(clientId);
            }

            Client client = new Client();
            client.setClientId(clientId);
            client.setOwnerName(ownerName);
            client.setOwnerEmail(ownerEmail);

            clientTable.putItem(new Item().withPrimaryKey("clientId", client.getClientId())
                    .withString("ownerName", client.getOwnerName())
                    .withString("ownerEmail", client.getOwnerEmail()));

            subscriber.onNext(client);
            subscriber.onCompleted();
        });
    }

    /**
     * Deletes a client from DynamoDB.
     *
     * @param clientId client identifier
     * @return an {@link Observable} that emits <code>true</code> if the delete was successful; otherwise <code>false</code>
     */
    public Observable<Boolean> delete(String clientId) {
        return findOne(clientId).flatMap(client -> Observable.create(subscriber -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            clientTable.deleteItem("clientId", client.getClientId());

            subscriber.onNext(true);
            subscriber.onCompleted();
        }));
    }

    /**
     * Finds all clients in DynamoDB.
     *
     * @param offset number of records to offset when paginating
     * @param limit number of records to return when paginating
     * @param sortDir the direction to sort returned records when paginating
     * @param active a boolean flag indicating whether or not to return only "active" clients
     * @return an {@link Observable} that emits all clients
     */
    public Observable<Client> findAll(long offset, long limit, String sortDir, boolean active) {
        return Observable.create(subscriber -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            ItemCollection<ScanOutcome> results = clientTable.scan(new ScanSpec());

            results.forEach(item -> subscriber.onNext(convertFromItem(item)));

            subscriber.onCompleted();
        });
    }

    /**
     * Finds a single client by id in DynamoDB.
     *
     * @param clientId client identifier
     * @return an {@link Observable} that emits the client
     */
    public Observable<Client> findOne(String clientId) {
        return Observable.create(subscriber -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            Item item = clientTable.getItem("clientId", clientId);

            if (item == null) {
                throw new ClientNotFoundException(clientId);
            } else {
                subscriber.onNext(convertFromItem(item));
                subscriber.onCompleted();
            }
        });
    }

    /**
     * Checks whether or not a client with the supplied id exists in DynamoDB.
     *
     * @param clientId client identifier
     * @return an {@link Observable} that emits <code>true</code> if the delete was successful; otherwise <code>false</code>
     */
    public Observable<Boolean> exists(String clientId) {
        return Observable.create(subscriber -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            Item item = clientTable.getItem("clientId", clientId);

            if (item == null) {
                subscriber.onNext(false);
            } else {
                subscriber.onNext(true);
            }

            subscriber.onCompleted();
        });
    }

    /**
     *
     * @param newClient
     * @return
     */
    public Observable<Client> update(Client newClient) {
        return findOne(newClient.getClientId()).last().map(oldClient -> {
            Table clientTable = dynamoDB.getTable(CLIENT_TABLE_NAME);

            UpdateItemOutcome outcome = clientTable
                    .updateItem(new UpdateItemSpec().withPrimaryKey("clientId", oldClient.getClientId())
                            .withAttributeUpdate(new AttributeUpdate("ownerName").put(newClient.getOwnerName()))
                            .withAttributeUpdate(new AttributeUpdate("ownerEmail").put(newClient.getOwnerEmail())));

            Item item = outcome.getItem();

            return convertFromItem(item);
        });
    }

    /**
     *
     * @param item
     * @return
     */
    public Client convertFromItem(Item item) {
        Client client = new Client();
        client.setClientId(item.getString("clientId"));
        client.setOwnerName(item.getString("ownerName"));
        client.setOwnerEmail(item.getString("ownerEmail"));

        return client;
    }
}