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 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
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 {
|
||||
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()
|
||||
|
@ -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
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