Package com.github.mrcritical.ironcache

Source Code of com.github.mrcritical.ironcache.DefaultIronCacheProvider

/**
*
*/
package com.github.mrcritical.ironcache;

import java.util.List;
import java.util.Locale;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import org.apache.http.annotation.ThreadSafe;
import org.joda.time.DateTime;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import com.github.mrcritical.ironcache.internal.http.ApacheHttpTransport;
import com.github.mrcritical.ironcache.internal.http.ResponseInitializer;
import com.github.mrcritical.ironcache.internal.model.CacheRequest;
import com.github.mrcritical.ironcache.internal.model.CacheResponse;
import com.github.mrcritical.ironcache.internal.model.Increment;
import com.github.mrcritical.ironcache.internal.model.requests.CacheItemUrl;
import com.github.mrcritical.ironcache.internal.model.requests.CacheUrl;
import com.github.mrcritical.ironcache.internal.model.requests.CachesUrl;
import com.github.mrcritical.ironcache.internal.model.requests.ClearCacheUrl;
import com.github.mrcritical.ironcache.internal.model.requests.IncrementCacheItemUrl;
import com.github.mrcritical.ironcache.internal.serializers.JodaDateTimeDeserializer;
import com.github.mrcritical.ironcache.internal.serializers.JodaDateTimeSerializer;
import com.github.mrcritical.ironcache.model.Cache;
import com.github.mrcritical.ironcache.model.CacheItemRequest;
import com.github.mrcritical.ironcache.model.CachedItem;
import com.github.mrcritical.ironcache.model.HTTPException;
import com.google.api.client.http.EmptyContent;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Strings;
import com.google.api.client.util.Throwables;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;

/**
* A implementation of the cache client that is to handle each project
* separately. The default hostname is "cache-aws-us-east-1". Unless you need to
* explicitly set a different hostname you can use the
* {@link #DefaultSimpleIronCache(String, String)} constructor.
*
* @author pjarrell
*
*/
@Slf4j
@ThreadSafe
public class DefaultIronCacheProvider implements IronCacheProvider {

  /**
   * Configures the ObjectMapper. Currently adds {@link AfterburnerModule} for
   * more speed and Joda date/time serializer/deserializers.
   *
   * @param json
   *            is the {@link ObjectMapper} to augment
   */
  protected static ObjectMapper configure(final ObjectMapper json) {
    final SimpleModule jodaModule = new SimpleModule("Joda");
    jodaModule.addSerializer(new JodaDateTimeSerializer());
    jodaModule.addDeserializer(DateTime.class, new JodaDateTimeDeserializer());
    json.registerModule(jodaModule);

    // Increase performance even more
    json.registerModule(new AfterburnerModule());
    return json;
  }

  private static final String DEFAULT_HOST_NAME = "cache-aws-us-east-1";

  private static HttpTransport httpTransport;

  private static final JsonFactory JSON_FACTORY = new JacksonFactory();

  private static ObjectMapper objectMapper;

  @Getter
  private final String hostName;

  @Getter
  private final String projectId;

  private final HttpRequestFactory requestFactory;

  @Getter(AccessLevel.PROTECTED)
  private final String token;

  /**
   * Create a new cache for the specified project using the default hostname
   * {@link #DEFAULT_HOST_NAME}.
   *
   * @param token
   *            is the authentication token to use
   * @param projectId
   *            is the project id this cache is configured for
   */
  public DefaultIronCacheProvider(final String token, final String projectId) {
    this(token, projectId, DEFAULT_HOST_NAME);
  }

