From 6d9f2f92a40a46a60b985a0123b4a1f3ec74156d Mon Sep 17 00:00:00 2001 From: Ace Date: Sun, 15 May 2016 01:12:45 +0530 Subject: [PATCH 1/2] Making API publish destination configurable --- .../pom.xml | 4 + .../APIPublisherLifecycleListener.java | 14 +- .../lifecycle/util/AnnotationUtil.java | 364 ------------------ .../mgt/core/DeviceManagementConstants.java | 3 + .../core/config/DeviceManagementConfig.java | 11 + .../pom.xml | 5 + .../FeatureManagementLifecycleListener.java | 15 +- .../feature/mgt/util/AnnotationUtil.java | 279 -------------- 8 files changed, 42 insertions(+), 653 deletions(-) delete mode 100644 components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationUtil.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationUtil.java 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 7da850e7a9..63176b19db 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 f3ecf34620..b04f2a5f59 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 4974a54c0e..0000000000 --- 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 379ca8c3d6..f4c2ba61f4 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 31dc99187a..ee11038ca4 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 6cb83f5974..41aa93f835 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 57ae592ee6..fde5517336 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 a70c9c5dc1..0000000000 --- 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 From 4517a7f1aaa5e3d841b513739e224c359160d28b Mon Sep 17 00:00:00 2001 From: Ace Date: Sun, 15 May 2016 01:15:11 +0530 Subject: [PATCH 2/2] Making API publish destination configurable and other changes --- .../lifecycle/util/AnnotationProcessor.java | 373 ++++++++++++++++++ .../config/deviceType/DTConfiguration.java | 53 +++ .../feature/mgt/util/AnnotationProcessor.java | 279 +++++++++++++ 3 files changed, 705 insertions(+) create mode 100644 components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/deviceType/DTConfiguration.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationProcessor.java diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java new file mode 100644 index 0000000000..730c8c82dc --- /dev/null +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java @@ -0,0 +1,373 @@ +/* + * 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 org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; +import org.wso2.carbon.device.mgt.core.config.deviceType.DTConfiguration; + +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 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 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 AnnotationProcessor(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)); + + DTConfiguration deviceTypeConfig = DeviceConfigurationManager.getInstance(). + getDeviceManagementConfig().getDTDeploymentConfiguration(); + + String serverIP = deviceTypeConfig.getDtHostAddress(); + String httpServerPort = deviceTypeConfig.getDtHostPort(); + + 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/config/deviceType/DTConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/deviceType/DTConfiguration.java new file mode 100644 index 0000000000..14a3af1274 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/deviceType/DTConfiguration.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + + +/** + * This class will read the configurations related to task. This task will be responsible for adding the operations. + */ +package org.wso2.carbon.device.mgt.core.config.deviceType; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "DTDepyloymentConfiguration") +public class DTConfiguration { + + private String dtHostAddress; + private String dtHostPort; + + @XmlElement(name = "DTHostAddress", required = true) + public String getDtHostAddress() { + return dtHostAddress; + } + + public void setDtHostAddress(String dtHostAddress) { + this.dtHostAddress = dtHostAddress; + } + + @XmlElement(name = "DTHostPort", required = true) + public String getDtHostPort() { + return dtHostPort; + } + + public void setDtHostPort(String dtHostPort) { + this.dtHostPort = dtHostPort; + } + + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationProcessor.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationProcessor.java new file mode 100644 index 0000000000..2819d47ee1 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/feature/mgt/util/AnnotationProcessor.java @@ -0,0 +1,279 @@ +/* + * 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 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 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 AnnotationProcessor(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