forked from Qortal/qortal
ADDED: ApiClient
ADDED: UsageDescription annotation ADDED: Start class as entry point first implementation of annotated resource descriptions
This commit is contained in:
parent
d63ff02b97
commit
4f279fc616
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
import api.ApiClient;
|
||||||
import api.ApiService;
|
import api.ApiService;
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
import repository.RepositoryFactory;
|
import repository.RepositoryFactory;
|
||||||
@ -16,5 +17,8 @@ public class Start {
|
|||||||
|
|
||||||
ApiService apiService = new ApiService();
|
ApiService apiService = new ApiService();
|
||||||
apiService.start();
|
apiService.start();
|
||||||
|
|
||||||
|
ApiClient client = new ApiClient(apiService);
|
||||||
|
String test = client.executeCommand("help GET blocks/height");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
123
src/api/ApiClient.java
Normal file
123
src/api/ApiClient.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -17,13 +17,14 @@ import settings.Settings;
|
|||||||
|
|
||||||
public class ApiService {
|
public class ApiService {
|
||||||
private Server server;
|
private Server server;
|
||||||
|
private Set<Class<?>> resources;
|
||||||
|
|
||||||
public ApiService()
|
public ApiService()
|
||||||
{
|
{
|
||||||
// resources to register
|
// resources to register
|
||||||
Set<Class<?>> s = new HashSet<Class<?>>();
|
resources = new HashSet<Class<?>>();
|
||||||
s.add(BlocksResource.class);
|
resources.add(BlocksResource.class);
|
||||||
ResourceConfig config = new ResourceConfig(s);
|
ResourceConfig config = new ResourceConfig(resources);
|
||||||
|
|
||||||
// create RPC server
|
// create RPC server
|
||||||
this.server = new Server(Settings.getInstance().getRpcPort());
|
this.server = new Server(Settings.getInstance().getRpcPort());
|
||||||
@ -44,14 +45,11 @@ public class ApiService {
|
|||||||
ServletHolder apiServlet = new ServletHolder(container);
|
ServletHolder apiServlet = new ServletHolder(container);
|
||||||
apiServlet.setInitOrder(1);
|
apiServlet.setInitOrder(1);
|
||||||
context.addServlet(apiServlet, "/api/*");
|
context.addServlet(apiServlet, "/api/*");
|
||||||
|
}
|
||||||
/*
|
|
||||||
// Setup Swagger servlet
|
Iterable<Class<?>> getResources()
|
||||||
ServletHolder swaggerServlet = context.addServlet(DefaultJaxrsConfig.class, "/swagger-core");
|
{
|
||||||
swaggerServlet.setInitOrder(2);
|
return resources;
|
||||||
swaggerServlet.setInitParameter("api.version", "1.0.0");
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start()
|
public void start()
|
||||||
|
@ -21,6 +21,7 @@ public class BlocksResource {
|
|||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/height")
|
@Path("/height")
|
||||||
|
@UsageDescription("Returns the height of the blockchain")
|
||||||
public static String getHeight()
|
public static String getHeight()
|
||||||
{
|
{
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
14
src/api/UsageDescription.java
Normal file
14
src/api/UsageDescription.java
Normal file
@ -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…
x
Reference in New Issue
Block a user