-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for annotated CoreHandlers using Runtime retention only.
- Loading branch information
codingchili
committed
Aug 18, 2017
1 parent
913eec8
commit 28d5d0e
Showing
6 changed files
with
446 additions
and
237 deletions.
There are no files selected for viewing
54 changes: 34 additions & 20 deletions
54
core/main/java/com/codingchili/core/listener/CoreHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,35 @@ | ||
package com.codingchili.core.listener; | ||
|
||
/** | ||
* @author Robin Duda | ||
* <p> | ||
* A simplified handler that may be deployed directly. | ||
*/ | ||
public interface CoreHandler extends CoreDeployment { | ||
|
||
/** | ||
* Handles an incoming request without exception handling. | ||
* | ||
* @param request the request to be handled. | ||
*/ | ||
void handle(Request request); | ||
|
||
/** | ||
* @return the address of the handler. | ||
*/ | ||
String address(); | ||
package com.codingchili.core.listener; | ||
|
||
import com.codingchili.core.protocol.Address; | ||
|
||
/** | ||
* @author Robin Duda | ||
* <p> | ||
* A simplified handler that may be deployed directly. | ||
*/ | ||
public interface CoreHandler extends CoreDeployment { | ||
|
||
/** | ||
* Handles an incoming request without exception handling. | ||
* | ||
* @param request the request to be handled. | ||
*/ | ||
void handle(Request request); | ||
|
||
/** | ||
* @return the address of the handler. If not implemented the @Address | ||
* annotation will be used, if missing an error is thrown. | ||
* | ||
* Could potentially lead to Runtime errors but is allowed here as | ||
* this is called during deployment. Reconsider this decision later. | ||
*/ | ||
default String address() { | ||
Address annotation = getClass().getAnnotation(Address.class); | ||
if (annotation != null) { | ||
return annotation.value(); | ||
} else { | ||
throw new RuntimeException("Class " + getClass().getName() + " does not" + | ||
" implement CoreHandler::address nor is annotated with @Address."); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.codingchili.core.protocol; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Alternate way of specifying a handlers listening address. | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.TYPE) | ||
public @interface Address { | ||
String value(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.codingchili.core.protocol; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Indicates that the annotated method requires authentication. | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface Private { | ||
String value(); | ||
} |
249 changes: 146 additions & 103 deletions
249
core/main/java/com/codingchili/core/protocol/Protocol.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,103 +1,146 @@ | ||
package com.codingchili.core.protocol; | ||
|
||
import com.codingchili.core.protocol.exception.AuthorizationRequiredException; | ||
import com.codingchili.core.protocol.exception.HandlerMissingException; | ||
|
||
import io.vertx.core.json.JsonObject; | ||
|
||
import static com.codingchili.core.configuration.CoreStrings.*; | ||
|
||
/** | ||
* @author Robin Duda | ||
* <p> | ||
* Maps packet data to handlers and manages authentication status for handlers. | ||
*/ | ||
public class Protocol<Handler extends RequestHandler> { | ||
private final AuthorizationHandler<Handler> handlers = new AuthorizationHandler<>(); | ||
|
||
/** | ||
* Returns the route handler for the given target route and its access level. | ||
* | ||
* @param access the access level the request is valid for. | ||
* @param route the handler route to find | ||
* @return the handler that is mapped to the route and access level. | ||
* @throws AuthorizationRequiredException when authorization level is not fulfilled for given route. | ||
* @throws HandlerMissingException when the requested route handler is not registered. | ||
*/ | ||
public Handler get(Access access, String route) throws AuthorizationRequiredException, HandlerMissingException { | ||
if (handlers.contains(route)) { | ||
return handlers.get(route, access); | ||
} else { | ||
return handlers.get(ANY, access); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the route handler for the given target route and its access level. | ||
* | ||
* @param route the handler route to find. | ||
* @return the handler that is mapped to the route. | ||
* @throws AuthorizationRequiredException when authorization level is not fulfilled for the given route. | ||
* @throws HandlerMissingException when the requested route handler is not registered. | ||
*/ | ||
public Handler get(String route) throws AuthorizationRequiredException, HandlerMissingException { | ||
return get(Access.AUTHORIZED, route); | ||
} | ||
|
||
/** | ||
* Registers a handler for the given route. | ||
* | ||
* @param route the route to register a handler for. | ||
* @param handler the handler to be registered for the given route. | ||
* @return the updated protocol specification for fluent use. | ||
*/ | ||
public Protocol<Handler> use(String route, Handler handler) { | ||
use(route, handler, Access.AUTHORIZED); | ||
return this; | ||
} | ||
|
||
/** | ||
* Registers a handler for the given route with an access level. | ||
* | ||
* @param route the route to register a handler for. | ||
* @param handler the handler to be registered for the given route with the access level. | ||
* @param access specifies the authorization level required to access the route. | ||
* @return the updated protocol specification for fluent use. | ||
*/ | ||
public Protocol<Handler> use(String route, Handler handler, Access access) { | ||
handlers.use(route, handler, access); | ||
return this; | ||
} | ||
|
||
/** | ||
* @return returns a list of all registered routes on the protoocol. | ||
*/ | ||
public ProtocolMapping list() { | ||
return handlers.list(); | ||
} | ||
|
||
/** | ||
* Creates a response object given a response status. | ||
* | ||
* @param status the status to create the response from. | ||
* @return a JSON encoded response packed in a buffer. | ||
*/ | ||
public static JsonObject response(ResponseStatus status) { | ||
return new JsonObject() | ||
.put(PROTOCOL_STATUS, status); | ||
} | ||
|
||
/** | ||
* Creates a response object given a response status and a throwable. | ||
* | ||
* @param status the status to include in the response. | ||
* @param e an exception that was the cause of an abnormal response status. | ||
* @return a JSON encoded response packed in a buffer. | ||
*/ | ||
public static JsonObject response(ResponseStatus status, Throwable e) { | ||
return new JsonObject() | ||
.put(PROTOCOL_STATUS, status) | ||
.put(PROTOCOL_MESSAGE, e.getMessage()); | ||
} | ||
} | ||
|
||
package com.codingchili.core.protocol; | ||
|
||
import com.codingchili.core.listener.CoreHandler; | ||
import com.codingchili.core.listener.Request; | ||
import com.codingchili.core.protocol.exception.AuthorizationRequiredException; | ||
import com.codingchili.core.protocol.exception.HandlerMissingException; | ||
import io.vertx.core.json.JsonObject; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
|
||
import static com.codingchili.core.configuration.CoreStrings.*; | ||
|
||
/** | ||
* @author Robin Duda | ||
* <p> | ||
* Maps packet data to handlers and manages authentication status for handlers. | ||
*/ | ||
public class Protocol<Handler extends RequestHandler> { | ||
private final AuthorizationHandler<Handler> handlers = new AuthorizationHandler<>(); | ||
|
||
public Protocol() {} | ||
|
||
/** | ||
* Creates a protocol by mapping @Public and @Private annotated methods. | ||
* | ||
* @param handler contains methods to be mapped. | ||
*/ | ||
public Protocol(CoreHandler handler) { | ||
Method[] methods = handler.getClass().getDeclaredMethods(); | ||
|
||
for (Method method : methods) { | ||
Annotation annotation = method.getAnnotation(Public.class); | ||
|
||
if (annotation != null) { | ||
use(((Public) annotation).value(), wrap(handler, method), Access.PUBLIC); | ||
} else { | ||
annotation = method.getAnnotation(Private.class); | ||
if (annotation != null) { | ||
use(((Private) annotation).value(), wrap(handler, method), Access.AUTHORIZED); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private Handler wrap(Object coreHandler, Method method) { | ||
return (Handler) new RequestHandler<Request>() { | ||
@Override | ||
public void handle(Request request) { | ||
try { | ||
method.invoke(coreHandler, request); | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Returns the route handler for the given target route and its access level. | ||
* | ||
* @param access the access level the request is valid for. | ||
* @param route the handler route to find | ||
* @return the handler that is mapped to the route and access level. | ||
* @throws AuthorizationRequiredException when authorization level is not fulfilled for given route. | ||
* @throws HandlerMissingException when the requested route handler is not registered. | ||
*/ | ||
public Handler get(Access access, String route) throws AuthorizationRequiredException, HandlerMissingException { | ||
if (handlers.contains(route)) { | ||
return handlers.get(route, access); | ||
} else { | ||
return handlers.get(ANY, access); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the route handler for the given target route and its access level. | ||
* | ||
* @param route the handler route to find. | ||
* @return the handler that is mapped to the route. | ||
* @throws AuthorizationRequiredException when authorization level is not fulfilled for the given route. | ||
* @throws HandlerMissingException when the requested route handler is not registered. | ||
*/ | ||
public Handler get(String route) throws AuthorizationRequiredException, HandlerMissingException { | ||
return get(Access.AUTHORIZED, route); | ||
} | ||
|
||
/** | ||
* Registers a handler for the given route. | ||
* | ||
* @param route the route to register a handler for. | ||
* @param handler the handler to be registered for the given route. | ||
* @return the updated protocol specification for fluent use. | ||
*/ | ||
public Protocol<Handler> use(String route, Handler handler) { | ||
use(route, handler, Access.AUTHORIZED); | ||
return this; | ||
} | ||
|
||
/** | ||
* Registers a handler for the given route with an access level. | ||
* | ||
* @param route the route to register a handler for. | ||
* @param handler the handler to be registered for the given route with the access level. | ||
* @param access specifies the authorization level required to access the route. | ||
* @return the updated protocol specification for fluent use. | ||
*/ | ||
public Protocol<Handler> use(String route, Handler handler, Access access) { | ||
handlers.use(route, handler, access); | ||
return this; | ||
} | ||
|
||
/** | ||
* @return returns a list of all registered routes on the protoocol. | ||
*/ | ||
public ProtocolMapping list() { | ||
return handlers.list(); | ||
} | ||
|
||
/** | ||
* Creates a response object given a response status. | ||
* | ||
* @param status the status to create the response from. | ||
* @return a JSON encoded response packed in a buffer. | ||
*/ | ||
public static JsonObject response(ResponseStatus status) { | ||
return new JsonObject() | ||
.put(PROTOCOL_STATUS, status); | ||
} | ||
|
||
/** | ||
* Creates a response object given a response status and a throwable. | ||
* | ||
* @param status the status to include in the response. | ||
* @param e an exception that was the cause of an abnormal response status. | ||
* @return a JSON encoded response packed in a buffer. | ||
*/ | ||
public static JsonObject response(ResponseStatus status, Throwable e) { | ||
return new JsonObject() | ||
.put(PROTOCOL_STATUS, status) | ||
.put(PROTOCOL_MESSAGE, e.getMessage()); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.codingchili.core.protocol; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Indicates that the annotated method does not require authentication. | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface Public { | ||
public String value(); | ||
} |
Oops, something went wrong.