/** * Copyright 2014 Bayes Technologies * * 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 me.bayes.vertx.vest.binding; import me.bayes.vertx.vest.VestApplication; import me.bayes.vertx.vest.util.ContextUtil; import me.bayes.vertx.vest.util.HttpUtils; import me.bayes.vertx.vest.util.UriPathUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.Consumes; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.Produces; import java.lang.reflect.Method; import java.util.Set; /** * @author Kevin Bayes * @since 1.1 * @version 1.1 */ public class DefaultRouteBindingHolderFactory implements RouteBindingHolderFactory { protected final Logger log = LoggerFactory.getLogger(getClass()); private VestApplication application; private RouteBindingHolder bindingHolder; public DefaultRouteBindingHolderFactory(VestApplication application) { super(); this.application = application; this.bindingHolder = new RouteBindingHolder(); } /* (non-Javadoc) * @see me.bayes.vertx.vest.binding.RouteBindingHolderFactory#build() */ public RouteBindingHolder build() throws Exception { this.bindingHolder = new RouteBindingHolder(); final Set<Class<?>> classes = application.getClasses(); final String applicationContextPath = UriPathUtil.getApplicationContext(application); //loop through classes and add then to the route matcher for(Class<?> clazz : classes) { addClassBindings(clazz, applicationContextPath); } return bindingHolder; } /** * * @param clazz * @param contextPath * @throws Exception */ private void addClassBindings(final Class<?> clazz, String contextPath) throws Exception { final Path pathAnnotation = clazz.getAnnotation(Path.class); if(pathAnnotation == null) { return; } Object instance = clazz.getConstructor().newInstance(); ContextUtil.assignContextFields(clazz, instance, application); for(Method method : clazz.getMethods()) { if(!method.getReturnType().equals(Void.TYPE)) { //Carry on if return type is not void as we are interested in async. //3.3.3 Return Type continue; } addMethodBindings(clazz, instance, UriPathUtil.concatPaths(contextPath, pathAnnotation.value()), method); } } /** * * @param clazz * @param instance * @param path * @param method * @throws Exception */ private void addMethodBindings(Class<?> clazz, final Object instance, String path, Method method) throws Exception { final Path pathAnnotation = method.getAnnotation(Path.class); final HttpMethod httpMethod = HttpUtils.resolveHttpType(method); if(httpMethod == null) { return; } //3.3.1 Visibility Only public methods may be exposed as resource methods. if(method.getModifiers() != Method.PUBLIC) { log.warn("Method {} is not public and is annotated with @Path.", method.getName()); } addBinding(clazz, method, instance, httpMethod, UriPathUtil.concatPaths(path, (pathAnnotation == null) ? "" : pathAnnotation.value())); } /** * The simplest case adds routes and delegates the execution to the method annotated with the {@link Path} annotation. * * @param clazz * @param method * @param httpMethod * @param path * @throws Exception */ private void addBinding(final Class<?> clazz, final Method method, final Object instance, final HttpMethod httpMethod, String path) throws Exception { final Produces produces = method.getAnnotation(Produces.class); final Consumes consumes = method.getAnnotation(Consumes.class); final String finalPath = UriPathUtil.convertPath(path); bindingHolder.addBinding(httpMethod, finalPath, consumes, produces, instance, clazz, method); } }