All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.greenfield.vertx.irked.RouteConfigurationMethod Maven / Gradle / Ivy

There is a newer version: 4.5.10
Show newest version
package tech.greenfield.vertx.irked;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import tech.greenfield.vertx.irked.annotations.WebSocket;
import tech.greenfield.vertx.irked.exceptions.InvalidRouteConfiguration;
import tech.greenfield.vertx.irked.status.InternalServerError;
import tech.greenfield.vertx.irked.websocket.WebSocketMessage;

public class RouteConfigurationMethod extends RouteConfiguration {

	private Method method;
	private Class[] params;

	public RouteConfigurationMethod(Controller impl, Method m) throws InvalidRouteConfiguration {
		super(impl, m.getAnnotations());
		method = m;
		if (!isValid())
			return; // don't sanity check methods that aren't routing methods
		//if ((m.getModifiers() & Modifier.PUBLIC) == 0)
		//	throw new InvalidRouteConfiguration("Method " + m.getName() + " is not public");
		params = m.getParameterTypes();
		if (isWebSocketHandler()) return; // satisfies
		if (params.length < 1 || !RoutingContext.class.isAssignableFrom(params[0]))
			throw new InvalidRouteConfiguration("Method " + m.getName() + " doesn't take a Vert.x RoutingContext as first parameter");
		if (m.getParameterCount() > 1)
			throw new InvalidRouteConfiguration("Method " + m.getName() + " requires more than one parameter which I don't know how to provide yet");
	}

	private boolean isWebSocketHandler() throws InvalidRouteConfiguration {
		Map> types = Arrays.stream(annotations).collect(Collectors.partitioningBy((Annotation a) -> a.annotationType().equals(WebSocket.class)));
		if (types.get(false).size() > 0 && types.get(true).size() > 0)
			throw new InvalidRouteConfiguration("A WebSocket handler " + method + " cannot also be a request handler");
		if (types.get(false).size() > 0)
			return false;
		if (params.length == 1 && WebSocketMessage.class.isAssignableFrom(params[0]))
			return true;
		if (params.length == 2 && Request.class.isAssignableFrom(params[0]) && WebSocketMessage.class.isAssignableFrom(params[1]))
			return true;
		throw new InvalidRouteConfiguration("A WebSocket handler " + method + " must accept (WebSocketMessage) or (Request,WebSocketMessage)");
	}
	
	@Override
	protected  T[] getAnnotation(Class anot) {
		return method.getDeclaredAnnotationsByType(anot);
	}
	
	@Override
	public boolean isController() {
		return false; // a method is always a request handler and never a sub router
	}

	@Override
	Controller getController() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	protected String getName() {
		return method.getName();
	}

	@Override
	Handler getHandler() throws IllegalArgumentException, IllegalAccessException, InvalidRouteConfiguration {
		method.setAccessible(true);
		return new Handler() {
			@Override
			public void handle(RoutingContext r) {
				// run time check for correct type
				// we support working with methods that take specializations for Request, we'll rely on the specific implementation's
				// getRequest() to provide the correct type
				if (!params[0].isAssignableFrom(r.getClass())) {
					r.fail(new InternalServerError("Invalid request handler " + this + " - can't handle request of type " + r.getClass()));
					return;
				}
				
				try {
					method.invoke(impl, r);
				} catch (InvocationTargetException e) { // user exception
					handleUserException(r, e.getCause(), "method " + method);
				} catch (IllegalAccessException e) { // shouldn't happen because we setAccessible above
					r.fail(new InternalServerError("Invalid request handler " + this + ": " + e, e));
				} catch (IllegalArgumentException e) { // shouldn't happen because we checked the type before calling
					r.fail(new InternalServerError("Mistyped request handler " + this + ": " + e, e));
				}
			}
			@Override
			public String toString() {
				return method.getName() + "(" + Arrays.asList(method.getParameterTypes()).stream().map(Class::getSimpleName).collect(Collectors.joining(", ")) + ")";
			}
		};
	}

	@Override
	Handler getMessageHandler() throws IllegalArgumentException, IllegalAccessException, InvalidRouteConfiguration {
		method.setAccessible(true);
		return new Handler() {
			@Override
			public void handle(WebSocketMessage m) {
				Request req = m.request();
				// run time check for correct type
				// we support working with methods that take specializations for Request, we'll rely on the specific implementation's
				// getRequest() to provide the correct type
				if (!params[0].isAssignableFrom(m.getClass()) && !params[0].isAssignableFrom(req.getClass())) {
					req.fail(new InternalServerError("Invalid request handler " + this + " - can't handle request of type " + req.getClass()));
					return;
				}
				
				try {
					if (params.length == 1)
						method.invoke(impl, m);
					else
						method.invoke(impl, req, m);
				} catch (InvocationTargetException e) { // user exception
					handleUserException(m, e.getCause(), "method " + method);
				} catch (IllegalAccessException | IllegalArgumentException e) {
					// shouldn't happen because we setAccessible above and we checked the type before calling
					handleUserException(m, e, "method " + method);
				}
			}
			@Override
			public String toString() {
				return method.getName() + "(" + Arrays.asList(method.getParameterTypes()).stream().map(Class::getSimpleName).collect(Collectors.joining(", ")) + ")";
			}
		};
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy