forked from community/device-mgt-core
parent
3bef5155e0
commit
6d9f2f92a4
@ -1,364 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* WSO2 Inc. licenses this file to you 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 org.wso2.carbon.apimgt.webapp.publisher.lifecycle.util;
|
|
||||||
|
|
||||||
import org.apache.catalina.core.StandardContext;
|
|
||||||
import org.apache.commons.lang.ArrayUtils;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.scannotation.AnnotationDB;
|
|
||||||
import org.scannotation.WarUrlFinder;
|
|
||||||
import org.wso2.carbon.apimgt.annotations.api.API;
|
|
||||||
import org.wso2.carbon.apimgt.annotations.api.Permission;
|
|
||||||
import org.wso2.carbon.apimgt.api.model.Scope;
|
|
||||||
import org.wso2.carbon.apimgt.webapp.publisher.config.APIResource;
|
|
||||||
import org.wso2.carbon.apimgt.webapp.publisher.config.APIResourceConfiguration;
|
|
||||||
import org.wso2.carbon.apimgt.webapp.publisher.config.PermissionConfiguration;
|
|
||||||
import org.wso2.carbon.apimgt.webapp.publisher.config.PermissionManagementException;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import javax.ws.rs.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class AnnotationUtil {
|
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(AnnotationUtil.class);
|
|
||||||
|
|
||||||
private static final String PACKAGE_ORG_APACHE = "org.apache";
|
|
||||||
private static final String PACKAGE_ORG_CODEHAUS = "org.codehaus";
|
|
||||||
private static final String PACKAGE_ORG_SPRINGFRAMEWORK = "org.springframework";
|
|
||||||
|
|
||||||
private static final String AUTH_TYPE = "Any";
|
|
||||||
private static final String PROTOCOL_HTTP = "http";
|
|
||||||
private static final String SERVER_HOST = "carbon.local.ip";
|
|
||||||
private static final String HTTP_PORT = "httpPort";
|
|
||||||
private static final String STRING_ARR = "string_arr";
|
|
||||||
private static final String STRING = "string";
|
|
||||||
|
|
||||||
private StandardContext context;
|
|
||||||
private Method[] pathClazzMethods;
|
|
||||||
private Class<Path> pathClazz;
|
|
||||||
Class<API> apiClazz;
|
|
||||||
private ClassLoader classLoader;
|
|
||||||
private ServletContext servletContext;
|
|
||||||
|
|
||||||
|
|
||||||
public AnnotationUtil(final StandardContext context) {
|
|
||||||
this.context = context;
|
|
||||||
servletContext = context.getServletContext();
|
|
||||||
classLoader = servletContext.getClassLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan the context for classes with annotations
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public Set<String> scanStandardContext(String className) throws IOException {
|
|
||||||
AnnotationDB db = new AnnotationDB();
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_APACHE);
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_CODEHAUS);
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_SPRINGFRAMEWORK);
|
|
||||||
|
|
||||||
URL[] libPath = WarUrlFinder.findWebInfLibClasspaths(servletContext);
|
|
||||||
URL classPath = WarUrlFinder.findWebInfClassesPath(servletContext);
|
|
||||||
URL[] urls = (URL[]) ArrayUtils.add(libPath, libPath.length, classPath);
|
|
||||||
|
|
||||||
db.scanArchives(urls);
|
|
||||||
|
|
||||||
//Returns a list of classes with given Annotation
|
|
||||||
return db.getAnnotationIndex().get(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method identifies the URL templates and context by reading the annotations of a class
|
|
||||||
*
|
|
||||||
* @param entityClasses
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<APIResourceConfiguration> extractAPIInfo(final ServletContext servletContext, Set<String> entityClasses)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
|
|
||||||
List<APIResourceConfiguration> apiResourceConfigs = new ArrayList<APIResourceConfiguration>();
|
|
||||||
|
|
||||||
if (entityClasses != null && !entityClasses.isEmpty()) {
|
|
||||||
for (final String className : entityClasses) {
|
|
||||||
|
|
||||||
APIResourceConfiguration resource =
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<APIResourceConfiguration>() {
|
|
||||||
public APIResourceConfiguration run() {
|
|
||||||
Class<?> clazz = null;
|
|
||||||
APIResourceConfiguration apiResourceConfig = null;
|
|
||||||
try {
|
|
||||||
clazz = classLoader.loadClass(className);
|
|
||||||
|
|
||||||
apiClazz = (Class<API>)
|
|
||||||
classLoader.loadClass(org.wso2.carbon.apimgt.annotations.api.API
|
|
||||||
.class.getName());
|
|
||||||
|
|
||||||
Annotation apiAnno = clazz.getAnnotation(apiClazz);
|
|
||||||
List<APIResource> resourceList;
|
|
||||||
|
|
||||||
if (apiAnno != null) {
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Application Context root = " + servletContext.getContextPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
apiResourceConfig = processAPIAnnotation(apiAnno);
|
|
||||||
// All the apis should map to same root "/"
|
|
||||||
String rootContext = servletContext.getContextPath();
|
|
||||||
pathClazz = (Class<Path>) classLoader.loadClass(Path.class.getName());
|
|
||||||
pathClazzMethods = pathClazz.getMethods();
|
|
||||||
|
|
||||||
Annotation rootContectAnno = clazz.getAnnotation(pathClazz);
|
|
||||||
String subContext = "";
|
|
||||||
if (rootContectAnno != null) {
|
|
||||||
subContext = invokeMethod(pathClazzMethods[0], rootContectAnno, STRING);
|
|
||||||
if (subContext != null && !subContext.isEmpty()) {
|
|
||||||
rootContext = rootContext + "/" + subContext;
|
|
||||||
} else {
|
|
||||||
subContext = "";
|
|
||||||
}
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("API Root Context = " + rootContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Method[] annotatedMethods = clazz.getDeclaredMethods();
|
|
||||||
resourceList = getApiResources(rootContext, subContext, annotatedMethods);
|
|
||||||
apiResourceConfig.setResources(resourceList);
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
log.error("Error encountered while scanning for annotations", throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
log.error("Error when passing the api annotation for device type apis.");
|
|
||||||
}
|
|
||||||
return apiResourceConfig;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
apiResourceConfigs.add(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apiResourceConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate API annotation and build API Configuration
|
|
||||||
* @param apiAnno
|
|
||||||
* @return
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
private APIResourceConfiguration processAPIAnnotation(Annotation apiAnno) throws Throwable {
|
|
||||||
Method[] apiClazzMethods = apiClazz.getMethods();
|
|
||||||
APIResourceConfiguration apiResourceConfig = new APIResourceConfiguration();
|
|
||||||
for (int k = 0; k < apiClazzMethods.length; k++) {
|
|
||||||
switch (apiClazzMethods[k].getName()) {
|
|
||||||
case "name":
|
|
||||||
apiResourceConfig.setName(invokeMethod(apiClazzMethods[k], apiAnno, STRING));
|
|
||||||
break;
|
|
||||||
case "version":
|
|
||||||
apiResourceConfig.setVersion(invokeMethod(apiClazzMethods[k], apiAnno, STRING));
|
|
||||||
break;
|
|
||||||
case "context":
|
|
||||||
apiResourceConfig.setContext(invokeMethod(apiClazzMethods[k], apiAnno, STRING));
|
|
||||||
break;
|
|
||||||
case "tags":
|
|
||||||
apiResourceConfig.setTags(invokeMethod(apiClazzMethods[k], apiAnno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apiResourceConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Resources for each API
|
|
||||||
* @param resourceRootContext
|
|
||||||
* @param apiRootContext
|
|
||||||
* @param annotatedMethods
|
|
||||||
* @return
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
private List<APIResource> getApiResources(String resourceRootContext, String apiRootContext,
|
|
||||||
Method[] annotatedMethods) throws Throwable {
|
|
||||||
List<APIResource> resourceList;
|
|
||||||
resourceList = new ArrayList<APIResource>();
|
|
||||||
for (Method method : annotatedMethods) {
|
|
||||||
Annotation methodContextAnno = method.getAnnotation(pathClazz);
|
|
||||||
if (methodContextAnno != null) {
|
|
||||||
String subCtx = invokeMethod(pathClazzMethods[0], methodContextAnno, STRING);
|
|
||||||
APIResource resource = new APIResource();
|
|
||||||
resource.setUriTemplate(makeContextURLReady(apiRootContext + subCtx));
|
|
||||||
|
|
||||||
String serverIP = System.getProperty(SERVER_HOST);
|
|
||||||
String httpServerPort = System.getProperty(HTTP_PORT);
|
|
||||||
|
|
||||||
resource.setUri(PROTOCOL_HTTP + "://" + serverIP + ":" + httpServerPort + makeContextURLReady(
|
|
||||||
resourceRootContext) + makeContextURLReady(subCtx));
|
|
||||||
resource.setAuthType(AUTH_TYPE);
|
|
||||||
|
|
||||||
Annotation[] annotations = method.getDeclaredAnnotations();
|
|
||||||
for (int i = 0; i < annotations.length; i++) {
|
|
||||||
processHTTPMethodAnnotation(resource, annotations[i]);
|
|
||||||
if (annotations[i].annotationType().getName().equals(Consumes.class.getName())) {
|
|
||||||
Class<Consumes> consumesClass = (Class<Consumes>) classLoader.loadClass(
|
|
||||||
Consumes.class.getName());
|
|
||||||
Method[] consumesClassMethods = consumesClass.getMethods();
|
|
||||||
Annotation consumesAnno = method.getAnnotation(consumesClass);
|
|
||||||
resource.setConsumes(invokeMethod(consumesClassMethods[0], consumesAnno, STRING_ARR));
|
|
||||||
}
|
|
||||||
if (annotations[i].annotationType().getName().equals(Produces.class.getName())) {
|
|
||||||
Class<Produces> producesClass = (Class<Produces>) classLoader.loadClass(
|
|
||||||
Produces.class.getName());
|
|
||||||
Method[] producesClassMethods = producesClass.getMethods();
|
|
||||||
Annotation producesAnno = method.getAnnotation(producesClass);
|
|
||||||
resource.setProduces(invokeMethod(producesClassMethods[0], producesAnno, STRING_ARR));
|
|
||||||
}
|
|
||||||
if (annotations[i].annotationType().getName().equals(Permission.class.getName())) {
|
|
||||||
PermissionConfiguration permissionConf = this.getPermission(method);
|
|
||||||
if (permissionConf != null) {
|
|
||||||
Scope scope = new Scope();
|
|
||||||
scope.setKey(permissionConf.getScopeName());
|
|
||||||
scope.setDescription(permissionConf.getScopeName());
|
|
||||||
scope.setName(permissionConf.getScopeName());
|
|
||||||
String roles = StringUtils.join(permissionConf.getPermissions(), ",");
|
|
||||||
scope.setRoles(roles);
|
|
||||||
resource.setScope(scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resourceList.add(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resourceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Method annotations indicating HTTP Methods
|
|
||||||
* @param resource
|
|
||||||
* @param annotation
|
|
||||||
*/
|
|
||||||
private void processHTTPMethodAnnotation(APIResource resource, Annotation annotation) {
|
|
||||||
if (annotation.annotationType().getName().equals(GET.class.getName())) {
|
|
||||||
resource.setHttpVerb(HttpMethod.GET);
|
|
||||||
}
|
|
||||||
if (annotation.annotationType().getName().equals(POST.class.getName())) {
|
|
||||||
resource.setHttpVerb(HttpMethod.POST);
|
|
||||||
}
|
|
||||||
if (annotation.annotationType().getName().equals(OPTIONS.class.getName())) {
|
|
||||||
resource.setHttpVerb(HttpMethod.OPTIONS);
|
|
||||||
}
|
|
||||||
if (annotation.annotationType().getName().equals(DELETE.class.getName())) {
|
|
||||||
resource.setHttpVerb(HttpMethod.DELETE);
|
|
||||||
}
|
|
||||||
if (annotation.annotationType().getName().equals(PUT.class.getName())) {
|
|
||||||
resource.setHttpVerb(HttpMethod.PUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append '/' to the context and make it URL ready
|
|
||||||
* @param context
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String makeContextURLReady(String context) {
|
|
||||||
if (context != null && !context.equalsIgnoreCase("")) {
|
|
||||||
if (context.startsWith("/")) {
|
|
||||||
return context;
|
|
||||||
} else {
|
|
||||||
return "/" + context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an annotation and method is passed, this method invokes that executes said method against the annotation
|
|
||||||
*
|
|
||||||
* @param method
|
|
||||||
* @param annotation
|
|
||||||
* @param returnType
|
|
||||||
* @return
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
private String invokeMethod(Method method, Annotation annotation, String returnType) throws Throwable {
|
|
||||||
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
|
|
||||||
switch (returnType) {
|
|
||||||
case STRING:
|
|
||||||
return (String) methodHandler.invoke(annotation, method, null);
|
|
||||||
case STRING_ARR:
|
|
||||||
return ((String[]) methodHandler.invoke(annotation, method, null))[0];
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an annotation and method is passed, this method invokes that executes said method against the annotation
|
|
||||||
*/
|
|
||||||
private String[] invokeMethod(Method method, Annotation annotation) throws Throwable {
|
|
||||||
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
|
|
||||||
return ((String[]) methodHandler.invoke(annotation, method, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private PermissionConfiguration getPermission(Method currentMethod) throws Throwable {
|
|
||||||
Class<Permission> permissionClass = (Class<Permission>) classLoader.loadClass(Permission.class.getName());
|
|
||||||
Annotation permissionAnnotation = currentMethod.getAnnotation(permissionClass);
|
|
||||||
if (permissionClass != null) {
|
|
||||||
Method[] permissionClassMethods = permissionClass.getMethods();
|
|
||||||
PermissionConfiguration permissionConf = new PermissionConfiguration();
|
|
||||||
for (Method method : permissionClassMethods) {
|
|
||||||
switch (method.getName()) {
|
|
||||||
case "scope":
|
|
||||||
permissionConf.setScopeName(invokeMethod(method, permissionAnnotation, STRING));
|
|
||||||
break;
|
|
||||||
case "permissions":
|
|
||||||
String permissions[] = invokeMethod(method, permissionAnnotation);
|
|
||||||
this.addPermission(permissions);
|
|
||||||
permissionConf.setPermissions(permissions);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return permissionConf;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPermission(String[] permissions) throws PermissionManagementException {
|
|
||||||
for (String permission : permissions) {
|
|
||||||
PermissionUtils.addPermission(permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,279 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* WSO2 Inc. licenses this file to you 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 org.wso2.carbon.device.mgt.extensions.feature.mgt.util;
|
|
||||||
|
|
||||||
import org.apache.catalina.core.StandardContext;
|
|
||||||
import org.apache.commons.lang.ArrayUtils;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.scannotation.AnnotationDB;
|
|
||||||
import org.scannotation.WarUrlFinder;
|
|
||||||
import org.wso2.carbon.device.mgt.common.Feature;
|
|
||||||
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
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;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This has the utility function to extract feature information.
|
|
||||||
*/
|
|
||||||
public class AnnotationUtil {
|
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(AnnotationUtil.class);
|
|
||||||
|
|
||||||
private static final String PACKAGE_ORG_APACHE = "org.apache";
|
|
||||||
private static final String PACKAGE_ORG_CODEHAUS = "org.codehaus";
|
|
||||||
private static final String PACKAGE_ORG_SPRINGFRAMEWORK = "org.springframework";
|
|
||||||
private static final String STRING_ARR = "string_arr";
|
|
||||||
private static final String STRING = "string";
|
|
||||||
private static final String METHOD = "method";
|
|
||||||
private Class<org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature>
|
|
||||||
featureAnnotationClazz;
|
|
||||||
private ClassLoader classLoader;
|
|
||||||
private ServletContext servletContext;
|
|
||||||
|
|
||||||
|
|
||||||
public AnnotationUtil(final StandardContext context) {
|
|
||||||
servletContext = context.getServletContext();
|
|
||||||
classLoader = servletContext.getClassLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan the context for classes with annotations
|
|
||||||
*/
|
|
||||||
public Set<String> scanStandardContext(String className) throws IOException {
|
|
||||||
AnnotationDB db = new AnnotationDB();
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_APACHE);
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_CODEHAUS);
|
|
||||||
db.addIgnoredPackages(PACKAGE_ORG_SPRINGFRAMEWORK);
|
|
||||||
URL[] libPath = WarUrlFinder.findWebInfLibClasspaths(servletContext);
|
|
||||||
URL classPath = WarUrlFinder.findWebInfClassesPath(servletContext);
|
|
||||||
URL[] urls = (URL[]) ArrayUtils.add(libPath, libPath.length, classPath);
|
|
||||||
db.scanArchives(urls);
|
|
||||||
|
|
||||||
//Returns a list of classes with given Annotation
|
|
||||||
return db.getAnnotationIndex().get(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method identifies the URL templates and context by reading the annotations of a class
|
|
||||||
*/
|
|
||||||
public Map<String, List<Feature>> extractFeatures(Set<String> entityClasses) throws ClassNotFoundException {
|
|
||||||
Map<String, List<Feature>> features = null;
|
|
||||||
if (entityClasses != null && !entityClasses.isEmpty()) {
|
|
||||||
features = new HashMap<>();
|
|
||||||
for (final String className : entityClasses) {
|
|
||||||
final Map<String, List<Feature>> featureMap =
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Map<String, List<Feature>>>() {
|
|
||||||
public Map<String, List<Feature>> run() {
|
|
||||||
Map<String, List<Feature>> featureMap = new HashMap<>();
|
|
||||||
try {
|
|
||||||
Class<?> clazz = classLoader.loadClass(className);
|
|
||||||
Class<DeviceType> deviceTypeClazz = (Class<DeviceType>) classLoader.loadClass(
|
|
||||||
DeviceType.class.getName());
|
|
||||||
Annotation deviceTypeAnno = clazz.getAnnotation(deviceTypeClazz);
|
|
||||||
if (deviceTypeAnno != null) {
|
|
||||||
Method[] deviceTypeMethod = deviceTypeClazz.getMethods();
|
|
||||||
String deviceType = invokeMethod(deviceTypeMethod[0], deviceTypeAnno, STRING);
|
|
||||||
featureAnnotationClazz =
|
|
||||||
(Class<org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations
|
|
||||||
.Feature>) classLoader.loadClass(
|
|
||||||
org.wso2.carbon.device.mgt.extensions.feature.mgt
|
|
||||||
.annotations.Feature.class.getName());
|
|
||||||
List<Feature> featureList = getFeatures(clazz.getDeclaredMethods());
|
|
||||||
featureMap.put(deviceType, featureList);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error("Failed to load the annotation from the features in the " +
|
|
||||||
"class " + className, e);
|
|
||||||
}
|
|
||||||
return featureMap;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
features.putAll(featureMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Feature> getFeatures(Method[] methodsList) throws Throwable {
|
|
||||||
List<Feature> featureList = new ArrayList<>();
|
|
||||||
for (Method currentMethod : methodsList) {
|
|
||||||
Annotation featureAnnotation = currentMethod.getAnnotation(featureAnnotationClazz);
|
|
||||||
if (featureAnnotation != null) {
|
|
||||||
Feature feature = new Feature();
|
|
||||||
feature = processFeatureAnnotation(feature, currentMethod);
|
|
||||||
Annotation[] annotations = currentMethod.getDeclaredAnnotations();
|
|
||||||
Feature.MetadataEntry metadataEntry = new Feature.MetadataEntry();
|
|
||||||
metadataEntry.setId(-1);
|
|
||||||
Map<String, Object> apiParams = new HashMap<>();
|
|
||||||
for (int i = 0; i < annotations.length; i++) {
|
|
||||||
Annotation currentAnnotation = annotations[i];
|
|
||||||
processHttpMethodAnnotation(apiParams, currentAnnotation);
|
|
||||||
if (currentAnnotation.annotationType().getName().equals(Path.class.getName())) {
|
|
||||||
String uri = getPathAnnotationValue(currentMethod);
|
|
||||||
apiParams.put("uri", uri);
|
|
||||||
}
|
|
||||||
apiParams = processParamAnnotations(apiParams, currentMethod);
|
|
||||||
}
|
|
||||||
metadataEntry.setValue(apiParams);
|
|
||||||
List<Feature.MetadataEntry> metaInfoList = new ArrayList<>();
|
|
||||||
metaInfoList.add(metadataEntry);
|
|
||||||
feature.setMetadataEntries(metaInfoList);
|
|
||||||
featureList.add(feature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return featureList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> processParamAnnotations(Map<String, Object> apiParams, Method currentMethod)
|
|
||||||
throws Throwable{
|
|
||||||
try {
|
|
||||||
apiParams.put("pathParams", processParamAnnotations(currentMethod, PathParam.class));
|
|
||||||
apiParams.put("queryParams", processParamAnnotations(currentMethod, QueryParam.class));
|
|
||||||
apiParams.put("formParams", processParamAnnotations(currentMethod, FormParam.class));
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
log.debug("No Form Param found for class " + featureAnnotationClazz.getName());
|
|
||||||
}
|
|
||||||
return apiParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> processParamAnnotations(Method currentMethod, Class<?> clazz) throws Throwable{
|
|
||||||
List<String> params = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
Class<?> paramClazz = (Class<?>) classLoader.loadClass(clazz.getName());
|
|
||||||
Method[] formMethods = paramClazz.getMethods();
|
|
||||||
//Extract method parameter information and store same as feature meta info
|
|
||||||
Annotation[][] paramAnnotations = currentMethod.getParameterAnnotations();
|
|
||||||
Method valueMethod = formMethods[0];
|
|
||||||
for (int j = 0; j < paramAnnotations.length; j++) {
|
|
||||||
for (Annotation anno : paramAnnotations[j]) {
|
|
||||||
if (anno.annotationType().getName().equals(clazz.getName())) {
|
|
||||||
params.add(invokeMethod(valueMethod, anno, STRING));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
log.debug("No "+ clazz.getName() +" Param found for class " + featureAnnotationClazz.getName());
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Method annotations indicating HTTP Methods
|
|
||||||
*/
|
|
||||||
private void processHttpMethodAnnotation(Map<String, Object> apiParams, Annotation currentAnnotation) {
|
|
||||||
//Extracting method with which feature is exposed
|
|
||||||
if (currentAnnotation.annotationType().getName().equals(GET.class.getName())) {
|
|
||||||
apiParams.put(METHOD, HttpMethod.GET);
|
|
||||||
} else if (currentAnnotation.annotationType().getName().equals(POST.class.getName())) {
|
|
||||||
apiParams.put(METHOD, HttpMethod.POST);
|
|
||||||
} else if (currentAnnotation.annotationType().getName().equals(OPTIONS.class.getName())) {
|
|
||||||
apiParams.put(METHOD, HttpMethod.OPTIONS);
|
|
||||||
} else if (currentAnnotation.annotationType().getName().equals(DELETE.class.getName())) {
|
|
||||||
apiParams.put(METHOD, HttpMethod.DELETE);
|
|
||||||
} else if (currentAnnotation.annotationType().getName().equals(PUT.class.getName())) {
|
|
||||||
apiParams.put(METHOD, HttpMethod.PUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Feature annotation and Identify Features
|
|
||||||
* @param feature
|
|
||||||
* @param currentMethod
|
|
||||||
* @return
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
private Feature processFeatureAnnotation(Feature feature, Method currentMethod) throws Throwable{
|
|
||||||
Method[] featureAnnoMethods = featureAnnotationClazz.getMethods();
|
|
||||||
Annotation featureAnno = currentMethod.getAnnotation(featureAnnotationClazz);
|
|
||||||
for (int k = 0; k < featureAnnoMethods.length; k++) {
|
|
||||||
switch (featureAnnoMethods[k].getName()) {
|
|
||||||
case "name":
|
|
||||||
feature.setName(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
|
|
||||||
break;
|
|
||||||
case "code":
|
|
||||||
feature.setCode(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
|
|
||||||
break;
|
|
||||||
case "description":
|
|
||||||
feature.setDescription(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return feature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value depicted by Path Annotation
|
|
||||||
* @param currentMethod
|
|
||||||
* @return
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
public String getPathAnnotationValue(Method currentMethod) throws Throwable{
|
|
||||||
String uri = "";
|
|
||||||
try {
|
|
||||||
Class<Path> pathClazz = (Class<Path>) classLoader.loadClass(Path.class.getName());
|
|
||||||
Annotation pathAnnno = currentMethod.getAnnotation(pathClazz);
|
|
||||||
Method[] pathMethods = pathClazz.getMethods();
|
|
||||||
Method valueMethod = pathMethods[0];
|
|
||||||
uri = invokeMethod(valueMethod, pathAnnno, STRING);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
log.debug("No Path Param found for class " + featureAnnotationClazz.getName());
|
|
||||||
}
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an annotation and method is passed, this method invokes that executes said method against the annotation
|
|
||||||
*/
|
|
||||||
private String invokeMethod(Method method, Annotation annotation, String returnType) throws Throwable {
|
|
||||||
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
|
|
||||||
switch (returnType) {
|
|
||||||
case STRING:
|
|
||||||
return (String) methodHandler.invoke(annotation, method, null);
|
|
||||||
case STRING_ARR:
|
|
||||||
return ((String[]) methodHandler.invoke(annotation, method, null))[0];
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue