package com.netflix.evcache.service.resources; import com.google.inject.Inject; import com.google.inject.Singleton; import com.netflix.evcache.EVCache; import com.netflix.evcache.EVCacheException; import com.netflix.evcache.EVCacheLatch; import com.netflix.evcache.EVCacheLatch.Policy; import com.netflix.evcache.service.transcoder.RESTServiceTranscoder; import net.spy.memcached.CachedData; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Created by senugula on 3/22/16. */ @Singleton @Path("/evcrest/v1.0") public class EVCacheRESTService { private static final Logger logger = LoggerFactory.getLogger(EVCacheRESTService.class); private final EVCache.Builder builder; private final Map<String, EVCache> evCacheMap; private final RESTServiceTranscoder evcacheTranscoder = new RESTServiceTranscoder(); @Inject public EVCacheRESTService(EVCache.Builder builder) { this.builder = builder; this.evCacheMap = new HashMap<>(); } @POST @Path("{appId}/{key}") @Consumes({MediaType.APPLICATION_OCTET_STREAM}) @Produces(MediaType.TEXT_PLAIN) public Response setOperation(final InputStream in, @PathParam("appId") String pAppId, @PathParam("key") String key, @QueryParam("ttl") String ttl, @DefaultValue("") @QueryParam("flag") String flag) { try { final String appId = pAppId.toUpperCase(); final byte[] bytes = IOUtils.toByteArray(in); return setData(appId, ttl, flag, key, bytes); } catch (EVCacheException e) { e.printStackTrace(); return Response.serverError().build(); } catch (Throwable t) { return Response.serverError().build(); } } @PUT @Path("{appId}/{key}") @Consumes({MediaType.APPLICATION_OCTET_STREAM}) @Produces(MediaType.TEXT_PLAIN) public Response putOperation(final InputStream in, @PathParam("appId") String pAppId, @PathParam("key") String key, @QueryParam("ttl") String ttl, @DefaultValue("") @QueryParam("flag") String flag) { try { final String appId = pAppId.toUpperCase(); final byte[] bytes = IOUtils.toByteArray(in); return setData(appId, ttl, flag, key, bytes); } catch (EVCacheException e) { e.printStackTrace(); return Response.serverError().build(); } catch (Throwable t) { return Response.serverError().build(); } } private Response setData(String appId, String ttl, String flag, String key, byte[] bytes) throws EVCacheException, InterruptedException { final EVCache evcache = getEVCache(appId); if (ttl == null) { return Response.status(400).type("text/plain").entity("Please specify ttl for the key " + key + " as query parameter \n").build(); } final int timeToLive = Integer.valueOf(ttl).intValue(); EVCacheLatch latch = null; if(flag != null && flag.length() > 0) { final CachedData cd = new CachedData(Integer.parseInt(flag), bytes, Integer.MAX_VALUE); latch = evcache.set(key, cd, timeToLive, Policy.ALL_MINUS_1); } else { latch = evcache.set(key, bytes, timeToLive, Policy.ALL_MINUS_1); } if(latch != null) { final boolean status = latch.await(2500, TimeUnit.MILLISECONDS); if(status) { return Response.ok("Set Operation for Key - " + key + " was successful. \n").build(); } else { if(latch.getCompletedCount() > 0) { if(latch.getSuccessCount() == 0){ return Response.serverError().build(); } else if(latch.getSuccessCount() > 0 ) { return Response.ok("Set Operation for Key - " + key + " was successful in " + latch.getSuccessCount() + " Server Groups. \n").build(); } } else { return Response.serverError().build(); } } } return Response.serverError().build(); } @GET @Path("{appId}/{key}") @Produces({MediaType.APPLICATION_OCTET_STREAM}) public Response getOperation(@PathParam("appId") String appId, @PathParam("key") String key) { appId = appId.toUpperCase(); if (logger.isDebugEnabled()) logger.debug("Get for application " + appId + " for Key " + key); try { final EVCache evCache = getEVCache(appId); CachedData cachedData = (CachedData) evCache.get(key, evcacheTranscoder); if (cachedData == null) { return Response.status(404).type("text/plain").entity("Key " + key + " Not Found in cache " + appId + "\n").build(); } byte[] bytes = cachedData.getData(); if (bytes == null) { return Response.status(404).type("text/plain").entity("Key " + key + " Not Found in cache " + appId + "\n").build(); } else { return Response.status(200).type("application/octet-stream").entity(bytes).build(); } } catch (EVCacheException e) { e.printStackTrace(); return Response.serverError().build(); } } @DELETE @Path("{appId}/{key}") @Consumes(MediaType.APPLICATION_JSON) @Produces("text/plain") public Response deleteOperation(@PathParam("appId") String appId, @PathParam("key") String key) { if (logger.isDebugEnabled()) logger.debug("Get for application " + appId + " for Key " + key); appId = appId.toUpperCase(); final EVCache evCache = getEVCache(appId); try { Future<Boolean>[] _future = evCache.delete(key); if (_future.equals(Boolean.TRUE)) { if (logger.isDebugEnabled()) logger.debug("set key is successful"); } return Response.ok("Deleted Operation for Key - " + key + " was successful. \n").build(); } catch (EVCacheException e) { e.printStackTrace(); return Response.serverError().build(); } } private EVCache getEVCache(String appId) { EVCache evCache = evCacheMap.get(appId); if (evCache != null) return evCache; evCache = builder.setAppName(appId).build(); evCacheMap.put(appId, evCache); return evCache; } }