diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/pom.xml b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/pom.xml index 7da850e7a94..63176b19db8 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/pom.xml +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/pom.xml @@ -105,6 +105,10 @@ org.wso2.carbon.governance org.wso2.carbon.governance.lcm + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/listener/APIPublisherLifecycleListener.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/listener/APIPublisherLifecycleListener.java index f3ecf346207..b04f2a5f599 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/listener/APIPublisherLifecycleListener.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/listener/APIPublisherLifecycleListener.java @@ -30,7 +30,8 @@ import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherService; import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherUtil; import org.wso2.carbon.apimgt.webapp.publisher.config.APIResourceConfiguration; import org.wso2.carbon.apimgt.webapp.publisher.internal.APIPublisherDataHolder; -import org.wso2.carbon.apimgt.webapp.publisher.lifecycle.util.AnnotationUtil; +import org.wso2.carbon.apimgt.webapp.publisher.lifecycle.util.AnnotationProcessor; +import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; import javax.servlet.ServletContext; import java.io.IOException; @@ -51,13 +52,16 @@ public class APIPublisherLifecycleListener implements LifecycleListener { String param = servletContext.getInitParameter(PARAM_MANAGED_API_ENABLED); boolean isManagedApi = (param != null && !param.isEmpty()) && Boolean.parseBoolean(param); - if (isManagedApi) { + String profile = System.getProperty(DeviceManagementConstants.Common.PROPERTY_PROFILE); + + if ((profile.equalsIgnoreCase(DeviceManagementConstants.Common.PROFILE_DT_GOVERN) || + profile.equalsIgnoreCase(DeviceManagementConstants.Common.PROFILE_DEFAULT)) && isManagedApi) { try { - AnnotationUtil annotationUtil = new AnnotationUtil(context); - Set annotatedAPIClasses = annotationUtil. + AnnotationProcessor annotationProcessor = new AnnotationProcessor(context); + Set annotatedAPIClasses = annotationProcessor. scanStandardContext(org.wso2.carbon.apimgt.annotations.api.API.class.getName()); - List apiDefinitions = annotationUtil.extractAPIInfo(servletContext, + List apiDefinitions = annotationProcessor.extractAPIInfo(servletContext, annotatedAPIClasses); for (APIResourceConfiguration apiDefinition : apiDefinitions) { diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationUtil.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationUtil.java deleted file mode 100644 index 4974a54c0eb..00000000000 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationUtil.java +++ /dev/null @@ -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 pathClazz; - Class 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 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 extractAPIInfo(final ServletContext servletContext, Set entityClasses) - throws ClassNotFoundException { - - List apiResourceConfigs = new ArrayList(); - - if (entityClasses != null && !entityClasses.isEmpty()) { - for (final String className : entityClasses) { - - APIResourceConfiguration resource = - AccessController.doPrivileged(new PrivilegedAction() { - public APIResourceConfiguration run() { - Class clazz = null; - APIResourceConfiguration apiResourceConfig = null; - try { - clazz = classLoader.loadClass(className); - - apiClazz = (Class) - classLoader.loadClass(org.wso2.carbon.apimgt.annotations.api.API - .class.getName()); - - Annotation apiAnno = clazz.getAnnotation(apiClazz); - List 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) 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 getApiResources(String resourceRootContext, String apiRootContext, - Method[] annotatedMethods) throws Throwable { - List resourceList; - resourceList = new ArrayList(); - 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 consumesClass = (Class) 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 producesClass = (Class) 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 permissionClass = (Class) 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); - } - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java index 379ca8c3d6c..f4c2ba61f4a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java @@ -28,6 +28,9 @@ public final class DeviceManagementConstants { public static final String PROPERTY_SETUP = "setup"; public static final String DEFAULT_LICENSE_CONFIG_XML_NAME = "license-config.xml"; + public static final String PROPERTY_PROFILE = "profile"; + public static final String PROFILE_DT_GOVERN = "deviceTypeGovern"; + public static final String PROFILE_DEFAULT = "default"; } public static final class AppManagement { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java index 31dc99187a0..ee11038ca47 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java @@ -17,6 +17,7 @@ */ package org.wso2.carbon.device.mgt.core.config; +import org.wso2.carbon.device.mgt.core.config.deviceType.DTConfiguration; import org.wso2.carbon.device.mgt.core.config.identity.IdentityConfigurations; import org.wso2.carbon.device.mgt.core.config.policy.PolicyConfiguration; import org.wso2.carbon.device.mgt.core.config.task.TaskConfiguration; @@ -37,6 +38,7 @@ public final class DeviceManagementConfig { private IdentityConfigurations identityConfigurations; private PolicyConfiguration policyConfiguration; //private List pushNotificationProviders; + private DTConfiguration dTDepyloymentConfiguration; @XmlElement(name = "ManagementRepository", required = true) public DeviceManagementConfigRepository getDeviceManagementConfigRepository() { @@ -75,6 +77,15 @@ public final class DeviceManagementConfig { this.taskConfiguration = taskConfiguration; } + @XmlElement(name = "DTDeploymentConfiguration", required = true) + public DTConfiguration getDTDeploymentConfiguration() { + return dTDepyloymentConfiguration; + } + + public void setDTDeploymentConfiguration(DTConfiguration dTDeploymentConfiguration) { + this.dTDepyloymentConfiguration = dTDeploymentConfiguration; + } + // @XmlElementWrapper(name = "PushNotificationProviders", required = true) // @XmlElement(name = "Provider", required = true) // public List getPushNotificationProviders() { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/pom.xml index 6cb83f59746..41aa93f835e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/pom.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/pom.xml @@ -90,6 +90,10 @@ commons-lang.wso2 commons-lang + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + @@ -110,6 +114,7 @@ org.wso2.carbon.governance.api.*, javax.xml.namespace;resolution:=optional, + org.wso2.carbon.device.mgt.core.*, org.wso2.carbon.context, org.wso2.carbon.device.mgt.common, org.wso2.carbon.device.mgt.common.license.mgt, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/lifecycle/listener/FeatureManagementLifecycleListener.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/lifecycle/listener/FeatureManagementLifecycleListener.java index 57ae592ee65..fde55173369 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/lifecycle/listener/FeatureManagementLifecycleListener.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/lifecycle/listener/FeatureManagementLifecycleListener.java @@ -24,9 +24,10 @@ import org.apache.catalina.core.StandardContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; -import org.wso2.carbon.device.mgt.extensions.feature.mgt.util.AnnotationUtil; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.util.AnnotationProcessor; import javax.servlet.ServletContext; import java.io.IOException; @@ -51,11 +52,15 @@ public class FeatureManagementLifecycleListener implements LifecycleListener { ServletContext servletContext = context.getServletContext(); String param = servletContext.getInitParameter(PARAM_MANAGED_API_ENABLED); boolean isManagedApi = (param != null && !param.isEmpty()) && Boolean.parseBoolean(param); - if (isManagedApi) { + + String profile = System.getProperty(DeviceManagementConstants.Common.PROPERTY_PROFILE); + + if ((profile.equalsIgnoreCase(DeviceManagementConstants.Common.PROFILE_DT_GOVERN) || + profile.equalsIgnoreCase(DeviceManagementConstants.Common.PROFILE_DEFAULT)) && isManagedApi) { try { - AnnotationUtil annotationUtil = new AnnotationUtil(context); - Set annotatedAPIClasses = annotationUtil.scanStandardContext(DeviceType.class.getName()); - Map> features = annotationUtil.extractFeatures(annotatedAPIClasses); + AnnotationProcessor annotationProcessor = new AnnotationProcessor(context); + Set annotatedAPIClasses = annotationProcessor.scanStandardContext(DeviceType.class.getName()); + Map> features = annotationProcessor.extractFeatures(annotatedAPIClasses); if (features != null && !features.isEmpty()) { GenericFeatureManager.getInstance().addFeatures(features); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationUtil.java deleted file mode 100644 index a70c9c5dc14..00000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationUtil.java +++ /dev/null @@ -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 - 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 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> extractFeatures(Set entityClasses) throws ClassNotFoundException { - Map> features = null; - if (entityClasses != null && !entityClasses.isEmpty()) { - features = new HashMap<>(); - for (final String className : entityClasses) { - final Map> featureMap = - AccessController.doPrivileged(new PrivilegedAction>>() { - public Map> run() { - Map> featureMap = new HashMap<>(); - try { - Class clazz = classLoader.loadClass(className); - Class deviceTypeClazz = (Class) 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) classLoader.loadClass( - org.wso2.carbon.device.mgt.extensions.feature.mgt - .annotations.Feature.class.getName()); - List 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 getFeatures(Method[] methodsList) throws Throwable { - List 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 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 metaInfoList = new ArrayList<>(); - metaInfoList.add(metadataEntry); - feature.setMetadataEntries(metaInfoList); - featureList.add(feature); - } - } - return featureList; - } - - private Map processParamAnnotations(Map 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 processParamAnnotations(Method currentMethod, Class clazz) throws Throwable{ - List 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 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 pathClazz = (Class) 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; - } - } -} \ No newline at end of file