/* * Copyright © 2014 Cask Data, Inc. * * 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 co.cask.cdap.internal.app.services; import co.cask.cdap.api.service.http.HttpServiceHandler; import co.cask.cdap.api.service.http.ServiceHttpEndpoint; import co.cask.cdap.internal.lang.MethodVisitor; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; import java.util.Set; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.HttpMethod; import javax.ws.rs.OPTIONS; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; /** * Extract the endpoints exposed by a {@link HttpServiceHandler}. */ public final class ServiceEndpointExtractor extends MethodVisitor { private final List<ServiceHttpEndpoint> endpoints; public ServiceEndpointExtractor(List<ServiceHttpEndpoint> endpoints) { this.endpoints = endpoints; } @Override public void visit(Object instance, Type inspectType, Type declareType, Method method) throws Exception { if (!Modifier.isPublic(method.getModifiers())) { return; } Path classPathAnnotation = TypeToken.of(inspectType).getRawType().getAnnotation(Path.class); Path methodPathAnnotation = method.getAnnotation(Path.class); if (methodPathAnnotation == null && classPathAnnotation == null) { return; } // Find one or more request type annotations present on the method. Set<Class<? extends Annotation>> acceptedMethodTypes = ImmutableSet.of(GET.class, POST.class, DELETE.class, PUT.class, OPTIONS.class, HEAD.class); Set<Class<? extends Annotation>> methodAnnotations = Sets.newHashSet(); for (Annotation annotation : method.getAnnotations()) { Class<? extends Annotation> annotationClz = annotation.annotationType(); if (acceptedMethodTypes.contains(annotationClz)) { methodAnnotations.add(annotationClz); } } for (Class<? extends Annotation> methodTypeClz : methodAnnotations) { String methodType = methodTypeClz.getAnnotation(HttpMethod.class).value(); String endpoint = "/"; endpoint = classPathAnnotation == null ? endpoint : endpoint + classPathAnnotation.value(); endpoint = methodPathAnnotation == null ? endpoint : endpoint + "/" + methodPathAnnotation.value(); // Replace consecutive instances of / with a single instance. endpoint = endpoint.replaceAll("/+", "/"); endpoints.add(new ServiceHttpEndpoint(methodType, endpoint)); } } }