  /**
   * Create a new cache for the specified project.
   *
   * @param token
   *            is the authentication token to use
   * @param projectId
   *            is the project id this cache is configured for
   * @param hostName
   *            is the hostname for the cache server
   *            (https://<hostName>.iron.io, only supply the <hostName> value
   *            in this argument)
   */
  public DefaultIronCacheProvider(final String token, final String projectId, final String hostName) {
    Preconditions.checkArgument(!Strings.isNullOrEmpty(projectId), "A valid project id is required");
    Preconditions.checkArgument(!Strings.isNullOrEmpty(token), "A valid token is required");
    Preconditions.checkArgument(!Strings.isNullOrEmpty(hostName), "A valid hostName is required");

    this.token = token;
    this.projectId = projectId;
    this.hostName = hostName;

    if (null == httpTransport) {
      DefaultIronCacheProvider.httpTransport = new ApacheHttpTransport();
    }

    if (null == objectMapper) {
      DefaultIronCacheProvider.objectMapper = configure(new ObjectMapper());
    }

    requestFactory = DefaultIronCacheProvider.httpTransport.createRequestFactory(new ResponseInitializer(token,
        JSON_FACTORY));
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#clearCache(java.lang.
   * String)
   */
  @Override
  public void clearCache(final String name) {
    try {

      final CacheResponse response = objectMapper.readValue(
          requestFactory.buildPostRequest(new ClearCacheUrl(hostName, projectId, name), new EmptyContent())
              .execute().getContent(), CacheResponse.class);

      validate(response, "cleared");

      log.debug("Successful request to clear to cache {}", name);

    } catch (final HTTPException e) {
      if (e.getStatusCode() == 301) {
        // Swallow this since that is what happens when cleared (it
        // isn't documented in the API spec)
        return;
      }
      throw Throwables.propagate(e);

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#deleteCache(java.lang
   * .String)
   */
  @Override
  public void deleteCache(final String name) {
    try {

      final CacheResponse response = objectMapper.readValue(
          requestFactory.buildDeleteRequest(new CacheUrl(hostName, projectId, name)).execute().getContent(),
          CacheResponse.class);

      validate(response, "deleted");

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#deleteItem(java.lang.
   * String, java.lang.String)
   */
  @Override
  public void deleteItem(final String name, final String key) {
    try {

      final CacheResponse response = objectMapper.readValue(
          requestFactory.buildDeleteRequest(new CacheItemUrl(hostName, projectId, name, key)).execute()
              .getContent(), CacheResponse.class);

      validate(response, "deleted");

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#getCache(java.lang.String
   * )
   */
  @Override
  public Optional<Cache> getCache(final String name) {
    try {

      return Optional.fromNullable(objectMapper.readValue(
          requestFactory.buildGetRequest(new CacheUrl(hostName, projectId, name)).execute().getContent(),
          Cache.class));

    } catch (final HTTPException e) {
      if (e.getStatusCode() == 404) {
        return Optional.absent();
      }
      throw Throwables.propagate(e);

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#getItem(java.lang.String,
   * java.lang.String)
   */
  @Override
  public Optional<CachedItem> getItem(final String name, final String key) {
    try {

      return Optional.fromNullable(objectMapper.readValue(
          requestFactory.buildGetRequest(new CacheItemUrl(hostName, projectId, name, key)).execute()
              .getContent(), CachedItem.class));

    } catch (final HTTPException e) {
      if (e.getStatusCode() == 404) {
        return Optional.absent();
      }
      throw Throwables.propagate(e);

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#incrementItem(java.lang
   * .String, java.lang.String, int)
   */
  @Override
  public void incrementItem(final String name, final String key, final int amount) {
    try {

      final CacheResponse response = objectMapper.readValue(
          requestFactory
              .buildPostRequest(new IncrementCacheItemUrl(hostName, projectId, name, key),
                  new JsonHttpContent(JSON_FACTORY, new Increment().amount(amount))).execute()
              .getContent(), CacheResponse.class);

      validate(response, "added");

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see com.github.mrcritical.ironcache.SimpleIronCache#listCaches()
   */
  @Override
  public List<Cache> listCaches() {
    try {

      return objectMapper.readValue(requestFactory.buildGetRequest(new CachesUrl(hostName, projectId)).execute()
          .getContent(), new TypeReference<List<Cache>>() {
      });

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.github.mrcritical.ironcache.SimpleIronCache#putItem(java.lang.String,
   * com.github.mrcritical.ironcache.model.CacheItemRequest)
   */
  @Override
  public void putItem(final String name, final CacheItemRequest request) {
    try {
      validate(request);
      final CacheRequest item = new CacheRequest().value(request.getValue()).cas(request.getCas())
          .expires(request.getExpireAfter());
      // .replace(request.getOnlyIfExists())
      // .add(request.getOnlyIfNotExists());

      final CacheResponse response = objectMapper.readValue(
          requestFactory
              .buildPutRequest(new CacheItemUrl(hostName, projectId, name, request.getKey()),
                  new JsonHttpContent(JSON_FACTORY, item)).execute().getContent(),
          CacheResponse.class);

      validate(response, "stored");

      log.debug("Successful request to add item {} with value {} to the cache {}", request.getKey(),
          request.getValue(), name);

    } catch (final Exception e) {
      throw Throwables.propagate(e);
    }
  }

  /**
   * Validates that the request being made is going to end up in a valid
   * request when processed on the server. This includes:
   *
   * <ul>
   * <li>Verifying that a key was provided that is not blank</li>
   * <li>Verifying that a NON-NULL value was provided</li>
   * <li>That {@link CacheItemRequest#getOnlyIfExists()} and
   * {@link CacheItemRequest#getOnlyIfNotExists()} are not both set (that
   * negate each other)</li>
   * <li>Verifying that any expiration provided is greater then 0</li>
   * </ul>
   *
   * @param request
   *            is the request to validate
   */
  private void validate(final CacheItemRequest request) {
    Preconditions.checkArgument(!Strings.isNullOrEmpty(request.getKey()), "A valid key must be supplied");
    Preconditions.checkArgument(null != request.getValue(),
        "A valid value must be supplied, it maybe an empty string");
    Preconditions.checkArgument(!(null != request.getOnlyIfExists() && null != request.getOnlyIfNotExists()),
        "Cannot specify both Only If Exists and Only If Not Exists. The two conditions negate each other.");
    Preconditions.checkArgument(
        null == request.getExpireAfter() || null != request.getExpireAfter() && request.getExpireAfter() > 0,
        "An expiration value must be greater then 0");
  }

  /**
   * Validates that the keyword expected was returned. Otherwise throws an
   * exception with the message returned included.
   *
   * @param response
   *            is the response to check
   * @param keyword
   *            is the keyword to expected
   */
  private void validate(final CacheResponse response, final String keyword) {
    if (!response.getMessage().toLowerCase(Locale.US).startsWith(keyword)) {
      throw new IllegalArgumentException(response.getMessage());
    }
  }

}
TOP

Related Classes of com.github.mrcritical.ironcache.DefaultIronCacheProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.