
ninja.RouteBuilderImpl Maven / Gradle / Ivy
/**
* Copyright (C) 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ninja;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;
import ninja.params.ControllerMethodInvoker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Injector;
class RouteBuilderImpl implements RouteBuilder {
private static final Logger log = LoggerFactory
.getLogger(RouteBuilder.class);
private String httpMethod;
private String uri;
private Class controller;
private Method controllerMethod;
private Result result;
public RouteBuilderImpl GET() {
httpMethod = "GET";
return this;
}
public RouteBuilderImpl POST() {
httpMethod = "POST";
return this;
}
public RouteBuilderImpl PUT() {
httpMethod = "PUT";
return this;
}
public RouteBuilderImpl DELETE() {
httpMethod = "DELETE";
return this;
}
public RouteBuilderImpl OPTIONS() {
httpMethod = "OPTIONS";
return this;
}
public RouteBuilderImpl HEAD() {
httpMethod = "HEAD";
return this;
}
public RouteBuilderImpl METHOD(String method) {
httpMethod = method;
return this;
}
@Override
public void with(Class controller, String controllerMethod) {
this.controller = controller;
this.controllerMethod = verifyThatControllerAndMethodExists(controller,
controllerMethod);
}
@Override
public void with(Result result) {
this.result = result;
}
@Override
public RouteBuilder route(String uri) {
this.uri = uri;
return this;
}
/**
* Routes are usually defined in conf/Routes.java as
* router.GET().route("/teapot").with(FilterController.class, "teapot");
*
* Unfortunately "teapot" is not checked by the compiler. We do that here at
* runtime.
*
* We are reloading when there are changes. So this is almost as good as
* compile time checking.
*
* @param controller
* The controller class
* @param controllerMethod
* The method
* @return The actual method
*/
private Method verifyThatControllerAndMethodExists(Class controller,
String controllerMethod) {
try {
Method methodFromQueryingClass = null;
// 1. Make sure method is in class
// 2. Make sure only one method is there. Otherwise we cannot really
// know what
// to do with the parameters.
for (Method method : controller.getMethods()) {
if (method.getName().equals(controllerMethod)) {
if (methodFromQueryingClass == null) {
methodFromQueryingClass = method;
} else {
throw new NoSuchMethodException();
}
}
}
if (methodFromQueryingClass == null) {
throw new NoSuchMethodException();
}
// make sure that the return type of that controller method
// is of type Result.
if (methodFromQueryingClass.getReturnType().isAssignableFrom(
Result.class)) {
return methodFromQueryingClass;
} else {
throw new NoSuchMethodException();
}
} catch (SecurityException e) {
log.error(
"Error while checking for valid Controller / controllerMethod combination",
e);
} catch (NoSuchMethodException e) {
log.error("Error in route configuration!!!");
log.error("Can not find Controller " + controller.getName()
+ " and method " + controllerMethod);
log.error("Hint: make sure the controller returns a ninja.Result!");
log.error("Hint: Ninja does not allow more than one method with the same name!");
}
return null;
}
/**
* Build the route
*
* @param injector
* The injector to build the route with
*/
public Route buildRoute(Injector injector) {
if(controller == null && result == null) {
log.error("Error in route configuration for {}", uri);
throw new IllegalStateException("Route not with a controller or result");
}
// Calculate filters
LinkedList> filters = new LinkedList>();
if(controller != null) {
if (controllerMethod == null) {
throw new IllegalStateException(
String.format("Route '%s' does not have a controller method", uri));
}
filters.addAll(calculateFiltersForClass(controller));
FilterWith filterWith = controllerMethod
.getAnnotation(FilterWith.class);
if (filterWith != null) {
filters.addAll(Arrays.asList(filterWith.value()));
}
}
return new Route(httpMethod, uri, controller, controllerMethod,
buildFilterChain(injector, filters, controller,
controllerMethod, result));
}
private FilterChain buildFilterChain(Injector injector,
LinkedList> filters,
Class> controller,
Method controllerMethod,
Result result) {
if (filters.isEmpty()) {
return result != null ? new FilterChainEnd(result) :
new FilterChainEnd(injector.getProvider(controller),
ControllerMethodInvoker.build(controllerMethod, injector));
} else {
Class extends Filter> filter = filters.pop();
return new FilterChainImpl(injector.getProvider(filter),
buildFilterChain(injector, filters, controller,
controllerMethod, result));
}
}
private Set> calculateFiltersForClass(Class controller) {
LinkedHashSet> filters = new LinkedHashSet>();
// First step up the superclass tree, so that superclass filters come
// first
// Superclass
if (controller.getSuperclass() != null) {
filters.addAll(calculateFiltersForClass(controller.getSuperclass()));
}
// Interfaces
if (controller.getInterfaces() != null) {
for (Class clazz : controller.getInterfaces()) {
filters.addAll(calculateFiltersForClass(clazz));
}
}
// Now add from here
FilterWith filterWith = (FilterWith) controller
.getAnnotation(FilterWith.class);
if (filterWith != null) {
filters.addAll(Arrays.asList(filterWith.value()));
}
// And return
return filters;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy