Browse Source

ADDED: ApiClient

ADDED: UsageDescription annotation
ADDED: Start class as entry point

first implementation of annotated resource descriptions
split-DB
Kc 6 years ago
parent
commit
4f279fc616
  1. 4
      src/Start.java
  2. 123
      src/api/ApiClient.java
  3. 18
      src/api/ApiService.java
  4. 1
      src/api/BlocksResource.java
  5. 14
      src/api/UsageDescription.java

4
src/Start.java

@ -1,4 +1,5 @@
import api.ApiClient;
import api.ApiService;
import repository.DataException;
import repository.RepositoryFactory;
@ -16,5 +17,8 @@ public class Start {
ApiService apiService = new ApiService();
apiService.start();
ApiClient client = new ApiClient(apiService);
String test = client.executeCommand("help GET blocks/height");
}
}

123
src/api/ApiClient.java

@ -0,0 +1,123 @@
package api;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.PATCH;
import javax.ws.rs.DELETE;
import javax.ws.rs.HttpMethod;
public class ApiClient {
private class HelpString
{
public final Pattern pattern;
public final String fullPath;
public final String description;
public HelpString(Pattern pattern, String fullPath, String description)
{
this.pattern = pattern;
this.fullPath = fullPath;
this.description = description;
}
}
private static final Pattern HELP_COMMAND_PATTERN = Pattern.compile("^ *help *(?<command>.*)$", Pattern.CASE_INSENSITIVE);
private static final List<Class<? extends Annotation>> REST_METHOD_ANNOTATIONS = Arrays.asList(
GET.class,
POST.class,
PUT.class,
PATCH.class,
DELETE.class
);
ApiService apiService;
List<HelpString> helpStrings;
public ApiClient(ApiService apiService)
{
this.apiService = apiService;
this.helpStrings = getHelpStrings(apiService.getResources());
}
private List<HelpString> getHelpStrings(Iterable<Class<?>> resources)
{
List<HelpString> result = new ArrayList<>();
for (Class<?> resource : resources) {
Path resourcePath = resource.getDeclaredAnnotation(Path.class);
if(resourcePath == null)
continue;
String resourcePathString = resourcePath.value();
for(Method method : resource.getDeclaredMethods())
{
UsageDescription usageDescription = method.getAnnotation(UsageDescription.class);
if(usageDescription == null)
continue;
String usageDescriptionString = usageDescription.value();
Path methodPath = method.getDeclaredAnnotation(Path.class);
String methodPathString = (methodPath != null) ? methodPath.value() : "";
for(Class<? extends Annotation> restMethodAnnotation : REST_METHOD_ANNOTATIONS)
{
Annotation annotation = method.getDeclaredAnnotation(restMethodAnnotation);
if(annotation == null)
continue;
HttpMethod httpMethod = annotation.annotationType().getDeclaredAnnotation(HttpMethod.class);
String httpMethodString = httpMethod.value();
Pattern pattern = Pattern.compile("^ *" + httpMethodString + " *" + getRegexPatternForPath(resourcePathString + methodPathString));
String fullPath = httpMethodString + " " + resourcePathString + methodPathString;
result.add(new HelpString(pattern, fullPath, usageDescriptionString));
}
}
}
return result;
}
private String getRegexPatternForPath(String path)
{
return path
.replaceAll("\\.", "\\.") // escapes "." as "\."
.replaceAll("\\{.*?\\}", ".*?"); // replace placeholders "{...}" by the "ungreedy match anything" pattern ".*?"
}
public String executeCommand(String command)
{
final Matcher helpMatch = HELP_COMMAND_PATTERN.matcher(command);
if(helpMatch.matches())
{
command = helpMatch.group("command");
StringBuilder help = new StringBuilder();
for(HelpString helpString : helpStrings)
{
if(helpString.pattern.matcher(command).matches())
{
help.append(helpString.fullPath + "\n");
help.append(helpString.description + "\n");
}
}
return help.toString();
}
return null;
}
}

18
src/api/ApiService.java

@ -17,13 +17,14 @@ import settings.Settings;
public class ApiService {
private Server server;
private Set<Class<?>> resources;
public ApiService()
{
// resources to register
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(BlocksResource.class);
ResourceConfig config = new ResourceConfig(s);
resources = new HashSet<Class<?>>();
resources.add(BlocksResource.class);
ResourceConfig config = new ResourceConfig(resources);
// create RPC server
this.server = new Server(Settings.getInstance().getRpcPort());
@ -44,14 +45,11 @@ public class ApiService {
ServletHolder apiServlet = new ServletHolder(container);
apiServlet.setInitOrder(1);
context.addServlet(apiServlet, "/api/*");
}
/*
// Setup Swagger servlet
ServletHolder swaggerServlet = context.addServlet(DefaultJaxrsConfig.class, "/swagger-core");
swaggerServlet.setInitOrder(2);
swaggerServlet.setInitParameter("api.version", "1.0.0");
*/
Iterable<Class<?>> getResources()
{
return resources;
}
public void start()

1
src/api/BlocksResource.java

@ -21,6 +21,7 @@ public class BlocksResource {
@GET
@Path("/height")
@UsageDescription("Returns the height of the blockchain")
public static String getHeight()
{
try (final Repository repository = RepositoryManager.getRepository()) {

14
src/api/UsageDescription.java

@ -0,0 +1,14 @@
package api;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value={ElementType.TYPE,ElementType.METHOD})
@Retention(value=RetentionPolicy.RUNTIME)
@Documented
public abstract @interface UsageDescription {
public abstract String value();
}
Loading…
Cancel
Save