Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tristantarrant committed Dec 12, 2019
1 parent ffcfc39 commit e9c1484
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 6 deletions.
2 changes: 2 additions & 0 deletions server/rest/src/main/java/org/infinispan/rest/RestServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.infinispan.rest.framework.impl.ResourceManagerImpl;
import org.infinispan.rest.framework.impl.RestDispatcherImpl;
import org.infinispan.rest.resources.CacheManagerResource;
import org.infinispan.rest.resources.CacheResource;
import org.infinispan.rest.resources.CacheResourceV2;
import org.infinispan.rest.resources.ClusterResource;
import org.infinispan.rest.resources.CounterResource;
Expand Down Expand Up @@ -113,6 +114,7 @@ protected void startInternal(RestServerConfiguration configuration, EmbeddedCach
String restContext = configuration.contextPath();
String rootContext = "/";
ResourceManager resourceManager = new ResourceManagerImpl();
resourceManager.registerResource(restContext, new CacheResource(invocationHelper));
resourceManager.registerResource(restContext, new CacheResourceV2(invocationHelper));
resourceManager.registerResource(restContext, new CounterResource(invocationHelper));
resourceManager.registerResource(restContext, new CacheManagerResource(invocationHelper));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.infinispan.rest.operations.mediatypes;

import static org.infinispan.commons.dataconversion.MediaType.APPLICATION_JSON_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.APPLICATION_OCTET_STREAM_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.APPLICATION_SERIALIZED_OBJECT_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.APPLICATION_XML_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.IMAGE_PNG_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.MATCH_ALL_TYPE;
import static org.infinispan.commons.dataconversion.MediaType.TEXT_PLAIN_TYPE;

import java.util.HashMap;
import java.util.Map;

import org.infinispan.commons.dataconversion.MediaType;
import org.infinispan.rest.operations.mediatypes.impl.BinaryOutputPrinter;
import org.infinispan.rest.operations.mediatypes.impl.JSONOutputPrinter;
import org.infinispan.rest.operations.mediatypes.impl.TextOutputPrinter;
import org.infinispan.rest.operations.mediatypes.impl.XMLOutputPrinter;

/**
* Formats collections of entries based on the associated {@link MediaType};
*
*/
public class EntrySetFormatter {

private static Map<String, OutputPrinter> printerByMediaType = new HashMap<>(10);

static {
TextOutputPrinter textOutputPrinter = new TextOutputPrinter();
XMLOutputPrinter xmlOutputPrinter = new XMLOutputPrinter();
JSONOutputPrinter jsonOutputPrinter = new JSONOutputPrinter();
BinaryOutputPrinter binaryOutputPrinter = new BinaryOutputPrinter();

printerByMediaType.put(TEXT_PLAIN_TYPE, textOutputPrinter);
printerByMediaType.put(APPLICATION_XML_TYPE, xmlOutputPrinter);
printerByMediaType.put(APPLICATION_JSON_TYPE, jsonOutputPrinter);
printerByMediaType.put(APPLICATION_OCTET_STREAM_TYPE, binaryOutputPrinter);
printerByMediaType.put(IMAGE_PNG_TYPE, binaryOutputPrinter);
printerByMediaType.put(APPLICATION_SERIALIZED_OBJECT_TYPE, binaryOutputPrinter);
printerByMediaType.put(MATCH_ALL_TYPE, textOutputPrinter);
}

public static OutputPrinter forMediaType(MediaType mediaType) {
return printerByMediaType.get(mediaType.getTypeSubtype());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.infinispan.rest.operations.mediatypes;

import java.io.UnsupportedEncodingException;

import org.infinispan.CacheSet;
import org.infinispan.commons.dataconversion.EncodingException;
import org.infinispan.rest.operations.exceptions.ServerInternalException;

/**
* Converts binary array from {@link org.infinispan.Cache} into output format.
*
* <p>
* In order to avoid unnecessary conversion steps, all methods need to return a byte array. This way
* Netty doesn't need to do any conversion - it just wraps it into a {@link io.netty.buffer.ByteBuf}.
* </p>
*
* @author Sebastian Łaskawiec
*/
public interface OutputPrinter {

/**
* Converts all values in the cache to a desired output format.
*
* @param cacheName Cache name (sometimes might be used as xml or json key).
* @param cacheSet Key Set.
* @param charset Desired {@link Charset}
* @return Byte array representation of converted values.
* @throws ServerInternalException Thrown if conversion was not successful.
*/
byte[] print(String cacheName, CacheSet<?> cacheSet, Charset charset) throws ServerInternalException;

default String asString(Object k) {
try {
if (k instanceof byte[]) {
return new String((byte[]) k, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
throw new EncodingException("Cannot convert key to string", e);
}
return k.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.infinispan.rest.operations.mediatypes.impl;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.infinispan.CacheSet;
import org.infinispan.commons.dataconversion.StandardConversions;
import org.infinispan.rest.operations.mediatypes.Charset;
import org.infinispan.rest.operations.mediatypes.OutputPrinter;

/**
* {@link OutputPrinter} for binary values.
*
* @author Sebastian Łaskawiec
*/
public class BinaryOutputPrinter implements OutputPrinter {

@Override
public byte[] print(String cacheName, CacheSet<?> keys, Charset charset) {
return Arrays.stream(keys.toArray())
.map(k -> (byte[]) k)
.map(StandardConversions::bytesToHex)
.collect(Collectors.joining("\n", "", ""))
.getBytes(charset.getJavaCharset());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.infinispan.rest.operations.mediatypes.impl;

public class Escaper {

private Escaper() {

}

static String escapeHtml(String html) {
return escapeXml(html);
}

static String escapeXml(String xml) {
StringBuilder sb = new StringBuilder();
for (char c : xml.toCharArray()) {
switch (c) {
case '&':
sb.append("&amp;");
break;
case '>':
sb.append("&gt;");
break;
case '<':
sb.append("&lt;");
break;
case '\"':
sb.append("&quot;");
break;
case '\'':
sb.append("&apos;");
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}

static String escapeJson(String json) {
return json.replaceAll("\"", "\\\\\"");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.infinispan.rest.operations.mediatypes.impl;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.infinispan.CacheSet;
import org.infinispan.rest.logging.Log;
import org.infinispan.rest.operations.mediatypes.Charset;
import org.infinispan.rest.operations.mediatypes.OutputPrinter;
import org.infinispan.util.logging.LogFactory;

/**
* {@link OutputPrinter} for JSON values.
*
* @author Sebastian Łaskawiec
*/
public class JSONOutputPrinter implements OutputPrinter {

protected final static Log logger = LogFactory.getLog(JSONOutputPrinter.class, Log.class);

@Override
public byte[] print(String cacheName, CacheSet<?> keys, Charset charset) {
return Arrays.stream(keys.toArray())
.map(this::asString)
.collect(Collectors.joining(",", "keys=[", "]"))
.getBytes(charset.getJavaCharset());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.infinispan.rest.operations.mediatypes.impl;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.infinispan.CacheSet;
import org.infinispan.rest.operations.mediatypes.Charset;
import org.infinispan.rest.operations.mediatypes.OutputPrinter;

/**
* {@link OutputPrinter} for text values.
*
* @author Sebastian Łaskawiec
*/
public class TextOutputPrinter implements OutputPrinter {

@Override
public byte[] print(String cacheName, CacheSet<?> keys, Charset charset) {
return Arrays.stream(keys.toArray()).map(this::asString)
.collect(Collectors.joining("\n", "", ""))
.getBytes(charset.getJavaCharset());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.infinispan.rest.operations.mediatypes.impl;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.infinispan.CacheSet;
import org.infinispan.rest.logging.Log;
import org.infinispan.rest.operations.mediatypes.Charset;
import org.infinispan.rest.operations.mediatypes.OutputPrinter;
import org.infinispan.util.logging.LogFactory;

/**
* {@link OutputPrinter} for xml values.
*
* @author Sebastian Łaskawiec
*/
public class XMLOutputPrinter implements OutputPrinter {

protected final static Log logger = LogFactory.getLog(JSONOutputPrinter.class, Log.class);

@Override
public byte[] print(String cacheName, CacheSet<?> keys, Charset charset) {
return Arrays.stream(keys.toArray())
.map(this::asString)
.map(Escaper::escapeXml)
.map(s -> "<key>" + s + "</key>")
.collect(Collectors.joining("", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><keys>", "</keys>"))
.getBytes(charset.getJavaCharset());
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.infinispan.rest.resources;

import static org.infinispan.rest.NettyRestRequest.EXTENDED_HEADER;
import static org.infinispan.rest.framework.Method.DELETE;
import static org.infinispan.rest.framework.Method.GET;
import static org.infinispan.rest.framework.Method.HEAD;
import static org.infinispan.rest.framework.Method.POST;
import static org.infinispan.rest.framework.Method.PUT;
import static org.infinispan.rest.resources.MediaTypeUtils.negotiateMediaType;

import java.util.Date;
Expand All @@ -24,31 +27,51 @@
import org.infinispan.rest.cachemanager.RestCacheManager;
import org.infinispan.rest.configuration.RestServerConfiguration;
import org.infinispan.rest.framework.ContentSource;
import org.infinispan.rest.framework.ResourceHandler;
import org.infinispan.rest.framework.RestRequest;
import org.infinispan.rest.framework.RestResponse;
import org.infinispan.rest.framework.impl.Invocations;
import org.infinispan.rest.operations.CacheOperationsHelper;
import org.infinispan.rest.operations.exceptions.NoDataFoundException;
import org.infinispan.rest.operations.exceptions.NoKeyException;

import io.netty.handler.codec.http.HttpResponseStatus;

/**
* Handle basic cache operations.
* Handler for the cache resource.
*
* @since 10.0
*/
public class BaseCacheResource {
public class CacheResource implements ResourceHandler {

private static final MurmurHash3 hashFunc = MurmurHash3.getInstance();

final CacheResourceQueryAction queryAction;
final InvocationHelper invocationHelper;

public BaseCacheResource(InvocationHelper invocationHelper) {
public CacheResource(InvocationHelper invocationHelper) {
this.invocationHelper = invocationHelper;
this.queryAction = new CacheResourceQueryAction(invocationHelper);
}

@Override
public Invocations getInvocations() {
return new Invocations.Builder()
.invocation().methods(PUT, POST).path("/{cacheName}/{cacheKey}").handleWith(this::putValueToCache)
.invocation().methods(GET, HEAD).path("/{cacheName}/{cacheKey}").handleWith(this::getCacheValue)
.invocation().method(DELETE).path("/{cacheName}/{cacheKey}").handleWith(this::deleteCacheValue)
.invocation().method(DELETE).path("/{cacheName}").handleWith(this::clearEntireCache)
.invocation().method(GET).path("/{cacheName}").handleWith(this::getCacheKeys)
.invocation().methods(GET, POST).path("/{cacheName}").withAction("search").handleWith(queryAction::search)
.create();
}

private CompletionStage<RestResponse> getCacheKeys(RestRequest request) throws RestResponseException {
NettyRestResponse.Builder responseBuilder = new NettyRestResponse.Builder();
responseBuilder.status(HttpResponseStatus.BAD_REQUEST.code());
return CompletableFuture.completedFuture(responseBuilder.build());
}

CompletionStage<RestResponse> deleteCacheValue(RestRequest request) throws RestResponseException {
String cacheName = request.variables().get("cacheName");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.infinispan.rest.framework.RestResponse;

/**
* Helper for handling the 'search' action of the {@link BaseCacheResource}.
* Helper for handling the 'search' action of the {@link CacheResource}.
*
* @since 10.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.infinispan.rest.RestResponseException;
import org.infinispan.rest.cachemanager.RestCacheManager;
import org.infinispan.rest.framework.ContentSource;
import org.infinispan.rest.framework.ResourceHandler;
import org.infinispan.rest.framework.RestRequest;
import org.infinispan.rest.framework.RestResponse;
import org.infinispan.rest.framework.impl.Invocations;
Expand All @@ -51,7 +50,7 @@

import io.netty.handler.codec.http.HttpResponseStatus;

public class CacheResourceV2 extends BaseCacheResource implements ResourceHandler {
public class CacheResourceV2 extends CacheResource {

private static final int STREAM_BATCH_SIZE = 1000;

Expand Down

0 comments on commit e9c1484

Please sign in to comment.