forked from community/device-mgt-core
parent
59028f9f09
commit
49623a4693
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* 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.device.mgt.core.config.permission;
|
||||||
|
|
||||||
|
import org.apache.catalina.core.StandardContext;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.scannotation.AnnotationDB;
|
||||||
|
import org.wso2.carbon.apimgt.annotations.api.API;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import java.io.File;
|
||||||
|
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.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
public class AnnotationProcessor {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(AnnotationProcessor.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 WILD_CARD = "/*";
|
||||||
|
private static final String URL_SEPARATOR = "/";
|
||||||
|
|
||||||
|
private static final String STRING_ARR = "string_arr";
|
||||||
|
private static final String STRING = "string";
|
||||||
|
|
||||||
|
private Method[] pathClazzMethods;
|
||||||
|
private Class<Path> pathClazz;
|
||||||
|
Class<API> apiClazz;
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
private ServletContext servletContext;
|
||||||
|
|
||||||
|
|
||||||
|
public AnnotationProcessor(final StandardContext 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 classPath = findWebInfClassesPath(servletContext);
|
||||||
|
db.scanArchives(classPath);
|
||||||
|
|
||||||
|
//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<org.wso2.carbon.device.mgt.common.permission.mgt.Permission>
|
||||||
|
extractPermissions(Set<String> entityClasses) {
|
||||||
|
|
||||||
|
List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> permissions = new ArrayList<>();
|
||||||
|
|
||||||
|
if (entityClasses != null && !entityClasses.isEmpty()) {
|
||||||
|
|
||||||
|
for (final String className : entityClasses) {
|
||||||
|
|
||||||
|
List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> resourcePermissions =
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission>>() {
|
||||||
|
public List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> run() {
|
||||||
|
Class<?> clazz;
|
||||||
|
List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> apiPermissions =
|
||||||
|
new ArrayList<>();
|
||||||
|
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<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> resourceList;
|
||||||
|
|
||||||
|
if (apiAnno != null) {
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Application Context root = " + servletContext.getContextPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
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()) {
|
||||||
|
if (subContext.trim().startsWith("/")) {
|
||||||
|
rootContext = rootContext + subContext;
|
||||||
|
} else {
|
||||||
|
rootContext = rootContext + "/" + subContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("API Root Context = " + rootContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Method[] annotatedMethods = clazz.getDeclaredMethods();
|
||||||
|
apiPermissions = getApiResources(rootContext, annotatedMethods);
|
||||||
|
} 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 apiPermissions;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
permissions.addAll(resourcePermissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Resources for each API
|
||||||
|
*
|
||||||
|
* @param resourceRootContext
|
||||||
|
* @param annotatedMethods
|
||||||
|
* @return
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
private List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission>
|
||||||
|
getApiResources(String resourceRootContext, Method[] annotatedMethods) throws Throwable {
|
||||||
|
|
||||||
|
List<org.wso2.carbon.device.mgt.common.permission.mgt.Permission> permissions = new ArrayList<>();
|
||||||
|
String subCtx;
|
||||||
|
for (Method method : annotatedMethods) {
|
||||||
|
Annotation[] annotations = method.getDeclaredAnnotations();
|
||||||
|
org.wso2.carbon.device.mgt.common.permission.mgt.Permission permission =
|
||||||
|
new org.wso2.carbon.device.mgt.common.permission.mgt.Permission();
|
||||||
|
|
||||||
|
if (isHttpMethodAvailable(annotations)) {
|
||||||
|
Annotation methodContextAnno = method.getAnnotation(pathClazz);
|
||||||
|
if (methodContextAnno != null) {
|
||||||
|
subCtx = invokeMethod(pathClazzMethods[0], methodContextAnno, STRING);
|
||||||
|
} else {
|
||||||
|
subCtx = WILD_CARD;
|
||||||
|
}
|
||||||
|
permission.setContext(makeContextURLReady(resourceRootContext));
|
||||||
|
permission.setUrlTemplate(makeContextURLReady(subCtx));
|
||||||
|
|
||||||
|
// this check is added to avoid url resolving conflict which happens due
|
||||||
|
// to adding of '*' notation for dynamic path variables.
|
||||||
|
if (WILD_CARD.equals(subCtx)) {
|
||||||
|
subCtx = makeContextURLReady(resourceRootContext);
|
||||||
|
} else {
|
||||||
|
subCtx = makeContextURLReady(resourceRootContext) + makeContextURLReady(subCtx);
|
||||||
|
}
|
||||||
|
permission.setUrl(replaceDynamicPathVariables(subCtx));
|
||||||
|
String httpMethod;
|
||||||
|
for (int i = 0; i < annotations.length; i++) {
|
||||||
|
httpMethod = getHTTPMethodAnnotation(annotations[i]);
|
||||||
|
if (httpMethod != null) {
|
||||||
|
permission.setMethod(httpMethod);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissions.add(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Method annotations indicating HTTP Methods
|
||||||
|
* @param annotation
|
||||||
|
*/
|
||||||
|
private String getHTTPMethodAnnotation(Annotation annotation) {
|
||||||
|
if (annotation.annotationType().getName().equals(GET.class.getName())) {
|
||||||
|
return HttpMethod.GET;
|
||||||
|
} else if (annotation.annotationType().getName().equals(POST.class.getName())) {
|
||||||
|
return HttpMethod.POST;
|
||||||
|
} else if (annotation.annotationType().getName().equals(OPTIONS.class.getName())) {
|
||||||
|
return HttpMethod.OPTIONS;
|
||||||
|
} else if (annotation.annotationType().getName().equals(DELETE.class.getName())) {
|
||||||
|
return HttpMethod.DELETE;
|
||||||
|
} else if (annotation.annotationType().getName().equals(PUT.class.getName())) {
|
||||||
|
return HttpMethod.PUT;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHttpMethodAvailable(Annotation[] annotations) {
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
if (annotation.annotationType().getName().equals(GET.class.getName())) {
|
||||||
|
return true;
|
||||||
|
} else if (annotation.annotationType().getName().equals(POST.class.getName())) {
|
||||||
|
return true;
|
||||||
|
} else if (annotation.annotationType().getName().equals(OPTIONS.class.getName())) {
|
||||||
|
return true;
|
||||||
|
} else if (annotation.annotationType().getName().equals(DELETE.class.getName())) {
|
||||||
|
return true;
|
||||||
|
} else if (annotation.annotationType().getName().equals(PUT.class.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append '/' to the context and make it URL ready
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String makeContextURLReady(String context) {
|
||||||
|
if (context != null && ! context.isEmpty()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the URL pointing to "/WEB-INF/classes" This method may not work in conjunction with IteratorFactory
|
||||||
|
* if your servlet container does not extract the /WEB-INF/classes into a real file-based directory
|
||||||
|
*
|
||||||
|
* @param servletContext
|
||||||
|
* @return null if cannot determin /WEB-INF/classes
|
||||||
|
*/
|
||||||
|
public static URL findWebInfClassesPath(ServletContext servletContext)
|
||||||
|
{
|
||||||
|
String path = servletContext.getRealPath("/WEB-INF/classes");
|
||||||
|
if (path == null) return null;
|
||||||
|
File fp = new File(path);
|
||||||
|
if (fp.exists() == false) return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URI uri = fp.toURI();
|
||||||
|
return uri.toURL();
|
||||||
|
}
|
||||||
|
catch (MalformedURLException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceDynamicPathVariables(String path) {
|
||||||
|
StringBuilder replacedPath = new StringBuilder();
|
||||||
|
StringTokenizer st = new StringTokenizer(path, URL_SEPARATOR);
|
||||||
|
String currentToken;
|
||||||
|
while (st.hasMoreTokens()) {
|
||||||
|
currentToken = st.nextToken();
|
||||||
|
if (currentToken.charAt(0) == '{') {
|
||||||
|
if (currentToken.charAt(currentToken.length() - 1) == '}') {
|
||||||
|
replacedPath.append(WILD_CARD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
replacedPath.append(URL_SEPARATOR);
|
||||||
|
replacedPath.append(currentToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replacedPath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,3 @@
|
|||||||
instructions.configure = \
|
instructions.configure = \
|
||||||
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
|
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
|
||||||
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v1.0.war,overwrite:true);\
|
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api-device-mgt-v1.0.war,target:${installFolder}/../../deployment/server/webapps/api-device-mgt-v1.0.war,overwrite:true);\
|
Loading…
Reference in new issue