From e71c3623094ce67c25270ab3959103cce484cfad Mon Sep 17 00:00:00 2001 From: charitha Date: Sun, 14 Apr 2019 15:58:51 +0530 Subject: [PATCH 01/27] Add device type specific platform config endpoint --- .../api/DeviceTypeManagementService.java | 239 +++++++++++------- .../DeviceTypeManagementAdminService.java | 164 +++++++++++- .../impl/DeviceTypeManagementServiceImpl.java | 117 +++++---- .../DeviceTypeManagementAdminServiceImpl.java | 75 +++++- .../src/main/webapp/WEB-INF/cxf-servlet.xml | 2 +- .../devicemgt/app/conf/config.json | 3 + .../modules/business-controllers/device.js | 2 +- .../app/pages/cdmf.page.devices/devices.js | 10 +- .../cdmf.unit.device.types.listing/listing.js | 4 +- .../units/cdmf.unit.policy.create/create.js | 2 +- .../cdmf.unit.ui.navbar.nav-menu/nav-menu.js | 13 +- 11 files changed, 452 insertions(+), 179 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java index 390bb2dca4..db10142cc4 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java @@ -15,6 +15,22 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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.jaxrs.service.api; @@ -31,15 +47,23 @@ import io.swagger.annotations.ApiResponses; import io.swagger.annotations.ResponseHeader; import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scopes; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import javax.validation.constraints.Size; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.List; @SwaggerDefinition( info = @Info( @@ -62,13 +86,19 @@ import javax.ws.rs.core.Response; name = "Getting the Supported Device Platforms", description = "Getting the Supported Device Platforms", key = "perm:device-types:types", - permissions = {"/device-mgt/devices/owning-device/view"} + permissions = {"/device-mgt/device-type/view"} ), @Scope( name = "Get Feature Details of a Device Type", description = "Get Feature Details of a Device Type", key = "perm:device-types:features", - permissions = {"/device-mgt/devices/owning-device/view"} + permissions = {"/device-mgt/device-type/features/view"} + ), + @Scope( + name = "Get Config Details of a Device Type", + description = "Get Config Details of a Device Type", + key = "perm:device-types:configs", + permissions = {"/device-mgt/device-type/config/view"} ) } ) @@ -84,7 +114,7 @@ public interface DeviceTypeManagementService { produces = MediaType.APPLICATION_JSON, httpMethod = "GET", value = "Getting the Supported Device Platforms", - notes = "Get the list of device platforms supported by WSO2 EMM.", + notes = "Get the list of device platforms supported by Entgra IoTS.", tags = "Device Type Management", extensions = { @Extension(properties = { @@ -133,18 +163,71 @@ public interface DeviceTypeManagementService { name = "If-Modified-Since", value = "Checks if the requested variant was modified, since the specified date-time.\n" + "Provide the value in the following format: EEE, d MMM yyyy HH:mm:ss Z.\n" + - "Example: Mon, 05 Jan 2014 15:10:00 +0200", - required = false) + "Example: Mon, 05 Jan 2014 15:10:00 +0200" + ) @HeaderParam("If-Modified-Since") String ifModifiedSince); + @GET + @Path("/{type}") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Details of a Device Type", + notes = "Get the details of a device by searching via the device type and the tenant domain.", + response = DeviceType.class, + tags = "Device Type Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:device-types:types") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device type.", + response = DeviceType.class, + responseContainer = "List", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body") + }), + @ApiResponse( + code = 304, + message = "Not Modified. Empty body because the client already has the latest version of the " + + "requested resource.\n"), + @ApiResponse( + code = 401, + message = "Unauthorized.\n The unauthorized access to the requested resource.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found.\n The specified device does not exist", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + Response getDeviceTypeByName( + @ApiParam( + name = "type", + value = "The device type name, such as ios, android, windows or fire-alarm.", + required = true) + @PathParam("type") + @Size(min = 2, max = 45) + String type); + @GET @Path("/{type}/features") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", value = "Get Feature Details of a Device Type", - notes = "The features in WSO2 EMM enables you to carry out many operations on a given device platform. " + + notes = "The features in Entgra IoTS enables you to carry out many operations on a given device platform. " + "Using this REST API you can get the features that can be carried out on a preferred device type," + " such as iOS, Android or Windows.", tags = "Device Type Management", @@ -202,108 +285,78 @@ public interface DeviceTypeManagementService { name = "If-Modified-Since", value = "Checks if the requested variant was modified, since the specified date-time.\n" + "Provide the value in the following format: EEE, d MMM yyyy HH:mm:ss Z.\n" + - "Example: Mon, 05 Jan 2014 15:10:00 +0200", - required = false) + "Example: Mon, 05 Jan 2014 15:10:00 +0200" + ) @HeaderParam("If-Modified-Since") String ifModifiedSince); @GET - @Path("/all/{type}") + @Path("/{type}/configs") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", - value = "Getting Details of a Device Type", - notes = "Get the details of a device by searching via the device type and the tenant domain.", - response = DeviceType.class, - tags = "Device Type Management Administrative Service", + value = "Get Configuration Details of a Device Type", + notes = "The features in Entgra IoTS enables you to carry out many operations on a given device platform. " + + "Using this REST API you can get platform configurations that can be carried out on a preferred " + + "device type, such as iOS, Android or Windows.", + tags = "Device Type Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:device-types:types") + @ExtensionProperty(name = Constants.SCOPE, value = "perm:device-types:configs") }) } ) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device type.", - response = DeviceType.class, - responseContainer = "List", - responseHeaders = { - @ResponseHeader( - name = "Content-Type", - description = "The content type of the body") - }), - @ApiResponse( - code = 304, - message = "Not Modified. Empty body because the client already has the latest version of the " + - "requested resource.\n"), - @ApiResponse( - code = 401, - message = "Unauthorized.\n The unauthorized access to the requested resource.", - response = ErrorResponse.class), - @ApiResponse( - code = 404, - message = "Not Found.\n The specified device does not exist", - response = ErrorResponse.class), - @ApiResponse( - code = 406, - message = "Not Acceptable.\n The requested media type is not supported"), - @ApiResponse( - code = 500, - message = "Internal Server Error. \n Server error occurred while fetching the device list.", - response = ErrorResponse.class) - }) - Response getDeviceTypeByName( + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully fetched configurations.", + response = PlatformConfiguration.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = + "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests."), + } + ), + @ApiResponse( + code = 304, + message = + "Not Modified. \n Empty body because the client already has the latest version " + + "of the requested resource.\n"), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the " + + "list of supported device types.", + response = ErrorResponse.class) + } + ) + Response getConfigs( @ApiParam( name = "type", value = "The device type name, such as ios, android, windows or fire-alarm.", required = true) @PathParam("type") - @Size(min = 2, max = 45) - String type); - - @GET - @Path("/all") - @ApiOperation( - produces = MediaType.APPLICATION_JSON, - httpMethod = "GET", - value = "Retrieve device types information", - notes = "Retrieve device types information.", - response = DeviceType.class, - tags = "Device Type Management Administrative Service", - extensions = { - @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:device-types:types") - }) - } - ) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device type.", - response = DeviceType.class, - responseContainer = "List", - responseHeaders = { - @ResponseHeader( - name = "Content-Type", - description = "The content type of the body") - }), - @ApiResponse( - code = 304, - message = "Not Modified. Empty body because the client already has the latest version of the " + - "requested resource.\n"), - @ApiResponse( - code = 401, - message = "Unauthorized.\n The unauthorized access to the requested resource.", - response = ErrorResponse.class), - @ApiResponse( - code = 404, - message = "Not Found.\n The specified device does not exist", - response = ErrorResponse.class), - @ApiResponse( - code = 406, - message = "Not Acceptable.\n The requested media type is not supported"), - @ApiResponse( - code = 500, - message = "Internal Server Error. \n Server error occurred while fetching the device list.", - response = ErrorResponse.class) - }) - Response getDeviceTypes(); + @Size(max = 45) + String type, + @ApiParam( + name = "If-Modified-Since", + value = "Checks if the requested variant was modified, since the specified date-time.\n" + + "Provide the value in the following format: EEE, d MMM yyyy HH:mm:ss Z.\n" + + "Example: Mon, 05 Jan 2014 15:10:00 +0200" + ) + @HeaderParam("If-Modified-Since") + String ifModifiedSince); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java index aa90b5b304..d669b2c309 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java @@ -15,6 +15,23 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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.jaxrs.service.api.admin; @@ -31,7 +48,7 @@ import io.swagger.annotations.SwaggerDefinition; import io.swagger.annotations.Tag; import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scopes; -import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; @@ -40,12 +57,11 @@ import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import javax.validation.constraints.Size; import javax.ws.rs.Consumes; import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -73,10 +89,22 @@ import javax.ws.rs.core.Response; @Scopes( scopes = { @Scope( - name = "Getting Details of a Device", - description = "Getting Details of a Device", + name = "Manage a Device Type", + description = "Add, Edit or View a Device Type", key = "perm:admin:device-type", permissions = {"/device-mgt/admin/device-type"} + ), + @Scope( + name = "Getting Details of a Device Type", + description = "Getting Details of a Device Type", + key = "perm:admin:device-type:view", + permissions = {"/device-mgt/admin/device-type/view"} + ), + @Scope( + name = "Add Device Type Config", + description = "Add Platform Config of a Device Type", + key = "perm:admin:device-type:configs", + permissions = {"/device-mgt/admin/device-type/config"} ) } ) @@ -88,10 +116,10 @@ public interface DeviceTypeManagementAdminService { httpMethod = "GET", value = "Getting the Supported Device Type with Meta Definition", notes = "Get the list of device types supported by WSO2 IoT.", - tags = "Device Type Management", + tags = "Device Type Management Administrative Service", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type") + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type:view") }) } ) @@ -133,6 +161,59 @@ public interface DeviceTypeManagementAdminService { ) Response getDeviceTypes(); + @GET + @Path("/{type}") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Details of a Device Type", + notes = "Get the details of a device by searching via the device type and the tenant domain.", + response = DeviceType.class, + tags = "Device Type Management Administrative Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type:view") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device type.", + response = DeviceType.class, + responseContainer = "List", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body") + }), + @ApiResponse( + code = 304, + message = "Not Modified. Empty body because the client already has the latest version of the " + + "requested resource.\n"), + @ApiResponse( + code = 401, + message = "Unauthorized.\n The unauthorized access to the requested resource.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found.\n The specified device does not exist", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + Response getDeviceTypeByName( + @ApiParam( + name = "type", + value = "The device type name, such as ios, android, windows or fire-alarm.", + required = true) + @PathParam("type") + @Size(min = 2, max = 45) + String type); + @POST @ApiOperation( produces = MediaType.APPLICATION_JSON, @@ -179,6 +260,7 @@ public interface DeviceTypeManagementAdminService { required = true)DeviceType deviceType); @PUT + @Path("/{type}") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "PUT", @@ -219,9 +301,73 @@ public interface DeviceTypeManagementAdminService { message = "Internal Server Error. \n Server error occurred while fetching the device list.", response = ErrorResponse.class) }) - Response updateDeviceType(@ApiParam( - name = "type", + Response updateDeviceType( + @ApiParam( + name = "type", + value = "The device type name, such as ios, android, windows or fire-alarm.", + required = true) + @PathParam("type") + @Size(min = 2, max = 45) + String name, + @ApiParam( + name = "deviceType", value = "The device type such as ios, android, windows or fire-alarm.", required = true) DeviceType deviceType); + @POST + @Path("/{type}/configs") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Add Configuration Details", + notes = "Add Configuration Details of a Device Type.", + tags = "Device Type Management Administrative Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type:configs") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully added the device type config.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body") + }), + @ApiResponse( + code = 304, + message = "Not Modified. Empty body because the client already has the latest version of the " + + "requested resource.\n"), + @ApiResponse( + code = 401, + message = "Unauthorized.\n The unauthorized access to the requested resource.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found.\n The specified device does not exist", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + Response addDeviceTypePlatformConfig( + @ApiParam( + name = "type", + value = "The device type name, such as ios, android, windows or fire-alarm.", + required = true) + @PathParam("type") + @Size(min = 2, max = 45) + String type, + @ApiParam( + name = "config", + value = "Platform configuration of specified device type.", + required = true) + PlatformConfiguration config); + + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java index 5fdc06a501..2c22f76e77 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java @@ -15,6 +15,23 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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.jaxrs.service.impl; @@ -23,14 +40,13 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig; import org.wso2.carbon.device.mgt.common.type.mgt.DeviceTypeMetaDefinition; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; -import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceTypeManagementService; -import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import javax.validation.constraints.Size; @@ -38,7 +54,6 @@ import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.List; @@ -51,50 +66,6 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ @GET @Override public Response getDeviceTypes(@HeaderParam("If-Modified-Since") String ifModifiedSince) { - List deviceTypes; - try { - deviceTypes = DeviceMgtAPIUtils.getDeviceManagementService().getAvailableDeviceTypes(); - - DeviceTypeList deviceTypeList = new DeviceTypeList(); - deviceTypeList.setCount(deviceTypes.size()); - deviceTypeList.setList(deviceTypes); - return Response.status(Response.Status.OK).entity(deviceTypeList).build(); - } catch (DeviceManagementException e) { - String msg = "Error occurred while fetching the list of device types."; - log.error(msg, e); - return Response.serverError().entity( - new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); - } - } - - @GET - @Override - @Path("/{type}/features") - public Response getFeatures(@PathParam("type") @Size(max = 45) String type, @HeaderParam("If-Modified-Since") String ifModifiedSince) { - List features; - DeviceManagementProviderService dms; - try { - dms = DeviceMgtAPIUtils.getDeviceManagementService(); - FeatureManager fm = dms.getFeatureManager(type); - if (fm == null) { - return Response.status(Response.Status.NOT_FOUND).entity( - new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + - "registered with the given type '" + type + "'").build()).build(); - } - features = fm.getFeatures(); - } catch (DeviceManagementException e) { - String msg = "Error occurred while retrieving the list of features of '" + type + "' device type"; - log.error(msg, e); - return Response.serverError().entity( - new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); - } - return Response.status(Response.Status.OK).entity(features).build(); - } - - @Override - @GET - @Path("/config") - public Response getDeviceTypes() { try { List deviceTypes = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceTypes(); List filteredDeviceTypes = new ArrayList<>(); @@ -111,8 +82,8 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ @Override @GET - @Path("/config/{type}") - public Response getDeviceTypeByName(@PathParam("type") String type) { + @Path("/{type}") + public Response getDeviceTypeByName(@PathParam("type") @Size(max = 45) String type) { if (type != null && type.length() > 0) { try { DeviceType deviceType = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(type); @@ -120,7 +91,7 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ String msg = "Device type does not exist, " + type; return Response.status(Response.Status.NO_CONTENT).entity(msg).build(); } - return Response.status(Response.Status.OK).entity(deviceType).build(); + return Response.status(Response.Status.OK).entity(clearMetaEntryInfo(deviceType)).build(); } catch (DeviceManagementException e) { String msg = "Error occurred at server side while fetching device type."; log.error(msg, e); @@ -131,10 +102,52 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ } } + @GET + @Override + @Path("/{type}/features") + public Response getFeatures(@PathParam("type") @Size(max = 45) String type, + @HeaderParam("If-Modified-Since") String ifModifiedSince) { + List features; + DeviceManagementProviderService dms; + try { + dms = DeviceMgtAPIUtils.getDeviceManagementService(); + FeatureManager fm = dms.getFeatureManager(type); + if (fm == null) { + features = new ArrayList<>(); + } else { + features = fm.getFeatures(); + } + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the list of features of '" + type + "' device type"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + return Response.status(Response.Status.OK).entity(features).build(); + } + + @GET + @Override + @Path("/{type}/configs") + public Response getConfigs(@PathParam("type") @Size(max = 45) String type, + @HeaderParam("If-Modified-Since") String ifModifiedSince) { + PlatformConfiguration platformConfiguration; + try { + platformConfiguration = DeviceMgtAPIUtils.getDeviceManagementService().getConfiguration(type); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the '" + type + "' platform configuration"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + return Response.status(Response.Status.OK).entity(platformConfiguration).build(); + } + /** * This cleans up the configs that should not be exposed to iot users. - * @param deviceType - * @return + * + * @param deviceType device type retrieved from service layer. + * @return sanitized device type. */ private DeviceType clearMetaEntryInfo(DeviceType deviceType) { DeviceTypeMetaDefinition metaDefinition = deviceType.getDeviceTypeMetaDefinition(); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index 57c0b7cde6..d7f659871d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -15,13 +15,31 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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.jaxrs.service.impl.admin; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.InvalidConfigurationException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; @@ -33,6 +51,7 @@ import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -63,6 +82,28 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } + @Override + @GET + @Path("/{type}") + public Response getDeviceTypeByName(@PathParam("type") String type) { + if (type != null && type.length() > 0) { + try { + DeviceType deviceType = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(type); + if (deviceType == null) { + String msg = "Device type does not exist, " + type; + return Response.status(Response.Status.NO_CONTENT).entity(msg).build(); + } + return Response.status(Response.Status.OK).entity(deviceType).build(); + } catch (DeviceManagementException e) { + String msg = "Error occurred at server side while fetching device type."; + log.error(msg, e); + return Response.serverError().entity(msg).build(); + } + } else { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + } + @Override @POST public Response addDeviceType(DeviceType deviceType) { @@ -81,8 +122,8 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen DeviceMgtAPIUtils.getDeviceManagementService().registerDeviceType(httpDeviceTypeManagerService); return Response.status(Response.Status.OK).build(); } else { - return Response.status(Response.Status.BAD_REQUEST).entity("Device type name does not match the pattern " - + DEVICETYPE_REGEX_PATTERN).build(); + return Response.status(Response.Status.BAD_REQUEST).entity("Device type name does not match " + + "the pattern " + DEVICETYPE_REGEX_PATTERN).build(); } } catch (DeviceManagementException e) { String msg = "Error occurred at server side while adding a device type."; @@ -96,11 +137,15 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @PUT - public Response updateDeviceType(DeviceType deviceType) { + public Response updateDeviceType(String type, DeviceType deviceType) { if (deviceType != null && deviceType.getDeviceTypeMetaDefinition() != null) { + if (deviceType.getName() == null || !deviceType.getName().equals(type)) { + return Response.status(Response.Status.BAD_REQUEST).entity("Type name mismatch. Expected: '" + type + + "' Found: '"+ deviceType.getName() + "'").build(); + } try { - if (DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(deviceType.getName()) == null) { - String msg = "Device type does not exist, " + deviceType.getName(); + if (DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(type) == null) { + String msg = "Device type does not exist, " + type; return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); } DeviceManagementService httpDeviceTypeManagerService = DeviceMgtAPIUtils.getDeviceTypeGeneratorService() @@ -116,4 +161,22 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen return Response.status(Response.Status.BAD_REQUEST).build(); } } + + @Override + public Response addDeviceTypePlatformConfig(String type, PlatformConfiguration platformConfiguration) { + boolean isSaved; + if (platformConfiguration.getType() == null || !platformConfiguration.getType().equals(type)) { + return Response.status(Response.Status.BAD_REQUEST).entity("Type name mismatch. Expected: '" + type + + "' Found: '"+ platformConfiguration.getType() + "'").build(); + } + try { + isSaved = DeviceMgtAPIUtils.getDeviceManagementService().saveConfiguration(platformConfiguration); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the Android tenant configuration"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + return Response.status(isSaved ? Response.Status.OK : Response.Status.BAD_REQUEST).build(); + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml index e1e2c46e8c..7a2013037a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -66,7 +66,7 @@ - + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/config.json b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/config.json index ffe9bcaa86..8e74ac0232 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/config.json +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/config.json @@ -136,6 +136,7 @@ "perm:groups:devices-remove", "perm:groups:devices-add", "perm:groups:assign", + "perm:device-types:configs", "perm:device-types:features", "perm:device-types:types", "perm:applications:install", @@ -154,6 +155,8 @@ "perm:device-types:events", "perm:device-types:events:view", "perm:admin:device-type", + "perm:admin:device-type:view", + "perm:admin:device-type:configs", "perm:device:enroll", "perm:geo-service:analytics-view", "perm:geo-service:alerts-manage", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js index 16be67eb43..ca8fa6dbd8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js @@ -303,7 +303,7 @@ deviceModule = function () { } return serviceInvokers.XMLHttp.get( url, function (responsePayload) { - return parse(responsePayload["responseText"])["count"]; + return parse(responsePayload["responseText"]).length; }, function (responsePayload) { log.error(responsePayload["responseText"]); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/devices.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/devices.js index c973d07985..41afed6ae9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/devices.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/devices.js @@ -56,12 +56,12 @@ function onRequest(context) { var typesListResponse = deviceModule.getDeviceTypes(); var deviceTypes = []; if (typesListResponse["status"] == "success") { - var data = typesListResponse.content.deviceTypes; + var data = typesListResponse.content; if (data) { for (var i = 0; i < data.length; i++) { - var config = utility.getDeviceTypeConfig(data[i]); + var config = utility.getDeviceTypeConfig(data[i].name); var category = "iot"; - var label = data[i]; + var label = data[i].name; var analyticsEnabled = "false"; var groupingEnabled = "true"; var analyticsView = null; @@ -75,10 +75,10 @@ function onRequest(context) { } deviceTypes.push({ - "type": data[i], + "type": data[i].name, "category": category, "label": label, - "thumb": utility.getDeviceThumb(data[i]), + "thumb": utility.getDeviceThumb(data[i].name), "analyticsEnabled": analyticsEnabled, "groupingEnabled": groupingEnabled, "analyticsView" : analyticsView diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.types.listing/listing.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.types.listing/listing.js index 9b0cdacddb..23ee3e59d0 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.types.listing/listing.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.types.listing/listing.js @@ -28,14 +28,14 @@ function onRequest(context) { var utility = require("/app/modules/utility.js").utility; var typesListResponse = deviceModule.getDeviceTypes(); if (typesListResponse["status"] == "success") { - var deviceTypes = typesListResponse.content.deviceTypes; + var deviceTypes = typesListResponse.content; if (deviceTypes) { if (deviceTypes.length > 0){ viewModel.hasDeviceTypes = true; } var deviceTypesList = [], virtualDeviceTypesList = []; for (var i = 0; i < deviceTypes.length; i++) { - var deviceType = deviceTypes[i]; + var deviceType = deviceTypes[i].name; var deviceTypeLabel = deviceType; var configs = utility.getDeviceTypeConfig(deviceTypeLabel); var deviceCategory = "device"; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.policy.create/create.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.policy.create/create.js index db1d8169a2..94f0b1235b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.policy.create/create.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.policy.create/create.js @@ -50,7 +50,7 @@ function onRequest(context) { types.isAuthorizedViewGroups = userModule.isAuthorized("/permission/admin/device-mgt/groups/view"); types["types"] = []; - var typesListResponse = deviceModule.getDeviceTypesConfig(); + var typesListResponse = deviceModule.getDeviceTypes(); if (typesListResponse["status"] == "success") { for (var type in typesListResponse["content"]) { var content = {}; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.js index 5bbd9926bf..3fce92e8e7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.js @@ -27,8 +27,8 @@ function onRequest(context) { return options.fn(this); } }); + var utility = require("/app/modules/utility.js").utility; var userModule = require("/app/modules/business-controllers/user.js")["userModule"]; - var deviceModule = require("/app/modules/business-controllers/device.js")["deviceModule"]; var mdmProps = require("/app/modules/conf-reader/main.js")["conf"]; var constants = require("/app/modules/constants.js"); var uiPermissions = userModule.getUIPermissions(); @@ -43,15 +43,10 @@ function onRequest(context) { "device-mgt": [] }; - var typesListResponse = deviceModule.getDeviceTypesConfig(); - var temp = []; - temp = typesListResponse["content"]; var iosPluginFlag = false; - temp.forEach(function(element) { - if (element["name"] == "ios") { - iosPluginFlag = true; - } - }); + if (utility.getTenantedDeviceUnitName("ios", "type-view")) { + iosPluginFlag = true; + } context["iosPluginFlag"] = iosPluginFlag; // following context.link value comes here based on the value passed at the point From fbaf21adc68669bb1851976d1728ec6d4ddfb663 Mon Sep 17 00:00:00 2001 From: charitha Date: Wed, 17 Apr 2019 02:18:16 +0530 Subject: [PATCH 02/27] Add device type specific platform config UIs --- .../api/DeviceTypeManagementService.java | 2 +- .../impl/DeviceTypeManagementServiceImpl.java | 9 +- .../public/images/thumb.png | Bin 42033 -> 26701 bytes .../public/templates/applications-list.hbs | 2 +- .../configuration.hbs | 41 + .../configuration.json | 3 + .../configuration.hbs | 19 +- .../configuration.js | 33 +- .../public/js/platform-configuration.js | 198 +- .../cdmf.unit.ui.navbar.nav-menu/nav-menu.hbs | 2 +- .../lib/font-wso2-1.3.0/css/font-wso2.css | 3004 ++++++++--------- .../lib/font-wso2-1.3.0/css/font-wso2.min.css | 30 +- 12 files changed, 1771 insertions(+), 1572 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.hbs create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.json diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java index db10142cc4..1b59cfe4fd 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceTypeManagementService.java @@ -348,7 +348,7 @@ public interface DeviceTypeManagementService { value = "The device type name, such as ios, android, windows or fire-alarm.", required = true) @PathParam("type") - @Size(max = 45) + @Size(min = 2, max = 45) String type, @ApiParam( name = "If-Modified-Since", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java index 2c22f76e77..b20b3462de 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java @@ -83,7 +83,7 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ @Override @GET @Path("/{type}") - public Response getDeviceTypeByName(@PathParam("type") @Size(max = 45) String type) { + public Response getDeviceTypeByName(@PathParam("type") @Size(min = 2, max = 45) String type) { if (type != null && type.length() > 0) { try { DeviceType deviceType = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(type); @@ -129,11 +129,16 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ @GET @Override @Path("/{type}/configs") - public Response getConfigs(@PathParam("type") @Size(max = 45) String type, + public Response getConfigs(@PathParam("type") @Size(min = 2, max = 45) String type, @HeaderParam("If-Modified-Since") String ifModifiedSince) { PlatformConfiguration platformConfiguration; try { platformConfiguration = DeviceMgtAPIUtils.getDeviceManagementService().getConfiguration(type); + if (platformConfiguration == null) { + platformConfiguration = new PlatformConfiguration(); + platformConfiguration.setType(type); + platformConfiguration.setConfiguration(new ArrayList<>()); + } } catch (DeviceManagementException e) { String msg = "Error occurred while retrieving the '" + type + "' platform configuration"; log.error(msg, e); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/public/images/thumb.png b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/public/images/thumb.png index 71e5c0c28b8161aab740a38422f10de5ca3ae955..109ed11017ae0b2a61e1ce0abd616cfbb462f916 100644 GIT binary patch literal 26701 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 Lid2<^S=j#qJ$(xW literal 42033 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 diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.view/public/templates/applications-list.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.view/public/templates/applications-list.hbs index 8fba28621b..2f6af71aa6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.view/public/templates/applications-list.hbs +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.view/public/templates/applications-list.hbs @@ -3,7 +3,7 @@ {{#each applications}} {{#equal platform "android"}}{{/equal}} - {{#equal platform "ios"}}{{/equal}} + {{#equal platform "ios"}}{{/equal}} {{#equal platform "windows"}}{{/equal}} {{name}} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.hbs new file mode 100644 index 0000000000..b4c64f7fd5 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.hbs @@ -0,0 +1,41 @@ +{{! + 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. +}} +
+ +
+ +
+
+
+ +
+
+
+{{#zone "bottomJs"}} + +{{/zone}} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.json b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.json new file mode 100644 index 0000000000..fd25901297 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.dynamic.platform.configuration/configuration.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs index 1d42bd01d8..597b38ce18 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs @@ -15,6 +15,11 @@ specific language governing permissions and limitations under the License. }} + +{{#zone "topCss"}} + {{css "css/platform-configuration.css"}} +{{/zone}} + {{#zone "content"}} {{#if isAuthorized}}
@@ -37,7 +42,7 @@
-
+
{{#unless isCloud}} @@ -63,7 +68,11 @@ - + {{#if unitName}} + + {{else}} + + {{/if}} {{label}} Configurations @@ -124,7 +133,11 @@ {{#each deviceTypes}} {{/each}} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.js index 361579554f..4fc10b836f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.js @@ -14,6 +14,23 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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. */ function onRequest(context) { @@ -29,23 +46,23 @@ function onRequest(context) { var deviceTypesArray = []; var typesListResponse = deviceModule.getDeviceTypes(); if (typesListResponse["status"] == "success") { - var data = typesListResponse["content"].deviceTypes; + var data = typesListResponse["content"]; if (data) { for (var i = 0; i < data.length; i++) { - var deviceTypeName = data[i]; + var deviceTypeName = data[i].name; + var deviceTypeLabel = deviceTypeName.charAt(0).toUpperCase() + deviceTypeName.slice(1);; var configUnitName = utility.getTenantedDeviceUnitName(deviceTypeName, "platform.configuration"); if (configUnitName) { var deviceTypeConfig = utility.getDeviceTypeConfig(deviceTypeName); - var deviceTypeLabel = deviceTypeName; if (deviceTypeConfig) { deviceTypeLabel = deviceTypeConfig.deviceType.label; } - deviceTypesArray.push({ - name: deviceTypeName, - label: deviceTypeLabel, - unitName: configUnitName - }); } + deviceTypesArray.push({ + name: deviceTypeName, + label: deviceTypeLabel, + unitName: configUnitName + }); } } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js index 45f753b4ed..d3a2152b06 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js @@ -16,6 +16,8 @@ * under the License. */ +var configRowId = 0; + $(document).ready(function () { var configParams = { @@ -41,25 +43,25 @@ $(document).ready(function () { } invokerUtil.get( - "/api/device-mgt/v1.0/configuration", - function (data) { - data = JSON.parse(data); - if (data && data.configuration) { - for (var i = 0; i < data.configuration.length; i++) { - var config = data.configuration[i]; - if (config.name == configParams["NOTIFIER_FREQUENCY"]) { - $("input#monitoring-config-frequency").val(config.value / 1000); - } + "/api/device-mgt/v1.0/configuration", + function (data) { + data = JSON.parse(data); + if (data && data.configuration) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if (config.name == configParams["NOTIFIER_FREQUENCY"]) { + $("input#monitoring-config-frequency").val(config.value / 1000); } } - }, function (data) { - console.log(data); - }); + } + }, function (data) { + console.log(data); + }); /** * Following click function would execute * when a user clicks on "Save" button - * on General platform configuration page in WSO2 EMM Console. + * on General platform configuration page in Entgra devicemgt Console. */ $("button#save-general-btn").click(function () { var notifierFrequency = $("input#monitoring-config-frequency").val(); @@ -87,33 +89,33 @@ $(document).ready(function () { var addConfigAPI = "/api/device-mgt/v1.0/configuration"; invokerUtil.put( - addConfigAPI, - addConfigFormData, - function (data, textStatus, jqXHR) { - data = jqXHR.status; - if (data == 200) { - $("#config-save-form").addClass("hidden"); - $("#record-created-msg").removeClass("hidden"); - } else if (data == 500) { - $(errorMsg).text("Exception occurred at backend."); - } else if (data == 403) { - $(errorMsg).text("Action was not permitted."); - } else { - $(errorMsg).text("An unexpected error occurred."); - } - - $(errorMsgWrapper).removeClass("hidden"); - }, function (data) { - data = data.status; - if (data == 500) { - $(errorMsg).text("Exception occurred at backend."); - } else if (data == 403) { - $(errorMsg).text("Action was not permitted."); - } else { - $(errorMsg).text("An unexpected error occurred."); - } - $(errorMsgWrapper).removeClass("hidden"); + addConfigAPI, + addConfigFormData, + function (data, textStatus, jqXHR) { + data = jqXHR.status; + if (data == 200) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); } + $(errorMsgWrapper).removeClass("hidden"); + } ); } }); @@ -154,3 +156,121 @@ var artifactGeoUpload = function () { showPopup(); }, contentType); }; + +var loadDynamicDeviceTypeConfig = function (deviceType) { + var configAPI = '/api/device-mgt/v1.0/device-types/' + deviceType + '/configs'; + invokerUtil.get( + configAPI, + function (data) { + data = JSON.parse(data); + var fieldWrapper = "#" + deviceType + "-config-field-wrapper"; + $(fieldWrapper).html(""); + if (data.configuration) { + var config; + var i; + for (i = 0; i < data.configuration.length; i++) { + config = data.configuration[i]; + onDynamicConfigAddNew(deviceType, config.name, config.value); + } + } + $(fieldWrapper).append( + '
' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + ); + }, function (data) { + console.log(data); + } + ); +}; + +var onDynamicConfigSubmit = function (deviceType) { + + var errorMsgWrapper = "#" + deviceType + "-config-error-msg"; + var errorMsg = "#" + deviceType + "-config-error-msg span"; + + var addConfigFormData = {}; + var configList = []; + + $('.' + deviceType + '-config-row').each(function () { + var configName = $(this).find("." + deviceType + "-config-name").val(); + var configVal = $(this).find("." + deviceType + "-config-value").val(); + if (configName && configName.trim() !== "" && configVal && configVal.trim() !== "") { + var configurationEntry = {}; + configurationEntry.name = configName.trim(); + configurationEntry.contentType = "text"; + configurationEntry.value = configVal.trim(); + configList.push(configurationEntry); + } + }); + + addConfigFormData.type = deviceType; + addConfigFormData.configuration = configList; + + var addConfigAPI = '/api/device-mgt/v1.0/admin/device-types/' + deviceType + '/configs'; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data, textStatus, jqXHR) { + data = jqXHR.status; + if (data == 200) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 400) { + $(errorMsg).text("Configurations cannot be empty."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + $(errorMsgWrapper).removeClass("hidden"); + } + ); +}; + +var onDynamicConfigAddNew = function (deviceType, name, value) { + $("#" + deviceType + "-config-field-wrapper").append( + '
' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + ); +}; + +var onDynamicConfigRemove = function (deviceType, rawId) { + $("#" + deviceType + "-config-row-" + rawId).remove() +}; \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.hbs index b071abf81d..8c80bd6fc7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.hbs +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.ui.navbar.nav-menu/nav-menu.hbs @@ -118,7 +118,7 @@ {{/if}} {{#if iosPluginFlag}}
  • - + DEP Configurations
  • diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.css b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.css index 870013db19..c6544d6f2e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.css +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.css @@ -1,1506 +1,1506 @@ -/*! -~ Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved. -~ -~ Licensed under the Apache License, Version 2.0 (the "License"); -~ you may not use this file except in compliance with the License. -~ You may obtain a copy of the License at -~ -~ http://www.apache.org/licenses/LICENSE-2.0 -~ -~ Unless required by applicable law or agreed to in writing, software -~ distributed under the License is distributed on an "AS IS" BASIS, -~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -~ See the License for the specific language governing permissions and -~ limitations under the License. -*/ - - -@font-face { - font-family:"font-wso2"; - src:local("font-wso2"), url("../fonts/font-wso2.eot?6563fa91278f239ef8c827d90a165223"); - src:local("font-wso2"), +/*! +~ Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved. +~ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ +~ http://www.apache.org/licenses/LICENSE-2.0 +~ +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +*/ + + +@font-face { + font-family:"font-wso2"; + src:local("font-wso2"), url("../fonts/font-wso2.eot?6563fa91278f239ef8c827d90a165223"); + src:local("font-wso2"), url("../fonts/font-wso2.eot?#iefix") format("embedded-opentype"), url("../fonts/font-wso2.woff2?6563fa91278f239ef8c827d90a165223") format("woff2"), url("../fonts/font-wso2.woff?6563fa91278f239ef8c827d90a165223") format("woff"), url("../fonts/font-wso2.ttf?6563fa91278f239ef8c827d90a165223") format("truetype"), - url("../fonts/font-wso2.svg?6563fa91278f239ef8c827d90a165223#font-wso2") format("svg"); - font-weight:normal; - font-style:normal; -} - -.fw, [class^="fw-"], [class*=" fw-"] { - font: normal normal normal 14px/1 font-wso2; - display: inline-block; - font-weight: normal; - font-style: normal; - font-size: inherit; - font-variant: normal; - speak: none; - text-decoration: inherit; - - /* Better Font Rendering =========== */ - text-transform: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - - -/* ======================================================================== - * font options - * ======================================================================== */ - -.fw-lg { - font-size: 1.33333333em; - line-height: 0.75em; - vertical-align: -15%; -} -.fw-2x { - font-size: 2em; -} -.fw-3x { - font-size: 3em; -} -.fw-4x { - font-size: 4em; -} -.fw-5x { - font-size: 5em; -} -.fw-fw { - width: 1.28571429em; - text-align: center; -} -.fw-ul { - padding-left: 0; - margin-left: 2.14285714em; - list-style-type: none; -} -.fw-ul > li { - position: relative; -} -.fw-li { - position: absolute; - left: -2.14285714em; - width: 2.14285714em; - top: 0.14285714em; - text-align: center; -} -.fw-li.fw-lg { - left: -1.85714286em; -} -.fw-border { - padding: .2em .25em .15em; - border: solid 0.08em #eeeeee; - border-radius: .1em; -} -.fw-background { - background: #888; - border-radius: .3em; - padding: .4em .50em .45em; -} -.fw-pull-left { - float: left; -} -.fw-pull-right { - float: right; -} -.fw.fw-pull-left { - margin-right: .3em; -} -.fw.fw-pull-right { - margin-left: .3em; -} -.fw-spin { - -webkit-animation: fw-spin 2s infinite linear; - animation: fw-spin 2s infinite linear; -} -@-webkit-keyframes fw-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes fw-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -.fw-pulse { - -webkit-animation: fw-pulse 2s ease-out infinite; - animation: fw-pulse 2s ease-out infinite; -} -@-webkit-keyframes fw-pulse { - 0%, 30% { - opacity: 0.3; - } - 40% { - opacity: 1; - } - 100% { - opacity: 0.3; - } -} -@keyframes fw-pulse { - 0%, 30% { - opacity: 0.3; - } - 40% { - opacity: 1; - } - 100% { - opacity: 0.3; - } -} -.fw-rotate-90 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); - -webkit-transform: rotate(90deg); - -ms-transform: rotate(90deg); - transform: rotate(90deg); -} -.fw-rotate-180 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} -.fw-rotate-270 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); - -webkit-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg); -} -.fw-flip-horizontal { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); - -webkit-transform: scale(-1, 1); - -ms-transform: scale(-1, 1); - transform: scale(-1, 1); -} -.fw-flip-vertical { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); - -webkit-transform: scale(1, -1); - -ms-transform: scale(1, -1); - transform: scale(1, -1); -} -:root .fw-rotate-90, -:root .fw-rotate-180, -:root .fw-rotate-270, -:root .fw-flip-horizontal, -:root .fw-flip-vertical { - filter: none; -} -.fw-stack, -.fw-helper { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 1.85em; - vertical-align: middle; -} -.fw-stack-1x, -.fw-stack-2x, -.fw-helper:before, -.fw-helper:after { - position: absolute; - left: 0; - width: 100%; - text-align: center; -} -.fw-stack-1x, -.fw-helper:before { - line-height: inherit; -} -.fw-stack-2x, -.fw-helper:after { - font-size: 1.9em; -} -.fw-helper-slash:before { - font-size: 1.4em; -} -.fw-helper-circle:before, -.fw-helper-square:before { - z-index: 1; -} -.fw-helper-circle-outline:after { - content: "\e61f"; -} -.fw-helper-circle:after { - content: "\e61a"; -} -.fw-helper-square-outline:after { - content: "\e6b2"; -} -.fw-helper-square:after { - content: "\e6b1"; -} -.fw-helper-slash:after { - content: "\e6e1"; -} -.fw-stack > .fw-stack { - position: absolute; - font-size: 0.5em; -} -.fw-stack > .fw-stack.fw-move-top { - top: -0.2em; -} -.fw-stack > .fw-stack.fw-move-bottom { - bottom: -0.2em; -} -.fw-stack > .fw.stack.fw-move-left { - left: -0.5em; -} -.fw-stack > .fw-stack.fw-move-right { - right: -0.5em; -} -.fw-inverse:before, -.fw-helper-inverse:after, -.fw-number { - color: #ffffff; -} -.fw-shadow:before, -.fw-helper-shadow:after { - text-shadow: #ffffff 1px 1px 0; -} -.fw-stroke:before, -.fw-helper-stroke:after { - text-shadow: -2px -2px 0 #ffffff, - 2px -2px 0 #ffffff, - -2px 2px 0 #ffffff, - 2px 2px 0 #ffffff; -} -.fw-number { - line-height: 2em; - font-family: Arial, Helvetica, sans-serif; -} - - -/* ======================================================================== - * font icons - * ======================================================================== */ - -.fw-abort:before { - content:"\e72a"; -} - -.fw-action-invoke:before { - content:"\e6fe"; -} - -.fw-action:before { - content:"\e709"; -} - -.fw-activate:before { - content:"\e6cf"; -} - -.fw-add:before { - content:"\e615"; -} - -.fw-airplay:before { - content:"\e600"; -} - -.fw-alarm:before { - content:"\e6c2"; -} - -.fw-alert:before { - content:"\e6be"; -} - -.fw-analytics-extensions:before { - content:"\e6e2"; -} - -.fw-android-logcat:before { - content:"\e72c"; -} - -.fw-android-sense:before { - content:"\e72d"; -} - -.fw-android:before { - content:"\e606"; -} - -.fw-annotation:before { - content:"\e6e6"; -} - -.fw-api:before { - content:"\e601"; -} - -.fw-apn:before { - content:"\e602"; -} - -.fw-apple:before { - content:"\e604"; -} - -.fw-application:before { - content:"\e608"; -} - -.fw-arduino:before { - content:"\e6ab"; -} - -.fw-assign:before { - content:"\e6ff"; -} - -.fw-ballerina-service:before { - content:"\e729"; -} - -.fw-ballerina:before { - content:"\e728"; -} - -.fw-bar-chart:before { - content:"\e690"; -} - -.fw-battery:before { - content:"\e60a"; -} - -.fw-blank-document:before { - content:"\e60c"; -} - -.fw-block:before { - content:"\e695"; -} - -.fw-bookmark:before { - content:"\e60d"; -} - -.fw-bpel:before { - content:"\e60e"; -} - -.fw-bpmn:before { - content:"\e60f"; -} - -.fw-break:before { - content:"\e721"; -} - -.fw-bug:before { - content:"\e611"; -} - -.fw-build:before { - content:"\e6c1"; -} - -.fw-calendar:before { - content:"\e612"; -} - -.fw-camera:before { - content:"\e613"; -} - -.fw-cancel:before { - content:"\e618"; -} - -.fw-carbon:before { - content:"\e6c5"; -} - -.fw-chat:before { - content:"\e65b"; -} - -.fw-check:before { - content:"\e617"; -} - -.fw-checklist:before { - content:"\e619"; -} - -.fw-circle-outline:before { - content:"\e61f"; -} - -.fw-circle:before { - content:"\e61a"; -} - -.fw-clear:before { - content:"\e61b"; -} - -.fw-clock:before { - content:"\e61d"; -} - -.fw-cloud:before { - content:"\e61e"; -} - -.fw-code-view:before { - content:"\e70e"; -} - -.fw-code:before { - content:"\e6f1"; -} - -.fw-comment:before { - content:"\e710"; -} - -.fw-compare:before { - content:"\e610"; -} - -.fw-computer:before { - content:"\e653"; -} - -.fw-configarations:before { - content:"\e609"; -} - -.fw-connector:before { - content:"\e700"; -} - -.fw-console:before { - content:"\e71d"; -} - -.fw-constant:before { - content:"\e701"; -} - -.fw-contact:before { - content:"\e620"; -} - -.fw-contract:before { - content:"\e614"; -} - -.fw-copy:before { - content:"\e621"; -} - -.fw-cut:before { - content:"\e6f2"; -} - -.fw-dashboard:before { - content:"\e622"; -} - -.fw-database:before { - content:"\e623"; -} - -.fw-delete:before { - content:"\e624"; -} - -.fw-depend:before { - content:"\e6c6"; -} - -.fw-deploy:before { - content:"\e625"; -} - -.fw-deprecate:before { - content:"\e6cb"; -} - -.fw-design-view:before { - content:"\e70f"; -} - -.fw-devices:before { - content:"\e704"; -} - -.fw-dgm-action-invoke:before { - content:"\e712"; -} - -.fw-dgm-action:before { - content:"\e711"; -} - -.fw-dgm-connector:before { - content:"\e6f4"; -} - -.fw-dgm-constant-definition:before { - content:"\e6f5"; -} - -.fw-dgm-fork:before { - content:"\e6e7"; -} - -.fw-dgm-header:before { - content:"\e6e8"; -} - -.fw-dgm-if-else:before { - content:"\e6e9"; -} - -.fw-dgm-import:before { - content:"\e717"; -} - -.fw-dgm-lifeline:before { - content:"\e6ea"; -} - -.fw-dgm-logger:before { - content:"\e6eb"; -} - -.fw-dgm-resource:before { - content:"\e6f6"; -} - -.fw-dgm-service:before { - content:"\e6f7"; -} - -.fw-dgm-try-catch:before { - content:"\e6ec"; -} - -.fw-dgm-type-convertor:before { - content:"\e6f8"; -} - -.fw-dgm-type:before { - content:"\e6f9"; -} - -.fw-dgm-while:before { - content:"\e707"; -} - -.fw-dial-up:before { - content:"\e627"; -} - -.fw-disabled:before { - content:"\e6d1"; -} - -.fw-display:before { - content:"\e626"; -} - -.fw-docker:before { - content:"\e70c"; -} - -.fw-document:before { - content:"\e628"; -} - -.fw-down-arrow:before { - content:"\e689"; -} - -.fw-down:before { - content:"\e685"; -} - -.fw-download:before { - content:"\e65f"; -} - -.fw-dss:before { - content:"\e62a"; -} - -.fw-ebook:before { - content:"\e62b"; -} - -.fw-edit:before { - content:"\e62c"; -} - -.fw-ellipsis:before { - content:"\e629"; -} - -.fw-endpoint:before { - content:"\e62d"; -} - -.fw-enterprise:before { - content:"\e6b6"; -} - -.fw-error:before { - content:"\e630"; -} - -.fw-esb-connector:before { - content:"\e6e3"; -} - -.fw-expand:before { - content:"\e61c"; -} - -.fw-export:before { - content:"\e631"; -} - -.fw-extensions:before { - content:"\e6e4"; -} - -.fw-facebook:before { - content:"\e6d3"; -} - -.fw-factory-reset:before { - content:"\e632"; -} - -.fw-fan:before { - content:"\e678"; -} - -.fw-faq:before { - content:"\e62f"; -} - -.fw-file-browse:before { - content:"\e633"; -} - -.fw-filter:before { - content:"\e634"; -} - -.fw-folder-open:before { - content:"\e70b"; -} - -.fw-folder:before { - content:"\e62e"; -} - -.fw-fork-join:before { - content:"\e720"; -} - -.fw-format:before { - content:"\e6fa"; -} - -.fw-forum:before { - content:"\e636"; -} - -.fw-function-invoke:before { - content:"\e713"; -} - -.fw-function:before { - content:"\e6fb"; -} - -.fw-gadget:before { - content:"\e637"; -} - -.fw-geo-fence-inbound:before { - content:"\e72e"; -} - -.fw-geo-fence-outbound:before { - content:"\e72f"; -} - -.fw-github:before { - content:"\e6d4"; -} - -.fw-globe:before { - content:"\e697"; -} - -.fw-google-docs:before { - content:"\e6d6"; -} - -.fw-google-drive:before { - content:"\e6da"; -} - -.fw-google-plus:before { - content:"\e6d9"; -} - -.fw-google-sheets:before { - content:"\e6d7"; -} - -.fw-google-slides:before { - content:"\e6d8"; -} - -.fw-google:before { - content:"\e6d5"; -} - -.fw-grid:before { - content:"\e638"; -} - -.fw-grip:before { - content:"\e6b7"; -} - -.fw-group:before { - content:"\e6af"; -} - -.fw-hardware:before { - content:"\e6a9"; -} - -.fw-hdd:before { - content:"\e639"; -} - -.fw-heart:before { - content:"\e6c3"; -} - -.fw-hide:before { - content:"\e6d2"; -} - -.fw-home:before { - content:"\e63a"; -} - -.fw-hour-glass:before { - content:"\e63b"; -} - -.fw-html:before { - content:"\e69d"; -} - -.fw-http:before { - content:"\e705"; -} - -.fw-image:before { - content:"\e70a"; -} - -.fw-import:before { - content:"\e63c"; -} - -.fw-incoming-call:before { - content:"\e63d"; -} - -.fw-info:before { - content:"\e63e"; -} - -.fw-instagram:before { - content:"\e6db"; -} - -.fw-invitation:before { - content:"\e63f"; -} - -.fw-invoke:before { - content:"\e6ed"; -} - -.fw-is-connector:before { - content:"\e6e5"; -} - -.fw-iterate:before { - content:"\e71f"; -} - -.fw-jaggery:before { - content:"\e640"; -} - -.fw-java-spring:before { - content:"\e644"; -} - -.fw-java:before { - content:"\e641"; -} - -.fw-javaee:before { - content:"\e642"; -} - -.fw-javascript:before { - content:"\e643"; -} - -.fw-jaxrs:before { - content:"\e645"; -} - -.fw-jaxws:before { - content:"\e6c7"; -} - -.fw-jquery:before { - content:"\e646"; -} - -.fw-key:before { - content:"\e647"; -} - -.fw-laptop:before { - content:"\e648"; -} - -.fw-layout:before { - content:"\e6bf"; -} - -.fw-ldap:before { - content:"\e649"; -} - -.fw-left-arrow:before { - content:"\e68a"; -} - -.fw-left:before { - content:"\e686"; -} - -.fw-lifecycle:before { - content:"\e64a"; -} - -.fw-light:before { - content:"\e680"; -} - -.fw-linkedin:before { - content:"\e6dc"; -} - -.fw-list-sort:before { - content:"\e64d"; -} - -.fw-list:before { - content:"\e64c"; -} - -.fw-loader:before { - content:"\e6b4"; -} - -.fw-loader2:before { - content:"\e6ba"; -} - -.fw-loader3:before { - content:"\e6bb"; -} - -.fw-loader4:before { - content:"\e6bc"; -} - -.fw-loader5:before { - content:"\e6bd"; -} - -.fw-lock:before { - content:"\e64e"; -} - -.fw-logical:before { - content:"\e702"; -} - -.fw-mail:before { - content:"\e64f"; -} - -.fw-main-function:before { - content:"\e706"; -} - -.fw-map-location:before { - content:"\e650"; -} - -.fw-menu:before { - content:"\e651"; -} - -.fw-message:before { - content:"\e635"; -} - -.fw-micro-services:before { - content:"\e6ce"; -} - -.fw-minus:before, .fw-hyphen:before, .fw-dash:before { - content:"\e616"; -} - -.fw-mobile:before { - content:"\e652"; -} - -.fw-ms-document:before { - content:"\e654"; -} - -.fw-mute:before { - content:"\e655"; -} - -.fw-nodejs:before { - content:"\e656"; -} - -.fw-notification:before { - content:"\e60b"; -} - -.fw-organization:before { - content:"\e6ac"; -} - -.fw-own:before { - content:"\e6c8"; -} - -.fw-package:before { - content:"\e6fd"; -} - -.fw-pages:before { - content:"\e6c0"; -} - -.fw-paste:before { - content:"\e658"; -} - -.fw-pdf:before { - content:"\e659"; -} - -.fw-pending:before { - content:"\e727"; -} - -.fw-php:before { - content:"\e6c9"; -} - -.fw-pie-chart:before { - content:"\e65a"; -} - -.fw-pinterest:before { - content:"\e6dd"; -} - -.fw-policy:before { - content:"\e67d"; -} - -.fw-polygon:before { - content:"\e70d"; -} - -.fw-prototype:before { - content:"\e6cc"; -} - -.fw-proxy:before { - content:"\e699"; -} - -.fw-public:before { - content:"\e6ad"; -} - -.fw-publish:before { - content:"\e65c"; -} - -.fw-question:before { - content:"\e6b0"; -} - -.fw-raspberry:before { - content:"\e6aa"; -} - -.fw-redo:before { - content:"\e65d"; -} - -.fw-refresh:before { - content:"\e692"; -} - -.fw-register:before { - content:"\e65e"; -} - -.fw-rename:before { - content:"\e6fc"; -} - -.fw-reply:before { - content:"\e714"; -} - -.fw-resource:before { - content:"\e660"; -} - -.fw-rest-api:before { - content:"\e661"; -} - -.fw-rest-service:before { - content:"\e662"; -} - -.fw-resume:before { - content:"\e71e"; -} - -.fw-retire:before { - content:"\e6cd"; -} - -.fw-return:before { - content:"\e715"; -} - -.fw-retweet:before { - content:"\e6b9"; -} - -.fw-right-arrow:before { - content:"\e68b"; -} - -.fw-right:before { - content:"\e687"; -} - -.fw-ringing:before { - content:"\e694"; -} - -.fw-rules:before { - content:"\e664"; -} - -.fw-run:before { - content:"\e708"; -} - -.fw-save:before { - content:"\e665"; -} - -.fw-scep:before { - content:"\e666"; -} - -.fw-schema:before { - content:"\e667"; -} - -.fw-search:before { - content:"\e668"; -} - -.fw-security-policy:before { - content:"\e67e"; -} - -.fw-security:before { - content:"\e669"; -} - -.fw-send:before, .fw-paper-rocket:before { - content:"\e66a"; -} - -.fw-sequence:before { - content:"\e66b"; -} - -.fw-server:before { - content:"\e66c"; -} - -.fw-service-provider:before { - content:"\e66e"; -} - -.fw-service:before, .fw-cogwheels:before, .fw-gears:before, .fw-sprockets:before { - content:"\e66d"; -} - -.fw-settings:before, .fw-cogwheel:before, .fw-gear:before, .fw-sprocket:before { - content:"\e66f"; -} - -.fw-share:before { - content:"\e670"; -} - -.fw-shell:before { - content:"\e730"; -} - -.fw-shortcut:before { - content:"\e725"; -} - -.fw-sign-in:before { - content:"\e671"; -} - -.fw-sign-out:before { - content:"\e6b8"; -} - -.fw-skype:before { - content:"\e6de"; -} - -.fw-slash:before { - content:"\e6e1"; -} - -.fw-soap:before { - content:"\e672"; -} - -.fw-sort-down:before { - content:"\e663"; -} - -.fw-sort-up:before { - content:"\e64b"; -} - -.fw-sort:before { - content:"\e673"; -} - -.fw-speed-alert:before { - content:"\e731"; -} - -.fw-square-outline:before { - content:"\e6b2"; -} - -.fw-square:before { - content:"\e6b1"; -} - -.fw-star:before { - content:"\e674"; -} - -.fw-start:before { - content:"\e718"; -} - -.fw-statistics:before { - content:"\e675"; -} - -.fw-stepin:before { - content:"\e719"; -} - -.fw-stepout:before { - content:"\e71a"; -} - -.fw-stepover:before { - content:"\e71b"; -} - -.fw-stop:before { - content:"\e71c"; -} - -.fw-store:before, .fw-cart:before { - content:"\e676"; -} - -.fw-struct:before { - content:"\e716"; -} - -.fw-subscribe:before { - content:"\e677"; -} - -.fw-success:before { - content:"\e657"; -} - -.fw-swagger:before { - content:"\e679"; -} - -.fw-sync:before { - content:"\e6b3"; -} - -.fw-table:before { - content:"\e6c4"; -} - -.fw-tag:before { - content:"\e67a"; -} - -.fw-task:before { - content:"\e67b"; -} - -.fw-text:before { - content:"\e67c"; -} - -.fw-theme:before { - content:"\e726"; -} - -.fw-throttling-policy:before { - content:"\e67f"; -} - -.fw-throw:before { - content:"\e722"; -} - -.fw-tiles:before { - content:"\e681"; -} - -.fw-transaction:before { - content:"\e72b"; -} - -.fw-try-catch:before { - content:"\e703"; -} - -.fw-twitter:before { - content:"\e6df"; -} - -.fw-type-converter:before { - content:"\e6f3"; -} - -.fw-uncheck:before { - content:"\e682"; -} - -.fw-undo:before { - content:"\e683"; -} - -.fw-ungroup:before { - content:"\e6b5"; -} - -.fw-unmute:before { - content:"\e6ae"; -} - -.fw-up-arrow:before { - content:"\e688"; -} - -.fw-up:before { - content:"\e684"; -} - -.fw-upload:before { - content:"\e68c"; -} - -.fw-uri:before { - content:"\e68d"; -} - -.fw-usb-drive:before { - content:"\e68e"; -} - -.fw-use:before { - content:"\e6ca"; -} - -.fw-user:before { - content:"\e68f"; -} - -.fw-variable:before { - content:"\e6ee"; -} - -.fw-view:before { - content:"\e691"; -} - -.fw-vpn:before { - content:"\e603"; -} - -.fw-wadl:before { - content:"\e6a1"; -} - -.fw-war:before { - content:"\e69e"; -} - -.fw-warning:before { - content:"\e693"; -} - -.fw-web-app:before { - content:"\e696"; -} - -.fw-web-clip:before { - content:"\e698"; -} - -.fw-web-service:before { - content:"\e69a"; -} - -.fw-website:before { - content:"\e69b"; -} - -.fw-wifi:before { - content:"\e607"; -} - -.fw-windows:before { - content:"\e605"; -} - -.fw-worker-invoke:before { - content:"\e723"; -} - -.fw-worker-reply:before { - content:"\e724"; -} - -.fw-worker:before { - content:"\e6ef"; -} - -.fw-wsdl:before { - content:"\e6a0"; -} - -.fw-wso2-logo:before { - content:"\e6a7"; -} - -.fw-wso2:before { - content:"\e6a8"; -} - -.fw-xacml:before { - content:"\e69f"; -} - -.fw-xml:before { - content:"\e69c"; -} - -.fw-xq:before { - content:"\e6a2"; -} - -.fw-xsd:before { - content:"\e6a3"; -} - -.fw-xslt:before { - content:"\e6a4"; -} - -.fw-youtube:before { - content:"\e6e0"; -} - -.fw-zoom-in:before { - content:"\e6a5"; -} - -.fw-zoom-out:before { - content:"\e6a6"; -} - + url("../fonts/font-wso2.svg?6563fa91278f239ef8c827d90a165223#font-wso2") format("svg"); + font-weight:normal; + font-style:normal; +} + +.fw, [class^="fw-"], [class*=" fw-"] { + font: normal normal normal 14px/1 font-wso2; + display: inline-block; + font-weight: normal; + font-style: normal; + font-size: inherit; + font-variant: normal; + speak: none; + text-decoration: inherit; + + /* Better Font Rendering =========== */ + text-transform: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +/* ======================================================================== + * font options + * ======================================================================== */ + +.fw-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fw-2x { + font-size: 2em; +} +.fw-3x { + font-size: 3em; +} +.fw-4x { + font-size: 4em; +} +.fw-5x { + font-size: 5em; +} +.fw-fw { + width: 1.28571429em; + text-align: center; +} +.fw-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fw-ul > li { + position: relative; +} +.fw-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fw-li.fw-lg { + left: -1.85714286em; +} +.fw-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fw-background { + background: #888; + border-radius: .3em; + padding: .4em .50em .45em; +} +.fw-pull-left { + float: left; +} +.fw-pull-right { + float: right; +} +.fw.fw-pull-left { + margin-right: .3em; +} +.fw.fw-pull-right { + margin-left: .3em; +} +.fw-spin { + -webkit-animation: fw-spin 2s infinite linear; + animation: fw-spin 2s infinite linear; +} +@-webkit-keyframes fw-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fw-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fw-pulse { + -webkit-animation: fw-pulse 2s ease-out infinite; + animation: fw-pulse 2s ease-out infinite; +} +@-webkit-keyframes fw-pulse { + 0%, 30% { + opacity: 0.3; + } + 40% { + opacity: 1; + } + 100% { + opacity: 0.3; + } +} +@keyframes fw-pulse { + 0%, 30% { + opacity: 0.3; + } + 40% { + opacity: 1; + } + 100% { + opacity: 0.3; + } +} +.fw-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fw-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fw-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fw-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fw-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fw-rotate-90, +:root .fw-rotate-180, +:root .fw-rotate-270, +:root .fw-flip-horizontal, +:root .fw-flip-vertical { + filter: none; +} +.fw-stack, +.fw-helper { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 1.85em; + vertical-align: middle; +} +.fw-stack-1x, +.fw-stack-2x, +.fw-helper:before, +.fw-helper:after { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fw-stack-1x, +.fw-helper:before { + line-height: inherit; +} +.fw-stack-2x, +.fw-helper:after { + font-size: 1.9em; +} +.fw-helper-slash:before { + font-size: 1.4em; +} +.fw-helper-circle:before, +.fw-helper-square:before { + z-index: 1; +} +.fw-helper-circle-outline:after { + content: "\e61f"; +} +.fw-helper-circle:after { + content: "\e61a"; +} +.fw-helper-square-outline:after { + content: "\e6b2"; +} +.fw-helper-square:after { + content: "\e6b1"; +} +.fw-helper-slash:after { + content: "\e6e1"; +} +.fw-stack > .fw-stack { + position: absolute; + font-size: 0.5em; +} +.fw-stack > .fw-stack.fw-move-top { + top: -0.2em; +} +.fw-stack > .fw-stack.fw-move-bottom { + bottom: -0.2em; +} +.fw-stack > .fw.stack.fw-move-left { + left: -0.5em; +} +.fw-stack > .fw-stack.fw-move-right { + right: -0.5em; +} +.fw-inverse:before, +.fw-helper-inverse:after, +.fw-number { + color: #ffffff; +} +.fw-shadow:before, +.fw-helper-shadow:after { + text-shadow: #ffffff 1px 1px 0; +} +.fw-stroke:before, +.fw-helper-stroke:after { + text-shadow: -2px -2px 0 #ffffff, + 2px -2px 0 #ffffff, + -2px 2px 0 #ffffff, + 2px 2px 0 #ffffff; +} +.fw-number { + line-height: 2em; + font-family: Arial, Helvetica, sans-serif; +} + + +/* ======================================================================== + * font icons + * ======================================================================== */ + +.fw-abort:before { + content:"\e72a"; +} + +.fw-action-invoke:before { + content:"\e6fe"; +} + +.fw-action:before { + content:"\e709"; +} + +.fw-activate:before { + content:"\e6cf"; +} + +.fw-add:before { + content:"\e615"; +} + +.fw-airplay:before { + content:"\e600"; +} + +.fw-alarm:before { + content:"\e6c2"; +} + +.fw-alert:before { + content:"\e6be"; +} + +.fw-analytics-extensions:before { + content:"\e6e2"; +} + +.fw-android-logcat:before { + content:"\e72c"; +} + +.fw-android-sense:before { + content:"\e72d"; +} + +.fw-android:before { + content:"\e606"; +} + +.fw-annotation:before { + content:"\e6e6"; +} + +.fw-api:before { + content:"\e601"; +} + +.fw-apn:before { + content:"\e602"; +} + +.fw-ios:before { + content:"\e604"; +} + +.fw-application:before { + content:"\e608"; +} + +.fw-arduino:before { + content:"\e6ab"; +} + +.fw-assign:before { + content:"\e6ff"; +} + +.fw-ballerina-service:before { + content:"\e729"; +} + +.fw-ballerina:before { + content:"\e728"; +} + +.fw-bar-chart:before { + content:"\e690"; +} + +.fw-battery:before { + content:"\e60a"; +} + +.fw-blank-document:before { + content:"\e60c"; +} + +.fw-block:before { + content:"\e695"; +} + +.fw-bookmark:before { + content:"\e60d"; +} + +.fw-bpel:before { + content:"\e60e"; +} + +.fw-bpmn:before { + content:"\e60f"; +} + +.fw-break:before { + content:"\e721"; +} + +.fw-bug:before { + content:"\e611"; +} + +.fw-build:before { + content:"\e6c1"; +} + +.fw-calendar:before { + content:"\e612"; +} + +.fw-camera:before { + content:"\e613"; +} + +.fw-cancel:before { + content:"\e618"; +} + +.fw-carbon:before { + content:"\e6c5"; +} + +.fw-chat:before { + content:"\e65b"; +} + +.fw-check:before { + content:"\e617"; +} + +.fw-checklist:before { + content:"\e619"; +} + +.fw-circle-outline:before { + content:"\e61f"; +} + +.fw-circle:before { + content:"\e61a"; +} + +.fw-clear:before { + content:"\e61b"; +} + +.fw-clock:before { + content:"\e61d"; +} + +.fw-cloud:before { + content:"\e61e"; +} + +.fw-code-view:before { + content:"\e70e"; +} + +.fw-code:before { + content:"\e6f1"; +} + +.fw-comment:before { + content:"\e710"; +} + +.fw-compare:before { + content:"\e610"; +} + +.fw-computer:before { + content:"\e653"; +} + +.fw-configarations:before { + content:"\e609"; +} + +.fw-connector:before { + content:"\e700"; +} + +.fw-console:before { + content:"\e71d"; +} + +.fw-constant:before { + content:"\e701"; +} + +.fw-contact:before { + content:"\e620"; +} + +.fw-contract:before { + content:"\e614"; +} + +.fw-copy:before { + content:"\e621"; +} + +.fw-cut:before { + content:"\e6f2"; +} + +.fw-dashboard:before { + content:"\e622"; +} + +.fw-database:before { + content:"\e623"; +} + +.fw-delete:before { + content:"\e624"; +} + +.fw-depend:before { + content:"\e6c6"; +} + +.fw-deploy:before { + content:"\e625"; +} + +.fw-deprecate:before { + content:"\e6cb"; +} + +.fw-design-view:before { + content:"\e70f"; +} + +.fw-devices:before { + content:"\e704"; +} + +.fw-dgm-action-invoke:before { + content:"\e712"; +} + +.fw-dgm-action:before { + content:"\e711"; +} + +.fw-dgm-connector:before { + content:"\e6f4"; +} + +.fw-dgm-constant-definition:before { + content:"\e6f5"; +} + +.fw-dgm-fork:before { + content:"\e6e7"; +} + +.fw-dgm-header:before { + content:"\e6e8"; +} + +.fw-dgm-if-else:before { + content:"\e6e9"; +} + +.fw-dgm-import:before { + content:"\e717"; +} + +.fw-dgm-lifeline:before { + content:"\e6ea"; +} + +.fw-dgm-logger:before { + content:"\e6eb"; +} + +.fw-dgm-resource:before { + content:"\e6f6"; +} + +.fw-dgm-service:before { + content:"\e6f7"; +} + +.fw-dgm-try-catch:before { + content:"\e6ec"; +} + +.fw-dgm-type-convertor:before { + content:"\e6f8"; +} + +.fw-dgm-type:before { + content:"\e6f9"; +} + +.fw-dgm-while:before { + content:"\e707"; +} + +.fw-dial-up:before { + content:"\e627"; +} + +.fw-disabled:before { + content:"\e6d1"; +} + +.fw-display:before { + content:"\e626"; +} + +.fw-docker:before { + content:"\e70c"; +} + +.fw-document:before { + content:"\e628"; +} + +.fw-down-arrow:before { + content:"\e689"; +} + +.fw-down:before { + content:"\e685"; +} + +.fw-download:before { + content:"\e65f"; +} + +.fw-dss:before { + content:"\e62a"; +} + +.fw-ebook:before { + content:"\e62b"; +} + +.fw-edit:before { + content:"\e62c"; +} + +.fw-ellipsis:before { + content:"\e629"; +} + +.fw-endpoint:before { + content:"\e62d"; +} + +.fw-enterprise:before { + content:"\e6b6"; +} + +.fw-error:before { + content:"\e630"; +} + +.fw-esb-connector:before { + content:"\e6e3"; +} + +.fw-expand:before { + content:"\e61c"; +} + +.fw-export:before { + content:"\e631"; +} + +.fw-extensions:before { + content:"\e6e4"; +} + +.fw-facebook:before { + content:"\e6d3"; +} + +.fw-factory-reset:before { + content:"\e632"; +} + +.fw-fan:before { + content:"\e678"; +} + +.fw-faq:before { + content:"\e62f"; +} + +.fw-file-browse:before { + content:"\e633"; +} + +.fw-filter:before { + content:"\e634"; +} + +.fw-folder-open:before { + content:"\e70b"; +} + +.fw-folder:before { + content:"\e62e"; +} + +.fw-fork-join:before { + content:"\e720"; +} + +.fw-format:before { + content:"\e6fa"; +} + +.fw-forum:before { + content:"\e636"; +} + +.fw-function-invoke:before { + content:"\e713"; +} + +.fw-function:before { + content:"\e6fb"; +} + +.fw-gadget:before { + content:"\e637"; +} + +.fw-geo-fence-inbound:before { + content:"\e72e"; +} + +.fw-geo-fence-outbound:before { + content:"\e72f"; +} + +.fw-github:before { + content:"\e6d4"; +} + +.fw-globe:before { + content:"\e697"; +} + +.fw-google-docs:before { + content:"\e6d6"; +} + +.fw-google-drive:before { + content:"\e6da"; +} + +.fw-google-plus:before { + content:"\e6d9"; +} + +.fw-google-sheets:before { + content:"\e6d7"; +} + +.fw-google-slides:before { + content:"\e6d8"; +} + +.fw-google:before { + content:"\e6d5"; +} + +.fw-grid:before { + content:"\e638"; +} + +.fw-grip:before { + content:"\e6b7"; +} + +.fw-group:before { + content:"\e6af"; +} + +.fw-hardware:before { + content:"\e6a9"; +} + +.fw-hdd:before { + content:"\e639"; +} + +.fw-heart:before { + content:"\e6c3"; +} + +.fw-hide:before { + content:"\e6d2"; +} + +.fw-home:before { + content:"\e63a"; +} + +.fw-hour-glass:before { + content:"\e63b"; +} + +.fw-html:before { + content:"\e69d"; +} + +.fw-http:before { + content:"\e705"; +} + +.fw-image:before { + content:"\e70a"; +} + +.fw-import:before { + content:"\e63c"; +} + +.fw-incoming-call:before { + content:"\e63d"; +} + +.fw-info:before { + content:"\e63e"; +} + +.fw-instagram:before { + content:"\e6db"; +} + +.fw-invitation:before { + content:"\e63f"; +} + +.fw-invoke:before { + content:"\e6ed"; +} + +.fw-is-connector:before { + content:"\e6e5"; +} + +.fw-iterate:before { + content:"\e71f"; +} + +.fw-jaggery:before { + content:"\e640"; +} + +.fw-java-spring:before { + content:"\e644"; +} + +.fw-java:before { + content:"\e641"; +} + +.fw-javaee:before { + content:"\e642"; +} + +.fw-javascript:before { + content:"\e643"; +} + +.fw-jaxrs:before { + content:"\e645"; +} + +.fw-jaxws:before { + content:"\e6c7"; +} + +.fw-jquery:before { + content:"\e646"; +} + +.fw-key:before { + content:"\e647"; +} + +.fw-laptop:before { + content:"\e648"; +} + +.fw-layout:before { + content:"\e6bf"; +} + +.fw-ldap:before { + content:"\e649"; +} + +.fw-left-arrow:before { + content:"\e68a"; +} + +.fw-left:before { + content:"\e686"; +} + +.fw-lifecycle:before { + content:"\e64a"; +} + +.fw-light:before { + content:"\e680"; +} + +.fw-linkedin:before { + content:"\e6dc"; +} + +.fw-list-sort:before { + content:"\e64d"; +} + +.fw-list:before { + content:"\e64c"; +} + +.fw-loader:before { + content:"\e6b4"; +} + +.fw-loader2:before { + content:"\e6ba"; +} + +.fw-loader3:before { + content:"\e6bb"; +} + +.fw-loader4:before { + content:"\e6bc"; +} + +.fw-loader5:before { + content:"\e6bd"; +} + +.fw-lock:before { + content:"\e64e"; +} + +.fw-logical:before { + content:"\e702"; +} + +.fw-mail:before { + content:"\e64f"; +} + +.fw-main-function:before { + content:"\e706"; +} + +.fw-map-location:before { + content:"\e650"; +} + +.fw-menu:before { + content:"\e651"; +} + +.fw-message:before { + content:"\e635"; +} + +.fw-micro-services:before { + content:"\e6ce"; +} + +.fw-minus:before, .fw-hyphen:before, .fw-dash:before { + content:"\e616"; +} + +.fw-mobile:before { + content:"\e652"; +} + +.fw-ms-document:before { + content:"\e654"; +} + +.fw-mute:before { + content:"\e655"; +} + +.fw-nodejs:before { + content:"\e656"; +} + +.fw-notification:before { + content:"\e60b"; +} + +.fw-organization:before { + content:"\e6ac"; +} + +.fw-own:before { + content:"\e6c8"; +} + +.fw-package:before { + content:"\e6fd"; +} + +.fw-pages:before { + content:"\e6c0"; +} + +.fw-paste:before { + content:"\e658"; +} + +.fw-pdf:before { + content:"\e659"; +} + +.fw-pending:before { + content:"\e727"; +} + +.fw-php:before { + content:"\e6c9"; +} + +.fw-pie-chart:before { + content:"\e65a"; +} + +.fw-pinterest:before { + content:"\e6dd"; +} + +.fw-policy:before { + content:"\e67d"; +} + +.fw-polygon:before { + content:"\e70d"; +} + +.fw-prototype:before { + content:"\e6cc"; +} + +.fw-proxy:before { + content:"\e699"; +} + +.fw-public:before { + content:"\e6ad"; +} + +.fw-publish:before { + content:"\e65c"; +} + +.fw-question:before { + content:"\e6b0"; +} + +.fw-raspberry:before { + content:"\e6aa"; +} + +.fw-redo:before { + content:"\e65d"; +} + +.fw-refresh:before { + content:"\e692"; +} + +.fw-register:before { + content:"\e65e"; +} + +.fw-rename:before { + content:"\e6fc"; +} + +.fw-reply:before { + content:"\e714"; +} + +.fw-resource:before { + content:"\e660"; +} + +.fw-rest-api:before { + content:"\e661"; +} + +.fw-rest-service:before { + content:"\e662"; +} + +.fw-resume:before { + content:"\e71e"; +} + +.fw-retire:before { + content:"\e6cd"; +} + +.fw-return:before { + content:"\e715"; +} + +.fw-retweet:before { + content:"\e6b9"; +} + +.fw-right-arrow:before { + content:"\e68b"; +} + +.fw-right:before { + content:"\e687"; +} + +.fw-ringing:before { + content:"\e694"; +} + +.fw-rules:before { + content:"\e664"; +} + +.fw-run:before { + content:"\e708"; +} + +.fw-save:before { + content:"\e665"; +} + +.fw-scep:before { + content:"\e666"; +} + +.fw-schema:before { + content:"\e667"; +} + +.fw-search:before { + content:"\e668"; +} + +.fw-security-policy:before { + content:"\e67e"; +} + +.fw-security:before { + content:"\e669"; +} + +.fw-send:before, .fw-paper-rocket:before { + content:"\e66a"; +} + +.fw-sequence:before { + content:"\e66b"; +} + +.fw-server:before { + content:"\e66c"; +} + +.fw-service-provider:before { + content:"\e66e"; +} + +.fw-service:before, .fw-cogwheels:before, .fw-gears:before, .fw-sprockets:before { + content:"\e66d"; +} + +.fw-settings:before, .fw-cogwheel:before, .fw-gear:before, .fw-sprocket:before { + content:"\e66f"; +} + +.fw-share:before { + content:"\e670"; +} + +.fw-shell:before { + content:"\e730"; +} + +.fw-shortcut:before { + content:"\e725"; +} + +.fw-sign-in:before { + content:"\e671"; +} + +.fw-sign-out:before { + content:"\e6b8"; +} + +.fw-skype:before { + content:"\e6de"; +} + +.fw-slash:before { + content:"\e6e1"; +} + +.fw-soap:before { + content:"\e672"; +} + +.fw-sort-down:before { + content:"\e663"; +} + +.fw-sort-up:before { + content:"\e64b"; +} + +.fw-sort:before { + content:"\e673"; +} + +.fw-speed-alert:before { + content:"\e731"; +} + +.fw-square-outline:before { + content:"\e6b2"; +} + +.fw-square:before { + content:"\e6b1"; +} + +.fw-star:before { + content:"\e674"; +} + +.fw-start:before { + content:"\e718"; +} + +.fw-statistics:before { + content:"\e675"; +} + +.fw-stepin:before { + content:"\e719"; +} + +.fw-stepout:before { + content:"\e71a"; +} + +.fw-stepover:before { + content:"\e71b"; +} + +.fw-stop:before { + content:"\e71c"; +} + +.fw-store:before, .fw-cart:before { + content:"\e676"; +} + +.fw-struct:before { + content:"\e716"; +} + +.fw-subscribe:before { + content:"\e677"; +} + +.fw-success:before { + content:"\e657"; +} + +.fw-swagger:before { + content:"\e679"; +} + +.fw-sync:before { + content:"\e6b3"; +} + +.fw-table:before { + content:"\e6c4"; +} + +.fw-tag:before { + content:"\e67a"; +} + +.fw-task:before { + content:"\e67b"; +} + +.fw-text:before { + content:"\e67c"; +} + +.fw-theme:before { + content:"\e726"; +} + +.fw-throttling-policy:before { + content:"\e67f"; +} + +.fw-throw:before { + content:"\e722"; +} + +.fw-tiles:before { + content:"\e681"; +} + +.fw-transaction:before { + content:"\e72b"; +} + +.fw-try-catch:before { + content:"\e703"; +} + +.fw-twitter:before { + content:"\e6df"; +} + +.fw-type-converter:before { + content:"\e6f3"; +} + +.fw-uncheck:before { + content:"\e682"; +} + +.fw-undo:before { + content:"\e683"; +} + +.fw-ungroup:before { + content:"\e6b5"; +} + +.fw-unmute:before { + content:"\e6ae"; +} + +.fw-up-arrow:before { + content:"\e688"; +} + +.fw-up:before { + content:"\e684"; +} + +.fw-upload:before { + content:"\e68c"; +} + +.fw-uri:before { + content:"\e68d"; +} + +.fw-usb-drive:before { + content:"\e68e"; +} + +.fw-use:before { + content:"\e6ca"; +} + +.fw-user:before { + content:"\e68f"; +} + +.fw-variable:before { + content:"\e6ee"; +} + +.fw-view:before { + content:"\e691"; +} + +.fw-vpn:before { + content:"\e603"; +} + +.fw-wadl:before { + content:"\e6a1"; +} + +.fw-war:before { + content:"\e69e"; +} + +.fw-warning:before { + content:"\e693"; +} + +.fw-web-app:before { + content:"\e696"; +} + +.fw-web-clip:before { + content:"\e698"; +} + +.fw-web-service:before { + content:"\e69a"; +} + +.fw-website:before { + content:"\e69b"; +} + +.fw-wifi:before { + content:"\e607"; +} + +.fw-windows:before { + content:"\e605"; +} + +.fw-worker-invoke:before { + content:"\e723"; +} + +.fw-worker-reply:before { + content:"\e724"; +} + +.fw-worker:before { + content:"\e6ef"; +} + +.fw-wsdl:before { + content:"\e6a0"; +} + +.fw-wso2-logo:before { + content:"\e6a7"; +} + +.fw-wso2:before { + content:"\e6a8"; +} + +.fw-xacml:before { + content:"\e69f"; +} + +.fw-xml:before { + content:"\e69c"; +} + +.fw-xq:before { + content:"\e6a2"; +} + +.fw-xsd:before { + content:"\e6a3"; +} + +.fw-xslt:before { + content:"\e6a4"; +} + +.fw-youtube:before { + content:"\e6e0"; +} + +.fw-zoom-in:before { + content:"\e6a5"; +} + +.fw-zoom-out:before { + content:"\e6a6"; +} + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.min.css b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.min.css index 6c3d742e3b..8d2a487bef 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.min.css +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/app/units/uuf.unit.theme/public/lib/font-wso2-1.3.0/css/font-wso2.min.css @@ -1,15 +1,15 @@ -/*! -~ Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved. -~ -~ Licensed under the Apache License, Version 2.0 (the "License"); -~ you may not use this file except in compliance with the License. -~ You may obtain a copy of the License at -~ -~ http://www.apache.org/licenses/LICENSE-2.0 -~ -~ Unless required by applicable law or agreed to in writing, software -~ distributed under the License is distributed on an "AS IS" BASIS, -~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -~ See the License for the specific language governing permissions and -~ limitations under the License. -*/.fw-fw,.fw-li{text-align:center}@font-face{font-family:font-wso2;src:local("font-wso2"),url(../fonts/font-wso2.eot?6563fa91278f239ef8c827d90a165223);src:local("font-wso2"),url(../fonts/font-wso2.eot?#iefix) format("embedded-opentype"),url(../fonts/font-wso2.woff2?6563fa91278f239ef8c827d90a165223) format("woff2"),url(../fonts/font-wso2.woff?6563fa91278f239ef8c827d90a165223) format("woff"),url(../fonts/font-wso2.ttf?6563fa91278f239ef8c827d90a165223) format("truetype"),url(../fonts/font-wso2.svg?6563fa91278f239ef8c827d90a165223#font-wso2) format("svg");font-weight:400;font-style:normal}.fw,[class*=" fw-"],[class^=fw-]{font:normal normal normal 14px/1 font-wso2;display:inline-block;font-weight:400;font-style:normal;font-size:inherit;font-variant:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fw-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fw-2x{font-size:2em}.fw-3x{font-size:3em}.fw-4x{font-size:4em}.fw-5x{font-size:5em}.fw-fw{width:1.28571429em}.fw-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fw-ul>li{position:relative}.fw-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em}.fw-li.fw-lg{left:-1.85714286em}.fw-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fw-background{background:#888;border-radius:.3em;padding:.4em .5em .45em}.fw-pull-left{float:left}.fw-pull-right{float:right}.fw.fw-pull-left{margin-right:.3em}.fw.fw-pull-right{margin-left:.3em}.fw-spin{-webkit-animation:fw-spin 2s infinite linear;animation:fw-spin 2s infinite linear}@-webkit-keyframes fw-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fw-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fw-pulse{-webkit-animation:fw-pulse 2s ease-out infinite;animation:fw-pulse 2s ease-out infinite}@-webkit-keyframes fw-pulse{0%,100%,30%{opacity:.3}40%{opacity:1}}@keyframes fw-pulse{0%,100%,30%{opacity:.3}40%{opacity:1}}.fw-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fw-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fw-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fw-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fw-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fw-flip-horizontal,:root .fw-flip-vertical,:root .fw-rotate-180,:root .fw-rotate-270,:root .fw-rotate-90{filter:none}.fw-helper,.fw-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:1.85em;vertical-align:middle}.fw-helper:after,.fw-helper:before,.fw-stack-1x,.fw-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fw-helper:before,.fw-stack-1x{line-height:inherit}.fw-helper:after,.fw-stack-2x{font-size:1.9em}.fw-helper-slash:before{font-size:1.4em}.fw-helper-circle:before,.fw-helper-square:before{z-index:1}.fw-helper-circle-outline:after{content:"\e61f"}.fw-helper-circle:after{content:"\e61a"}.fw-helper-square-outline:after{content:"\e6b2"}.fw-helper-square:after{content:"\e6b1"}.fw-helper-slash:after{content:"\e6e1"}.fw-stack>.fw-stack{position:absolute;font-size:.5em}.fw-stack>.fw-stack.fw-move-top{top:-.2em}.fw-stack>.fw-stack.fw-move-bottom{bottom:-.2em}.fw-stack>.fw.stack.fw-move-left{left:-.5em}.fw-stack>.fw-stack.fw-move-right{right:-.5em}.fw-helper-inverse:after,.fw-inverse:before,.fw-number{color:#fff}.fw-helper-shadow:after,.fw-shadow:before{text-shadow:#fff 1px 1px 0}.fw-helper-stroke:after,.fw-stroke:before{text-shadow:-2px -2px 0 #fff,2px -2px 0 #fff,-2px 2px 0 #fff,2px 2px 0 #fff}.fw-number{line-height:2em;font-family:Arial,Helvetica,sans-serif}.fw-abort:before{content:"\e72a"}.fw-action-invoke:before{content:"\e6fe"}.fw-action:before{content:"\e709"}.fw-activate:before{content:"\e6cf"}.fw-add:before{content:"\e615"}.fw-airplay:before{content:"\e600"}.fw-alarm:before{content:"\e6c2"}.fw-alert:before{content:"\e6be"}.fw-analytics-extensions:before{content:"\e6e2"}.fw-android-logcat:before{content:"\e72c"}.fw-android-sense:before{content:"\e72d"}.fw-android:before{content:"\e606"}.fw-annotation:before{content:"\e6e6"}.fw-api:before{content:"\e601"}.fw-apn:before{content:"\e602"}.fw-apple:before{content:"\e604"}.fw-application:before{content:"\e608"}.fw-arduino:before{content:"\e6ab"}.fw-assign:before{content:"\e6ff"}.fw-ballerina-service:before{content:"\e729"}.fw-ballerina:before{content:"\e728"}.fw-bar-chart:before{content:"\e690"}.fw-battery:before{content:"\e60a"}.fw-blank-document:before{content:"\e60c"}.fw-block:before{content:"\e695"}.fw-bookmark:before{content:"\e60d"}.fw-bpel:before{content:"\e60e"}.fw-bpmn:before{content:"\e60f"}.fw-break:before{content:"\e721"}.fw-bug:before{content:"\e611"}.fw-build:before{content:"\e6c1"}.fw-calendar:before{content:"\e612"}.fw-camera:before{content:"\e613"}.fw-cancel:before{content:"\e618"}.fw-carbon:before{content:"\e6c5"}.fw-chat:before{content:"\e65b"}.fw-check:before{content:"\e617"}.fw-checklist:before{content:"\e619"}.fw-circle-outline:before{content:"\e61f"}.fw-circle:before{content:"\e61a"}.fw-clear:before{content:"\e61b"}.fw-clock:before{content:"\e61d"}.fw-cloud:before{content:"\e61e"}.fw-code-view:before{content:"\e70e"}.fw-code:before{content:"\e6f1"}.fw-comment:before{content:"\e710"}.fw-compare:before{content:"\e610"}.fw-computer:before{content:"\e653"}.fw-configarations:before{content:"\e609"}.fw-connector:before{content:"\e700"}.fw-console:before{content:"\e71d"}.fw-constant:before{content:"\e701"}.fw-contact:before{content:"\e620"}.fw-contract:before{content:"\e614"}.fw-copy:before{content:"\e621"}.fw-cut:before{content:"\e6f2"}.fw-dashboard:before{content:"\e622"}.fw-database:before{content:"\e623"}.fw-delete:before{content:"\e624"}.fw-depend:before{content:"\e6c6"}.fw-deploy:before{content:"\e625"}.fw-deprecate:before{content:"\e6cb"}.fw-design-view:before{content:"\e70f"}.fw-devices:before{content:"\e704"}.fw-dgm-action-invoke:before{content:"\e712"}.fw-dgm-action:before{content:"\e711"}.fw-dgm-connector:before{content:"\e6f4"}.fw-dgm-constant-definition:before{content:"\e6f5"}.fw-dgm-fork:before{content:"\e6e7"}.fw-dgm-header:before{content:"\e6e8"}.fw-dgm-if-else:before{content:"\e6e9"}.fw-dgm-import:before{content:"\e717"}.fw-dgm-lifeline:before{content:"\e6ea"}.fw-dgm-logger:before{content:"\e6eb"}.fw-dgm-resource:before{content:"\e6f6"}.fw-dgm-service:before{content:"\e6f7"}.fw-dgm-try-catch:before{content:"\e6ec"}.fw-dgm-type-convertor:before{content:"\e6f8"}.fw-dgm-type:before{content:"\e6f9"}.fw-dgm-while:before{content:"\e707"}.fw-dial-up:before{content:"\e627"}.fw-disabled:before{content:"\e6d1"}.fw-display:before{content:"\e626"}.fw-docker:before{content:"\e70c"}.fw-document:before{content:"\e628"}.fw-down-arrow:before{content:"\e689"}.fw-down:before{content:"\e685"}.fw-download:before{content:"\e65f"}.fw-dss:before{content:"\e62a"}.fw-ebook:before{content:"\e62b"}.fw-edit:before{content:"\e62c"}.fw-ellipsis:before{content:"\e629"}.fw-endpoint:before{content:"\e62d"}.fw-enterprise:before{content:"\e6b6"}.fw-error:before{content:"\e630"}.fw-esb-connector:before{content:"\e6e3"}.fw-expand:before{content:"\e61c"}.fw-export:before{content:"\e631"}.fw-extensions:before{content:"\e6e4"}.fw-facebook:before{content:"\e6d3"}.fw-factory-reset:before{content:"\e632"}.fw-fan:before{content:"\e678"}.fw-faq:before{content:"\e62f"}.fw-file-browse:before{content:"\e633"}.fw-filter:before{content:"\e634"}.fw-folder-open:before{content:"\e70b"}.fw-folder:before{content:"\e62e"}.fw-fork-join:before{content:"\e720"}.fw-format:before{content:"\e6fa"}.fw-forum:before{content:"\e636"}.fw-function-invoke:before{content:"\e713"}.fw-function:before{content:"\e6fb"}.fw-gadget:before{content:"\e637"}.fw-geo-fence-inbound:before{content:"\e72e"}.fw-geo-fence-outbound:before{content:"\e72f"}.fw-github:before{content:"\e6d4"}.fw-globe:before{content:"\e697"}.fw-google-docs:before{content:"\e6d6"}.fw-google-drive:before{content:"\e6da"}.fw-google-plus:before{content:"\e6d9"}.fw-google-sheets:before{content:"\e6d7"}.fw-google-slides:before{content:"\e6d8"}.fw-google:before{content:"\e6d5"}.fw-grid:before{content:"\e638"}.fw-grip:before{content:"\e6b7"}.fw-group:before{content:"\e6af"}.fw-hardware:before{content:"\e6a9"}.fw-hdd:before{content:"\e639"}.fw-heart:before{content:"\e6c3"}.fw-hide:before{content:"\e6d2"}.fw-home:before{content:"\e63a"}.fw-hour-glass:before{content:"\e63b"}.fw-html:before{content:"\e69d"}.fw-http:before{content:"\e705"}.fw-image:before{content:"\e70a"}.fw-import:before{content:"\e63c"}.fw-incoming-call:before{content:"\e63d"}.fw-info:before{content:"\e63e"}.fw-instagram:before{content:"\e6db"}.fw-invitation:before{content:"\e63f"}.fw-invoke:before{content:"\e6ed"}.fw-is-connector:before{content:"\e6e5"}.fw-iterate:before{content:"\e71f"}.fw-jaggery:before{content:"\e640"}.fw-java-spring:before{content:"\e644"}.fw-java:before{content:"\e641"}.fw-javaee:before{content:"\e642"}.fw-javascript:before{content:"\e643"}.fw-jaxrs:before{content:"\e645"}.fw-jaxws:before{content:"\e6c7"}.fw-jquery:before{content:"\e646"}.fw-key:before{content:"\e647"}.fw-laptop:before{content:"\e648"}.fw-layout:before{content:"\e6bf"}.fw-ldap:before{content:"\e649"}.fw-left-arrow:before{content:"\e68a"}.fw-left:before{content:"\e686"}.fw-lifecycle:before{content:"\e64a"}.fw-light:before{content:"\e680"}.fw-linkedin:before{content:"\e6dc"}.fw-list-sort:before{content:"\e64d"}.fw-list:before{content:"\e64c"}.fw-loader:before{content:"\e6b4"}.fw-loader2:before{content:"\e6ba"}.fw-loader3:before{content:"\e6bb"}.fw-loader4:before{content:"\e6bc"}.fw-loader5:before{content:"\e6bd"}.fw-lock:before{content:"\e64e"}.fw-logical:before{content:"\e702"}.fw-mail:before{content:"\e64f"}.fw-main-function:before{content:"\e706"}.fw-map-location:before{content:"\e650"}.fw-menu:before{content:"\e651"}.fw-message:before{content:"\e635"}.fw-micro-services:before{content:"\e6ce"}.fw-dash:before,.fw-hyphen:before,.fw-minus:before{content:"\e616"}.fw-mobile:before{content:"\e652"}.fw-ms-document:before{content:"\e654"}.fw-mute:before{content:"\e655"}.fw-nodejs:before{content:"\e656"}.fw-notification:before{content:"\e60b"}.fw-organization:before{content:"\e6ac"}.fw-own:before{content:"\e6c8"}.fw-package:before{content:"\e6fd"}.fw-pages:before{content:"\e6c0"}.fw-paste:before{content:"\e658"}.fw-pdf:before{content:"\e659"}.fw-pending:before{content:"\e727"}.fw-php:before{content:"\e6c9"}.fw-pie-chart:before{content:"\e65a"}.fw-pinterest:before{content:"\e6dd"}.fw-policy:before{content:"\e67d"}.fw-polygon:before{content:"\e70d"}.fw-prototype:before{content:"\e6cc"}.fw-proxy:before{content:"\e699"}.fw-public:before{content:"\e6ad"}.fw-publish:before{content:"\e65c"}.fw-question:before{content:"\e6b0"}.fw-raspberry:before{content:"\e6aa"}.fw-redo:before{content:"\e65d"}.fw-refresh:before{content:"\e692"}.fw-register:before{content:"\e65e"}.fw-rename:before{content:"\e6fc"}.fw-reply:before{content:"\e714"}.fw-resource:before{content:"\e660"}.fw-rest-api:before{content:"\e661"}.fw-rest-service:before{content:"\e662"}.fw-resume:before{content:"\e71e"}.fw-retire:before{content:"\e6cd"}.fw-return:before{content:"\e715"}.fw-retweet:before{content:"\e6b9"}.fw-right-arrow:before{content:"\e68b"}.fw-right:before{content:"\e687"}.fw-ringing:before{content:"\e694"}.fw-rules:before{content:"\e664"}.fw-run:before{content:"\e708"}.fw-save:before{content:"\e665"}.fw-scep:before{content:"\e666"}.fw-schema:before{content:"\e667"}.fw-search:before{content:"\e668"}.fw-security-policy:before{content:"\e67e"}.fw-security:before{content:"\e669"}.fw-paper-rocket:before,.fw-send:before{content:"\e66a"}.fw-sequence:before{content:"\e66b"}.fw-server:before{content:"\e66c"}.fw-service-provider:before{content:"\e66e"}.fw-cogwheels:before,.fw-gears:before,.fw-service:before,.fw-sprockets:before{content:"\e66d"}.fw-cogwheel:before,.fw-gear:before,.fw-settings:before,.fw-sprocket:before{content:"\e66f"}.fw-share:before{content:"\e670"}.fw-shell:before{content:"\e730"}.fw-shortcut:before{content:"\e725"}.fw-sign-in:before{content:"\e671"}.fw-sign-out:before{content:"\e6b8"}.fw-skype:before{content:"\e6de"}.fw-slash:before{content:"\e6e1"}.fw-soap:before{content:"\e672"}.fw-sort-down:before{content:"\e663"}.fw-sort-up:before{content:"\e64b"}.fw-sort:before{content:"\e673"}.fw-speed-alert:before{content:"\e731"}.fw-square-outline:before{content:"\e6b2"}.fw-square:before{content:"\e6b1"}.fw-star:before{content:"\e674"}.fw-start:before{content:"\e718"}.fw-statistics:before{content:"\e675"}.fw-stepin:before{content:"\e719"}.fw-stepout:before{content:"\e71a"}.fw-stepover:before{content:"\e71b"}.fw-stop:before{content:"\e71c"}.fw-cart:before,.fw-store:before{content:"\e676"}.fw-struct:before{content:"\e716"}.fw-subscribe:before{content:"\e677"}.fw-success:before{content:"\e657"}.fw-swagger:before{content:"\e679"}.fw-sync:before{content:"\e6b3"}.fw-table:before{content:"\e6c4"}.fw-tag:before{content:"\e67a"}.fw-task:before{content:"\e67b"}.fw-text:before{content:"\e67c"}.fw-theme:before{content:"\e726"}.fw-throttling-policy:before{content:"\e67f"}.fw-throw:before{content:"\e722"}.fw-tiles:before{content:"\e681"}.fw-transaction:before{content:"\e72b"}.fw-try-catch:before{content:"\e703"}.fw-twitter:before{content:"\e6df"}.fw-type-converter:before{content:"\e6f3"}.fw-uncheck:before{content:"\e682"}.fw-undo:before{content:"\e683"}.fw-ungroup:before{content:"\e6b5"}.fw-unmute:before{content:"\e6ae"}.fw-up-arrow:before{content:"\e688"}.fw-up:before{content:"\e684"}.fw-upload:before{content:"\e68c"}.fw-uri:before{content:"\e68d"}.fw-usb-drive:before{content:"\e68e"}.fw-use:before{content:"\e6ca"}.fw-user:before{content:"\e68f"}.fw-variable:before{content:"\e6ee"}.fw-view:before{content:"\e691"}.fw-vpn:before{content:"\e603"}.fw-wadl:before{content:"\e6a1"}.fw-war:before{content:"\e69e"}.fw-warning:before{content:"\e693"}.fw-web-app:before{content:"\e696"}.fw-web-clip:before{content:"\e698"}.fw-web-service:before{content:"\e69a"}.fw-website:before{content:"\e69b"}.fw-wifi:before{content:"\e607"}.fw-windows:before{content:"\e605"}.fw-worker-invoke:before{content:"\e723"}.fw-worker-reply:before{content:"\e724"}.fw-worker:before{content:"\e6ef"}.fw-wsdl:before{content:"\e6a0"}.fw-wso2-logo:before{content:"\e6a7"}.fw-wso2:before{content:"\e6a8"}.fw-xacml:before{content:"\e69f"}.fw-xml:before{content:"\e69c"}.fw-xq:before{content:"\e6a2"}.fw-xsd:before{content:"\e6a3"}.fw-xslt:before{content:"\e6a4"}.fw-youtube:before{content:"\e6e0"}.fw-zoom-in:before{content:"\e6a5"}.fw-zoom-out:before{content:"\e6a6"} \ No newline at end of file +/*! +~ Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved. +~ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ +~ http://www.apache.org/licenses/LICENSE-2.0 +~ +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +*/.fw-fw,.fw-li{text-align:center}@font-face{font-family:font-wso2;src:local("font-wso2"),url(../fonts/font-wso2.eot?6563fa91278f239ef8c827d90a165223);src:local("font-wso2"),url(../fonts/font-wso2.eot?#iefix) format("embedded-opentype"),url(../fonts/font-wso2.woff2?6563fa91278f239ef8c827d90a165223) format("woff2"),url(../fonts/font-wso2.woff?6563fa91278f239ef8c827d90a165223) format("woff"),url(../fonts/font-wso2.ttf?6563fa91278f239ef8c827d90a165223) format("truetype"),url(../fonts/font-wso2.svg?6563fa91278f239ef8c827d90a165223#font-wso2) format("svg");font-weight:400;font-style:normal}.fw,[class*=" fw-"],[class^=fw-]{font:normal normal normal 14px/1 font-wso2;display:inline-block;font-weight:400;font-style:normal;font-size:inherit;font-variant:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fw-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fw-2x{font-size:2em}.fw-3x{font-size:3em}.fw-4x{font-size:4em}.fw-5x{font-size:5em}.fw-fw{width:1.28571429em}.fw-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fw-ul>li{position:relative}.fw-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em}.fw-li.fw-lg{left:-1.85714286em}.fw-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fw-background{background:#888;border-radius:.3em;padding:.4em .5em .45em}.fw-pull-left{float:left}.fw-pull-right{float:right}.fw.fw-pull-left{margin-right:.3em}.fw.fw-pull-right{margin-left:.3em}.fw-spin{-webkit-animation:fw-spin 2s infinite linear;animation:fw-spin 2s infinite linear}@-webkit-keyframes fw-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fw-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fw-pulse{-webkit-animation:fw-pulse 2s ease-out infinite;animation:fw-pulse 2s ease-out infinite}@-webkit-keyframes fw-pulse{0%,100%,30%{opacity:.3}40%{opacity:1}}@keyframes fw-pulse{0%,100%,30%{opacity:.3}40%{opacity:1}}.fw-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fw-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fw-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fw-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fw-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fw-flip-horizontal,:root .fw-flip-vertical,:root .fw-rotate-180,:root .fw-rotate-270,:root .fw-rotate-90{filter:none}.fw-helper,.fw-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:1.85em;vertical-align:middle}.fw-helper:after,.fw-helper:before,.fw-stack-1x,.fw-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fw-helper:before,.fw-stack-1x{line-height:inherit}.fw-helper:after,.fw-stack-2x{font-size:1.9em}.fw-helper-slash:before{font-size:1.4em}.fw-helper-circle:before,.fw-helper-square:before{z-index:1}.fw-helper-circle-outline:after{content:"\e61f"}.fw-helper-circle:after{content:"\e61a"}.fw-helper-square-outline:after{content:"\e6b2"}.fw-helper-square:after{content:"\e6b1"}.fw-helper-slash:after{content:"\e6e1"}.fw-stack>.fw-stack{position:absolute;font-size:.5em}.fw-stack>.fw-stack.fw-move-top{top:-.2em}.fw-stack>.fw-stack.fw-move-bottom{bottom:-.2em}.fw-stack>.fw.stack.fw-move-left{left:-.5em}.fw-stack>.fw-stack.fw-move-right{right:-.5em}.fw-helper-inverse:after,.fw-inverse:before,.fw-number{color:#fff}.fw-helper-shadow:after,.fw-shadow:before{text-shadow:#fff 1px 1px 0}.fw-helper-stroke:after,.fw-stroke:before{text-shadow:-2px -2px 0 #fff,2px -2px 0 #fff,-2px 2px 0 #fff,2px 2px 0 #fff}.fw-number{line-height:2em;font-family:Arial,Helvetica,sans-serif}.fw-abort:before{content:"\e72a"}.fw-action-invoke:before{content:"\e6fe"}.fw-action:before{content:"\e709"}.fw-activate:before{content:"\e6cf"}.fw-add:before{content:"\e615"}.fw-airplay:before{content:"\e600"}.fw-alarm:before{content:"\e6c2"}.fw-alert:before{content:"\e6be"}.fw-analytics-extensions:before{content:"\e6e2"}.fw-android-logcat:before{content:"\e72c"}.fw-android-sense:before{content:"\e72d"}.fw-android:before{content:"\e606"}.fw-annotation:before{content:"\e6e6"}.fw-api:before{content:"\e601"}.fw-apn:before{content:"\e602"}.fw-ios:before{content:"\e604"}.fw-application:before{content:"\e608"}.fw-arduino:before{content:"\e6ab"}.fw-assign:before{content:"\e6ff"}.fw-ballerina-service:before{content:"\e729"}.fw-ballerina:before{content:"\e728"}.fw-bar-chart:before{content:"\e690"}.fw-battery:before{content:"\e60a"}.fw-blank-document:before{content:"\e60c"}.fw-block:before{content:"\e695"}.fw-bookmark:before{content:"\e60d"}.fw-bpel:before{content:"\e60e"}.fw-bpmn:before{content:"\e60f"}.fw-break:before{content:"\e721"}.fw-bug:before{content:"\e611"}.fw-build:before{content:"\e6c1"}.fw-calendar:before{content:"\e612"}.fw-camera:before{content:"\e613"}.fw-cancel:before{content:"\e618"}.fw-carbon:before{content:"\e6c5"}.fw-chat:before{content:"\e65b"}.fw-check:before{content:"\e617"}.fw-checklist:before{content:"\e619"}.fw-circle-outline:before{content:"\e61f"}.fw-circle:before{content:"\e61a"}.fw-clear:before{content:"\e61b"}.fw-clock:before{content:"\e61d"}.fw-cloud:before{content:"\e61e"}.fw-code-view:before{content:"\e70e"}.fw-code:before{content:"\e6f1"}.fw-comment:before{content:"\e710"}.fw-compare:before{content:"\e610"}.fw-computer:before{content:"\e653"}.fw-configarations:before{content:"\e609"}.fw-connector:before{content:"\e700"}.fw-console:before{content:"\e71d"}.fw-constant:before{content:"\e701"}.fw-contact:before{content:"\e620"}.fw-contract:before{content:"\e614"}.fw-copy:before{content:"\e621"}.fw-cut:before{content:"\e6f2"}.fw-dashboard:before{content:"\e622"}.fw-database:before{content:"\e623"}.fw-delete:before{content:"\e624"}.fw-depend:before{content:"\e6c6"}.fw-deploy:before{content:"\e625"}.fw-deprecate:before{content:"\e6cb"}.fw-design-view:before{content:"\e70f"}.fw-devices:before{content:"\e704"}.fw-dgm-action-invoke:before{content:"\e712"}.fw-dgm-action:before{content:"\e711"}.fw-dgm-connector:before{content:"\e6f4"}.fw-dgm-constant-definition:before{content:"\e6f5"}.fw-dgm-fork:before{content:"\e6e7"}.fw-dgm-header:before{content:"\e6e8"}.fw-dgm-if-else:before{content:"\e6e9"}.fw-dgm-import:before{content:"\e717"}.fw-dgm-lifeline:before{content:"\e6ea"}.fw-dgm-logger:before{content:"\e6eb"}.fw-dgm-resource:before{content:"\e6f6"}.fw-dgm-service:before{content:"\e6f7"}.fw-dgm-try-catch:before{content:"\e6ec"}.fw-dgm-type-convertor:before{content:"\e6f8"}.fw-dgm-type:before{content:"\e6f9"}.fw-dgm-while:before{content:"\e707"}.fw-dial-up:before{content:"\e627"}.fw-disabled:before{content:"\e6d1"}.fw-display:before{content:"\e626"}.fw-docker:before{content:"\e70c"}.fw-document:before{content:"\e628"}.fw-down-arrow:before{content:"\e689"}.fw-down:before{content:"\e685"}.fw-download:before{content:"\e65f"}.fw-dss:before{content:"\e62a"}.fw-ebook:before{content:"\e62b"}.fw-edit:before{content:"\e62c"}.fw-ellipsis:before{content:"\e629"}.fw-endpoint:before{content:"\e62d"}.fw-enterprise:before{content:"\e6b6"}.fw-error:before{content:"\e630"}.fw-esb-connector:before{content:"\e6e3"}.fw-expand:before{content:"\e61c"}.fw-export:before{content:"\e631"}.fw-extensions:before{content:"\e6e4"}.fw-facebook:before{content:"\e6d3"}.fw-factory-reset:before{content:"\e632"}.fw-fan:before{content:"\e678"}.fw-faq:before{content:"\e62f"}.fw-file-browse:before{content:"\e633"}.fw-filter:before{content:"\e634"}.fw-folder-open:before{content:"\e70b"}.fw-folder:before{content:"\e62e"}.fw-fork-join:before{content:"\e720"}.fw-format:before{content:"\e6fa"}.fw-forum:before{content:"\e636"}.fw-function-invoke:before{content:"\e713"}.fw-function:before{content:"\e6fb"}.fw-gadget:before{content:"\e637"}.fw-geo-fence-inbound:before{content:"\e72e"}.fw-geo-fence-outbound:before{content:"\e72f"}.fw-github:before{content:"\e6d4"}.fw-globe:before{content:"\e697"}.fw-google-docs:before{content:"\e6d6"}.fw-google-drive:before{content:"\e6da"}.fw-google-plus:before{content:"\e6d9"}.fw-google-sheets:before{content:"\e6d7"}.fw-google-slides:before{content:"\e6d8"}.fw-google:before{content:"\e6d5"}.fw-grid:before{content:"\e638"}.fw-grip:before{content:"\e6b7"}.fw-group:before{content:"\e6af"}.fw-hardware:before{content:"\e6a9"}.fw-hdd:before{content:"\e639"}.fw-heart:before{content:"\e6c3"}.fw-hide:before{content:"\e6d2"}.fw-home:before{content:"\e63a"}.fw-hour-glass:before{content:"\e63b"}.fw-html:before{content:"\e69d"}.fw-http:before{content:"\e705"}.fw-image:before{content:"\e70a"}.fw-import:before{content:"\e63c"}.fw-incoming-call:before{content:"\e63d"}.fw-info:before{content:"\e63e"}.fw-instagram:before{content:"\e6db"}.fw-invitation:before{content:"\e63f"}.fw-invoke:before{content:"\e6ed"}.fw-is-connector:before{content:"\e6e5"}.fw-iterate:before{content:"\e71f"}.fw-jaggery:before{content:"\e640"}.fw-java-spring:before{content:"\e644"}.fw-java:before{content:"\e641"}.fw-javaee:before{content:"\e642"}.fw-javascript:before{content:"\e643"}.fw-jaxrs:before{content:"\e645"}.fw-jaxws:before{content:"\e6c7"}.fw-jquery:before{content:"\e646"}.fw-key:before{content:"\e647"}.fw-laptop:before{content:"\e648"}.fw-layout:before{content:"\e6bf"}.fw-ldap:before{content:"\e649"}.fw-left-arrow:before{content:"\e68a"}.fw-left:before{content:"\e686"}.fw-lifecycle:before{content:"\e64a"}.fw-light:before{content:"\e680"}.fw-linkedin:before{content:"\e6dc"}.fw-list-sort:before{content:"\e64d"}.fw-list:before{content:"\e64c"}.fw-loader:before{content:"\e6b4"}.fw-loader2:before{content:"\e6ba"}.fw-loader3:before{content:"\e6bb"}.fw-loader4:before{content:"\e6bc"}.fw-loader5:before{content:"\e6bd"}.fw-lock:before{content:"\e64e"}.fw-logical:before{content:"\e702"}.fw-mail:before{content:"\e64f"}.fw-main-function:before{content:"\e706"}.fw-map-location:before{content:"\e650"}.fw-menu:before{content:"\e651"}.fw-message:before{content:"\e635"}.fw-micro-services:before{content:"\e6ce"}.fw-dash:before,.fw-hyphen:before,.fw-minus:before{content:"\e616"}.fw-mobile:before{content:"\e652"}.fw-ms-document:before{content:"\e654"}.fw-mute:before{content:"\e655"}.fw-nodejs:before{content:"\e656"}.fw-notification:before{content:"\e60b"}.fw-organization:before{content:"\e6ac"}.fw-own:before{content:"\e6c8"}.fw-package:before{content:"\e6fd"}.fw-pages:before{content:"\e6c0"}.fw-paste:before{content:"\e658"}.fw-pdf:before{content:"\e659"}.fw-pending:before{content:"\e727"}.fw-php:before{content:"\e6c9"}.fw-pie-chart:before{content:"\e65a"}.fw-pinterest:before{content:"\e6dd"}.fw-policy:before{content:"\e67d"}.fw-polygon:before{content:"\e70d"}.fw-prototype:before{content:"\e6cc"}.fw-proxy:before{content:"\e699"}.fw-public:before{content:"\e6ad"}.fw-publish:before{content:"\e65c"}.fw-question:before{content:"\e6b0"}.fw-raspberry:before{content:"\e6aa"}.fw-redo:before{content:"\e65d"}.fw-refresh:before{content:"\e692"}.fw-register:before{content:"\e65e"}.fw-rename:before{content:"\e6fc"}.fw-reply:before{content:"\e714"}.fw-resource:before{content:"\e660"}.fw-rest-api:before{content:"\e661"}.fw-rest-service:before{content:"\e662"}.fw-resume:before{content:"\e71e"}.fw-retire:before{content:"\e6cd"}.fw-return:before{content:"\e715"}.fw-retweet:before{content:"\e6b9"}.fw-right-arrow:before{content:"\e68b"}.fw-right:before{content:"\e687"}.fw-ringing:before{content:"\e694"}.fw-rules:before{content:"\e664"}.fw-run:before{content:"\e708"}.fw-save:before{content:"\e665"}.fw-scep:before{content:"\e666"}.fw-schema:before{content:"\e667"}.fw-search:before{content:"\e668"}.fw-security-policy:before{content:"\e67e"}.fw-security:before{content:"\e669"}.fw-paper-rocket:before,.fw-send:before{content:"\e66a"}.fw-sequence:before{content:"\e66b"}.fw-server:before{content:"\e66c"}.fw-service-provider:before{content:"\e66e"}.fw-cogwheels:before,.fw-gears:before,.fw-service:before,.fw-sprockets:before{content:"\e66d"}.fw-cogwheel:before,.fw-gear:before,.fw-settings:before,.fw-sprocket:before{content:"\e66f"}.fw-share:before{content:"\e670"}.fw-shell:before{content:"\e730"}.fw-shortcut:before{content:"\e725"}.fw-sign-in:before{content:"\e671"}.fw-sign-out:before{content:"\e6b8"}.fw-skype:before{content:"\e6de"}.fw-slash:before{content:"\e6e1"}.fw-soap:before{content:"\e672"}.fw-sort-down:before{content:"\e663"}.fw-sort-up:before{content:"\e64b"}.fw-sort:before{content:"\e673"}.fw-speed-alert:before{content:"\e731"}.fw-square-outline:before{content:"\e6b2"}.fw-square:before{content:"\e6b1"}.fw-star:before{content:"\e674"}.fw-start:before{content:"\e718"}.fw-statistics:before{content:"\e675"}.fw-stepin:before{content:"\e719"}.fw-stepout:before{content:"\e71a"}.fw-stepover:before{content:"\e71b"}.fw-stop:before{content:"\e71c"}.fw-cart:before,.fw-store:before{content:"\e676"}.fw-struct:before{content:"\e716"}.fw-subscribe:before{content:"\e677"}.fw-success:before{content:"\e657"}.fw-swagger:before{content:"\e679"}.fw-sync:before{content:"\e6b3"}.fw-table:before{content:"\e6c4"}.fw-tag:before{content:"\e67a"}.fw-task:before{content:"\e67b"}.fw-text:before{content:"\e67c"}.fw-theme:before{content:"\e726"}.fw-throttling-policy:before{content:"\e67f"}.fw-throw:before{content:"\e722"}.fw-tiles:before{content:"\e681"}.fw-transaction:before{content:"\e72b"}.fw-try-catch:before{content:"\e703"}.fw-twitter:before{content:"\e6df"}.fw-type-converter:before{content:"\e6f3"}.fw-uncheck:before{content:"\e682"}.fw-undo:before{content:"\e683"}.fw-ungroup:before{content:"\e6b5"}.fw-unmute:before{content:"\e6ae"}.fw-up-arrow:before{content:"\e688"}.fw-up:before{content:"\e684"}.fw-upload:before{content:"\e68c"}.fw-uri:before{content:"\e68d"}.fw-usb-drive:before{content:"\e68e"}.fw-use:before{content:"\e6ca"}.fw-user:before{content:"\e68f"}.fw-variable:before{content:"\e6ee"}.fw-view:before{content:"\e691"}.fw-vpn:before{content:"\e603"}.fw-wadl:before{content:"\e6a1"}.fw-war:before{content:"\e69e"}.fw-warning:before{content:"\e693"}.fw-web-app:before{content:"\e696"}.fw-web-clip:before{content:"\e698"}.fw-web-service:before{content:"\e69a"}.fw-website:before{content:"\e69b"}.fw-wifi:before{content:"\e607"}.fw-windows:before{content:"\e605"}.fw-worker-invoke:before{content:"\e723"}.fw-worker-reply:before{content:"\e724"}.fw-worker:before{content:"\e6ef"}.fw-wsdl:before{content:"\e6a0"}.fw-wso2-logo:before{content:"\e6a7"}.fw-wso2:before{content:"\e6a8"}.fw-xacml:before{content:"\e69f"}.fw-xml:before{content:"\e69c"}.fw-xq:before{content:"\e6a2"}.fw-xsd:before{content:"\e6a3"}.fw-xslt:before{content:"\e6a4"}.fw-youtube:before{content:"\e6e0"}.fw-zoom-in:before{content:"\e6a5"}.fw-zoom-out:before{content:"\e6a6"} \ No newline at end of file From 3565e03c1b0cfaadbb2936597eb4fb319ea4c9c9 Mon Sep 17 00:00:00 2001 From: charitha Date: Wed, 17 Apr 2019 09:21:27 +0530 Subject: [PATCH 03/27] Fix test cases --- .../impl/DeviceManagementServiceImpl.java | 17 ++++--- .../impl/DeviceTypeManagementServiceImpl.java | 16 ++++--- .../impl/DeviceManagementServiceImplTest.java | 18 ++------ .../DeviceTypeManagementAdminServiceTest.java | 8 ++-- .../impl/DeviceTypeManagementServiceTest.java | 13 +++--- .../common/DeviceTypeNotFoundException.java | 44 +++++++++++++++++++ .../DeviceManagementProviderService.java | 2 +- .../DeviceManagementProviderServiceImpl.java | 5 ++- .../impl/DeviceManagementServiceImpl.java | 10 ++++- .../impl/DeviceTypeManagementServiceImpl.java | 12 ++++- .../impl/DeviceManagementServiceImplTest.java | 10 ++--- 11 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/DeviceTypeNotFoundException.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index 10aa8538fa..5c69f0bd4d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -25,6 +25,7 @@ import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; @@ -506,18 +507,22 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @PathParam("type") @Size(max = 45) String type, @PathParam("id") @Size(max = 45) String id, @HeaderParam("If-Modified-Since") String ifModifiedSince) { - List features; + List features = new ArrayList<>(); DeviceManagementProviderService dms; try { RequestValidationUtil.validateDeviceIdentifier(type, id); dms = DeviceMgtAPIUtils.getDeviceManagementService(); - FeatureManager fm = dms.getFeatureManager(type); - if (fm == null) { + FeatureManager fm; + try { + fm = dms.getFeatureManager(type); + } catch (DeviceTypeNotFoundException e) { return Response.status(Response.Status.NOT_FOUND).entity( - new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + - "registered with the given type '" + type + "'").build()).build(); + new ErrorResponse.ErrorResponseBuilder() + .setMessage("No device type found with name '" + type + "'").build()).build(); + } + if (fm != null) { + features = fm.getFeatures(); } - features = fm.getFeatures(); } catch (DeviceManagementException e) { String msg = "Error occurred while retrieving the list of features of '" + type + "' device, which " + "carries the id '" + id + "'"; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java index b20b3462de..e9129c4c6e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java @@ -38,6 +38,7 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; @@ -107,14 +108,19 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ @Path("/{type}/features") public Response getFeatures(@PathParam("type") @Size(max = 45) String type, @HeaderParam("If-Modified-Since") String ifModifiedSince) { - List features; + List features = new ArrayList<>(); DeviceManagementProviderService dms; try { dms = DeviceMgtAPIUtils.getDeviceManagementService(); - FeatureManager fm = dms.getFeatureManager(type); - if (fm == null) { - features = new ArrayList<>(); - } else { + FeatureManager fm; + try { + fm = dms.getFeatureManager(type); + } catch (DeviceTypeNotFoundException e) { + return Response.status(Response.Status.NOT_FOUND).entity( + new ErrorResponse.ErrorResponseBuilder() + .setMessage("No device type found with name '" + type + "'").build()).build(); + } + if (fm != null) { features = fm.getFeatures(); } } catch (DeviceManagementException e) { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java index c8549711fc..51aeaabde6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java @@ -34,6 +34,7 @@ import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; @@ -437,26 +438,15 @@ public class DeviceManagementServiceImplTest { Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); } - @Test(description = "Testing getting device features when feature manager is not registered for the device type") - public void testGetFeaturesOfDeviceWhenFeatureManagerIsNotRegistered() throws DeviceManagementException { - PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) - .toReturn(this.deviceManagementProviderService); - Mockito.when(this.deviceManagementProviderService.getFeatureManager(Mockito.anyString())).thenReturn(null); - Response response = this.deviceManagementService - .getFeaturesOfDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), null); - Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); - Mockito.reset(this.deviceManagementProviderService); - } - @Test(description = "Testing getting device features when unable to get the feature manager") - public void testGetFeaturesException() throws DeviceManagementException { + public void testGetFeaturesException() throws DeviceTypeNotFoundException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService.getFeatureManager(Mockito.anyString())) - .thenThrow(new DeviceManagementException()); + .thenThrow(new DeviceTypeNotFoundException()); Response response = this.deviceManagementService .getFeaturesOfDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), null); - Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); Mockito.reset(this.deviceManagementProviderService); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java index 0d275ea52d..1b8910507d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java @@ -171,7 +171,7 @@ public class DeviceTypeManagementAdminServiceTest { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceTypeGeneratorService")) .toReturn(this.deviceTypeGeneratorService); DeviceType deviceType = DeviceMgtAPITestHelper.getDummyDeviceType(TEST_DEVICE_TYPE, TEST_DEVICE_TYPE_ID); - Response response = this.deviceTypeManagementAdminService.updateDeviceType(deviceType); + Response response = this.deviceTypeManagementAdminService.updateDeviceType(TEST_DEVICE_TYPE, deviceType); Assert.assertNotNull(response, "The response should not be null"); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(), "The Response Status code should be 200."); @@ -185,7 +185,7 @@ public class DeviceTypeManagementAdminServiceTest { .toReturn(this.deviceTypeGeneratorService); Mockito.when(deviceManagementProviderService.getDeviceType(Mockito.anyString())).thenReturn(null); DeviceType deviceType = DeviceMgtAPITestHelper.getDummyDeviceType(TEST_DEVICE_TYPE, TEST_DEVICE_TYPE_ID); - Response response = this.deviceTypeManagementAdminService.updateDeviceType(deviceType); + Response response = this.deviceTypeManagementAdminService.updateDeviceType(TEST_DEVICE_TYPE, deviceType); Assert.assertNotNull(response, "The response should not be null"); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode(), "The Response Status code should be 400."); @@ -196,7 +196,7 @@ public class DeviceTypeManagementAdminServiceTest { public void testUpdateDeviceTypeWithNullDeviceType() { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); - Response response = this.deviceTypeManagementAdminService.updateDeviceType(null); + Response response = this.deviceTypeManagementAdminService.updateDeviceType(TEST_DEVICE_TYPE, null); Assert.assertNotNull(response, "The response should not be null"); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode(), "The Response Status code should be 400."); @@ -210,7 +210,7 @@ public class DeviceTypeManagementAdminServiceTest { Mockito.when(this.deviceManagementProviderService.getDeviceType(Mockito.anyString())) .thenThrow(new DeviceManagementException()); DeviceType deviceType = DeviceMgtAPITestHelper.getDummyDeviceType(TEST_DEVICE_TYPE, TEST_DEVICE_TYPE_ID); - Response response = this.deviceTypeManagementAdminService.updateDeviceType(deviceType); + Response response = this.deviceTypeManagementAdminService.updateDeviceType(TEST_DEVICE_TYPE, deviceType); Assert.assertNotNull(response, "The response should not be null"); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "The Response Status code should be 500."); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java index 9629afb07a..7143108184 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java @@ -89,7 +89,7 @@ public class DeviceTypeManagementServiceTest { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService.getDeviceTypes()).thenThrow(new DeviceManagementException()); - Response response = this.deviceTypeManagementService.getDeviceTypes(); + Response response = this.deviceTypeManagementService.getDeviceTypes(MODIFIED_SINCE); Assert.assertNotNull(response, "The response object is null."); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "The response status should be 500."); @@ -100,7 +100,7 @@ public class DeviceTypeManagementServiceTest { public void testExistingDeviceTypesModifiedError() throws Exception { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); - Mockito.when(this.deviceManagementProviderService.getAvailableDeviceTypes()).thenThrow(new + Mockito.when(this.deviceManagementProviderService.getDeviceTypes()).thenThrow(new DeviceManagementException()); Response response = this.deviceTypeManagementService.getDeviceTypes(MODIFIED_SINCE); Assert.assertNotNull(response, "The response object is null."); @@ -142,8 +142,9 @@ public class DeviceTypeManagementServiceTest { Mockito.when(this.deviceManagementProviderService.getFeatureManager(Mockito.anyString())).thenReturn(null); Response response = this.deviceTypeManagementService.getFeatures(TEST_DEVICE_TYPE, MODIFIED_SINCE); Assert.assertNotNull(response, "The response object is null."); - Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode(), - "The response status should be 404."); + Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(), + "The response status should be 200."); + Assert.assertEquals(response.getEntity().toString(), "[]", "The response should be []."); Mockito.reset(deviceManagementProviderService); } @@ -151,7 +152,7 @@ public class DeviceTypeManagementServiceTest { public void testGetDeviceTypes() throws Exception { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); - Response response = this.deviceTypeManagementService.getDeviceTypes(); + Response response = this.deviceTypeManagementService.getDeviceTypes(MODIFIED_SINCE); Assert.assertNotNull(response, "The response object is null."); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(), "The response status should be 200."); @@ -163,7 +164,7 @@ public class DeviceTypeManagementServiceTest { .toReturn(this.deviceManagementProviderService); List deviceTypes = DeviceMgtAPITestHelper.getDummyDeviceTypeList(5); Mockito.when(this.deviceManagementProviderService.getDeviceTypes()).thenReturn(deviceTypes); - Response response = this.deviceTypeManagementService.getDeviceTypes(); + Response response = this.deviceTypeManagementService.getDeviceTypes(MODIFIED_SINCE); Assert.assertNotNull(response, "The response object is null."); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(), "The response state should be 200"); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/DeviceTypeNotFoundException.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/DeviceTypeNotFoundException.java new file mode 100644 index 0000000000..d8034cc8cf --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/DeviceTypeNotFoundException.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. 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.common; + +public class DeviceTypeNotFoundException extends Exception { + + private static final long serialVersionUID = 3821589758650454161L; + + public DeviceTypeNotFoundException(String msg, Exception nestedEx) { + super(msg, nestedEx); + } + + public DeviceTypeNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public DeviceTypeNotFoundException(String msg) { + super(msg); + } + + public DeviceTypeNotFoundException() { + super(); + } + + public DeviceTypeNotFoundException(Throwable cause) { + super(cause); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index 5e7658ae71..1c108fbb74 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -486,7 +486,7 @@ public interface DeviceManagementProviderService { void sendRegistrationEmail(EmailMetaInfo metaInfo) throws DeviceManagementException, ConfigurationManagementException; - FeatureManager getFeatureManager(String deviceType) throws DeviceManagementException; + FeatureManager getFeatureManager(String deviceType) throws DeviceTypeNotFoundException; /** * Proxy method to get the tenant configuration of a given platform. diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index fac5c6faa5..c579623d73 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -39,6 +39,7 @@ import org.wso2.carbon.device.mgt.common.DeviceManager; import org.wso2.carbon.device.mgt.common.DeviceNotFoundException; import org.wso2.carbon.device.mgt.common.DeviceNotification; import org.wso2.carbon.device.mgt.common.DevicePropertyNotification; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.InitialOperationConfig; @@ -171,14 +172,14 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public FeatureManager getFeatureManager(String deviceType) throws DeviceManagementException { + public FeatureManager getFeatureManager(String deviceType) throws DeviceTypeNotFoundException { DeviceManager deviceManager = this.getDeviceManager(deviceType); if (deviceManager == null) { if (log.isDebugEnabled()) { log.debug("Device Manager associated with the device type '" + deviceType + "' is null. " + "Therefore, not attempting method 'getFeatureManager'"); } - return null; + throw new DeviceTypeNotFoundException("Device type '" + deviceType + "' not found."); } return deviceManager.getFeatureManager(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index d6269cc7c8..a57da167bd 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -26,6 +26,7 @@ import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; @@ -499,7 +500,14 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { try { RequestValidationUtil.validateDeviceIdentifier(type, id); dms = DeviceMgtAPIUtils.getDeviceManagementService(); - FeatureManager fm = dms.getFeatureManager(type); + FeatureManager fm; + try { + fm = dms.getFeatureManager(type); + } catch (DeviceTypeNotFoundException e) { + return Response.status(Response.Status.NOT_FOUND).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + + "registered with the given type '" + type + "'").build()).build(); + } if (fm == null) { return Response.status(Response.Status.NOT_FOUND).entity( new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java index 1fb5c0c37a..fa812a775e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceImpl.java @@ -22,6 +22,7 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationConfig; @@ -76,11 +77,18 @@ public class DeviceTypeManagementServiceImpl implements DeviceTypeManagementServ DeviceManagementProviderService dms; try { dms = DeviceMgtAPIUtils.getDeviceManagementService(); - FeatureManager fm = dms.getFeatureManager(type); + FeatureManager fm; + try { + fm = dms.getFeatureManager(type); + } catch (DeviceTypeNotFoundException e) { + return Response.status(Response.Status.NOT_FOUND).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + + "registered with the given type '" + type + "'").build()).build(); + } if (fm == null) { return Response.status(Response.Status.NOT_FOUND).entity( new ErrorResponse.ErrorResponseBuilder().setMessage("No feature manager is " + - "registered with the given type '" + type + "'").build()).build(); + "registered with the given type '" + type + "'").build()).build(); } features = fm.getFeatures(); } catch (DeviceManagementException e) { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java index e1935904ae..c1732254aa 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.v09.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java @@ -31,9 +31,9 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; import org.wso2.carbon.context.CarbonContext; -import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; @@ -437,7 +437,7 @@ public class DeviceManagementServiceImplTest { } @Test(description = "Testing getting device features when feature manager is not registered for the device type") - public void testGetFeaturesOfDeviceWhenFeatureManagerIsNotRegistered() throws DeviceManagementException { + public void testGetFeaturesOfDeviceWhenFeatureManagerIsNotRegistered() throws DeviceTypeNotFoundException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService.getFeatureManager(Mockito.anyString())).thenReturn(null); @@ -448,14 +448,14 @@ public class DeviceManagementServiceImplTest { } @Test(description = "Testing getting device features when unable to get the feature manager") - public void testGetFeaturesException() throws DeviceManagementException { + public void testGetFeaturesException() throws DeviceTypeNotFoundException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService.getFeatureManager(Mockito.anyString())) - .thenThrow(new DeviceManagementException()); + .thenThrow(new DeviceTypeNotFoundException()); Response response = this.deviceManagementService .getFeaturesOfDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), null); - Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); Mockito.reset(this.deviceManagementProviderService); } From ea4954ba9d49eda7833f351b42f4a8f69cb61bf1 Mon Sep 17 00:00:00 2001 From: charitha Date: Sun, 21 Apr 2019 17:03:47 +0530 Subject: [PATCH 04/27] Fix policy UI --- .../jaggeryapps/devicemgt/api/data-tables-invoker-api.jag | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/data-tables-invoker-api.jag b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/data-tables-invoker-api.jag index 146abcf0d0..4271f463bd 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/data-tables-invoker-api.jag +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/api/data-tables-invoker-api.jag @@ -59,10 +59,10 @@ if (uriMatcher.match("/{context}/api/data-tables/invoker/filters")) { result.deviceTypes = []; var deviceTypesRes = deviceModule.getDeviceTypes(); if (deviceTypesRes.status === "success") { - var deviceTypes = deviceTypesRes["content"]["deviceTypes"]; + var deviceTypes = deviceTypesRes["content"]; for (i = 0; i < deviceTypes.length; i++) { - var deviceTypeName = deviceTypes[i]; - var deviceTypeLabel = deviceTypeName; + var deviceTypeName = deviceTypes[i].name; + var deviceTypeLabel = deviceTypeName.charAt(0).toUpperCase() + deviceTypeName.slice(1); var configs = utility.getDeviceTypeConfig(deviceTypeLabel); if (configs) { if (configs[DTYPE_CONF_DEVICE_TYPE_KEY][DTYPE_CONF_DEVICE_TYPE_LABEL_KEY]) { From 893328c0ca4bbe57e22a6c49441526efd4b61faf Mon Sep 17 00:00:00 2001 From: charitha Date: Thu, 25 Apr 2019 14:27:35 +0530 Subject: [PATCH 05/27] Fix build failure --- .../device/mgt/core/service/DeviceManagementProviderService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index 7d3c0fdf52..3fa92a1aed 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.core.service; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.InvalidDeviceException; From 13511a79c42fb7863b32b9d401f80a0dc1f1928c Mon Sep 17 00:00:00 2001 From: charitha Date: Mon, 6 May 2019 13:47:56 +0530 Subject: [PATCH 06/27] Fix log issue in test cases --- .../mgt/jaxrs/service/impl/ActivityProviderServiceImplTest.java | 2 +- .../mgt/jaxrs/service/impl/ConfigurationServiceImplTest.java | 2 +- .../device/mgt/jaxrs/service/impl/DeviceAgentServiceTest.java | 2 +- .../mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java | 2 +- .../service/impl/DeviceTypeManagementAdminServiceTest.java | 2 +- .../mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java | 2 +- .../mgt/jaxrs/service/impl/GeoLocationBasedServiceImplTest.java | 2 ++ .../mgt/jaxrs/service/impl/GroupManagementServiceImplTest.java | 2 +- .../service/impl/NotificationManagementServiceImplTest.java | 2 +- .../mgt/jaxrs/service/impl/UserManagementServiceImplTest.java | 2 +- 10 files changed, 11 insertions(+), 9 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ActivityProviderServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ActivityProviderServiceImplTest.java index 0db0ac07b7..657dc4de0d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ActivityProviderServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ActivityProviderServiceImplTest.java @@ -55,7 +55,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This is a test class for {@link ActivityProviderServiceImpl}. */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({ "org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext", "org.wso2.carbon.context.PrivilegedCarbonContext" }) @PrepareForTest({ DeviceMgtAPIUtils.class, PolicyManagerUtil.class, PrivilegedCarbonContext.class }) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ConfigurationServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ConfigurationServiceImplTest.java index 5a4b0cd13b..ed8478bc11 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ConfigurationServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ConfigurationServiceImplTest.java @@ -44,7 +44,7 @@ import java.util.List; /** * This is a test class for {@link ConfigurationServiceImpl}. */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext"}) @PrepareForTest({DeviceMgtAPIUtils.class, PolicyManagerUtil.class}) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceAgentServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceAgentServiceTest.java index efd573b11f..44c23440d9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceAgentServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceAgentServiceTest.java @@ -75,7 +75,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This class holds the unit tests for the class {@link DeviceAgentServiceImpl} */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext", "org.wso2.carbon.context.internal.CarbonContextDataHolder"}) @PrepareForTest({DeviceMgtAPIUtils.class, DeviceManagementProviderService.class, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java index 51aeaabde6..27e84c7fc9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java @@ -68,7 +68,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This class includes unit tests for testing the functionality of {@link DeviceManagementServiceImpl} */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext"}) @PrepareForTest({DeviceMgtAPIUtils.class, MultitenantUtils.class, CarbonContext.class}) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java index 1b8910507d..9c129cd593 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java @@ -48,7 +48,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This class holds the unit tests for the class {@link DeviceTypeManagementAdminService} */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils"}) @PrepareForTest({DeviceMgtAPIUtils.class, DeviceManagementProviderService.class}) public class DeviceTypeManagementAdminServiceTest { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java index 7143108184..fa320b5b5f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementServiceTest.java @@ -48,7 +48,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This class holds the unit tests for the class {@link DeviceTypeManagementService} */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils"}) @PrepareForTest({DeviceMgtAPIUtils.class, DeviceManagementProviderService.class}) public class DeviceTypeManagementServiceTest { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImplTest.java index b655b1095e..befc2b47d6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImplTest.java @@ -1,6 +1,7 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl; import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -15,6 +16,7 @@ import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.List; +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) public class GeoLocationBasedServiceImplTest { private DeviceManagementProviderService deviceManagementProviderService; private PrivilegedCarbonContext context; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GroupManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GroupManagementServiceImplTest.java index d3c42b794a..9a4829cb56 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GroupManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GroupManagementServiceImplTest.java @@ -54,7 +54,7 @@ import java.util.List; /** * This is a test case for {@link GroupManagementServiceImpl}. */ -@PowerMockIgnore({"javax.ws.rs.*", "javax.xml.parsers"}) +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*", "javax.xml.parsers"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.PrivilegedCarbonContext"}) @PrepareForTest({DeviceMgtAPIUtils.class, CarbonContext.class}) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/NotificationManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/NotificationManagementServiceImplTest.java index 92e321745f..75a7f3cd1c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/NotificationManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/NotificationManagementServiceImplTest.java @@ -46,7 +46,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This is a test class for {@link NotificationManagementServiceImpl}. */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext"}) @PrepareForTest({DeviceMgtAPIUtils.class, MultitenantUtils.class, CarbonContext.class}) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/UserManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/UserManagementServiceImplTest.java index bcee738b6e..d6984503cb 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/UserManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/UserManagementServiceImplTest.java @@ -58,7 +58,7 @@ import static org.mockito.MockitoAnnotations.initMocks; /** * This is a test case for {@link UserManagementService}. */ -@PowerMockIgnore("javax.ws.rs.*") +@PowerMockIgnore({"javax.ws.rs.*", "org.apache.log4j.*"}) @SuppressStaticInitializationFor({"org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils", "org.wso2.carbon.context.CarbonContext"}) @PrepareForTest({DeviceMgtAPIUtils.class, MultitenantUtils.class, CarbonContext.class}) From 3b905f450a73c4ece361f97be4ce6993221d1eb2 Mon Sep 17 00:00:00 2001 From: charitha Date: Mon, 17 Jun 2019 09:36:54 +0530 Subject: [PATCH 07/27] Fix https://gitlab.com/entgra/product-iots/issues/109 --- .../src/main/resources/dbscripts/cdm/h2.sql | 4 ++-- .../src/main/resources/dbscripts/cdm/mssql.sql | 4 ++-- .../src/main/resources/dbscripts/cdm/mysql.sql | 4 ++-- .../src/main/resources/dbscripts/cdm/oracle.sql | 4 ++-- .../src/main/resources/dbscripts/cdm/postgresql.sql | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql index 6e4989721a..95d54b8da1 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql @@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS DM_GROUP ( ID INTEGER AUTO_INCREMENT NOT NULL, GROUP_NAME VARCHAR(100) DEFAULT NULL, DESCRIPTION TEXT DEFAULT NULL, - OWNER VARCHAR(45) DEFAULT NULL, + OWNER VARCHAR(255) DEFAULT NULL, TENANT_ID INTEGER DEFAULT 0, PRIMARY KEY (ID) ); @@ -110,7 +110,7 @@ CREATE TABLE IF NOT EXISTS DM_PROFILE_OPERATION ( CREATE TABLE IF NOT EXISTS DM_ENROLMENT ( ID INTEGER AUTO_INCREMENT NOT NULL, DEVICE_ID INTEGER NOT NULL, - OWNER VARCHAR(50) NOT NULL, + OWNER VARCHAR(255) NOT NULL, OWNERSHIP VARCHAR(45) DEFAULT NULL, STATUS VARCHAR(50) NULL, DATE_OF_ENROLMENT TIMESTAMP DEFAULT NULL, diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql index 8d6bb0fb7d..eb423d96bf 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql @@ -20,7 +20,7 @@ IF NOT EXISTS(SELECT * ID INTEGER IDENTITY (1, 1) NOT NULL, GROUP_NAME VARCHAR(100) DEFAULT NULL, DESCRIPTION VARCHAR(MAX) DEFAULT NULL, - OWNER VARCHAR(45) DEFAULT NULL, + OWNER VARCHAR(255) DEFAULT NULL, TENANT_ID INTEGER DEFAULT 0, PRIMARY KEY (ID) ); @@ -140,7 +140,7 @@ IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[D CREATE TABLE DM_ENROLMENT ( ID INTEGER IDENTITY(1,1) NOT NULL, DEVICE_ID INTEGER NOT NULL, - OWNER VARCHAR(50) NOT NULL, + OWNER VARCHAR(255) NOT NULL, OWNERSHIP VARCHAR(45) DEFAULT NULL, STATUS VARCHAR(50) NULL, DATE_OF_ENROLMENT DATETIME2 DEFAULT NULL, diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql index 0ff005b6b9..2363beb5e7 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS DM_GROUP ( ID INTEGER AUTO_INCREMENT NOT NULL, GROUP_NAME VARCHAR(100) DEFAULT NULL, DESCRIPTION TEXT DEFAULT NULL, - OWNER VARCHAR(45) DEFAULT NULL, + OWNER VARCHAR(255) DEFAULT NULL, TENANT_ID INTEGER DEFAULT 0, PRIMARY KEY (ID) ) @@ -125,7 +125,7 @@ CREATE TABLE IF NOT EXISTS DM_PROFILE_OPERATION ( CREATE TABLE IF NOT EXISTS DM_ENROLMENT ( ID INTEGER AUTO_INCREMENT NOT NULL, DEVICE_ID INTEGER NOT NULL, - OWNER VARCHAR(50) NOT NULL, + OWNER VARCHAR(255) NOT NULL, OWNERSHIP VARCHAR(45) DEFAULT NULL, STATUS VARCHAR(50) NULL, DATE_OF_ENROLMENT TIMESTAMP NULL DEFAULT NULL, diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql index 9ebdcf5615..f1d73729b0 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql @@ -27,7 +27,7 @@ CREATE TABLE DM_GROUP ( ID NUMBER(10) NOT NULL, DESCRIPTION CLOB DEFAULT NULL, GROUP_NAME VARCHAR2(100) DEFAULT NULL, - OWNER VARCHAR2(45) DEFAULT NULL, + OWNER VARCHAR2(255) DEFAULT NULL, TENANT_ID NUMBER(10) DEFAULT 0, CONSTRAINT PK_DM_GROUP PRIMARY KEY (ID) ) @@ -201,7 +201,7 @@ CREATE TABLE DM_PROFILE_OPERATION ( CREATE TABLE DM_ENROLMENT ( ID NUMBER(10) NOT NULL, DEVICE_ID NUMBER(10) NOT NULL, - OWNER VARCHAR2(50) NOT NULL, + OWNER VARCHAR2(255) NOT NULL, OWNERSHIP VARCHAR2(45) DEFAULT NULL, STATUS VARCHAR2(50) NULL, DATE_OF_ENROLMENT TIMESTAMP(0) DEFAULT NULL, diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql index 4ef06be29c..e401f099f7 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql @@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS DM_GROUP ( ID BIGSERIAL NOT NULL PRIMARY KEY, GROUP_NAME VARCHAR(100) DEFAULT NULL, DESCRIPTION TEXT DEFAULT NULL, - OWNER VARCHAR(45) DEFAULT NULL, + OWNER VARCHAR(255) DEFAULT NULL, TENANT_ID INTEGER DEFAULT 0 ); @@ -108,7 +108,7 @@ CREATE TABLE IF NOT EXISTS DM_PROFILE_OPERATION ( CREATE TABLE IF NOT EXISTS DM_ENROLMENT ( ID BIGSERIAL NOT NULL PRIMARY KEY, DEVICE_ID INTEGER NOT NULL, - OWNER VARCHAR(50) NOT NULL, + OWNER VARCHAR(255) NOT NULL, OWNERSHIP VARCHAR(45) DEFAULT NULL, STATUS VARCHAR(50) NULL, DATE_OF_ENROLMENT TIMESTAMP NULL DEFAULT NULL, From bb82eb723605e008b95db0b691a84b7831a93366 Mon Sep 17 00:00:00 2001 From: charitha Date: Tue, 13 Aug 2019 00:08:58 +0530 Subject: [PATCH 08/27] Fix issue in IoT device type loading --- .../impl/admin/DeviceTypeManagementAdminServiceImpl.java | 8 ++++++-- .../devicemgt/app/modules/business-controllers/device.js | 9 --------- .../app/pages/cdmf.page.devicetype.edit/edit.js | 2 +- .../cdmf.page.devicetype.edit/public/js/bottomJs.js | 2 +- .../device-view.js | 2 +- .../cdmf.unit.default.device.type.type-view/type-view.js | 2 +- 6 files changed, 10 insertions(+), 15 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index d7f659871d..02c807df55 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -137,7 +137,8 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @PUT - public Response updateDeviceType(String type, DeviceType deviceType) { + @Path("/{type}") + public Response updateDeviceType(@PathParam("type") String type, DeviceType deviceType) { if (deviceType != null && deviceType.getDeviceTypeMetaDefinition() != null) { if (deviceType.getName() == null || !deviceType.getName().equals(type)) { return Response.status(Response.Status.BAD_REQUEST).entity("Type name mismatch. Expected: '" + type + @@ -163,7 +164,10 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } @Override - public Response addDeviceTypePlatformConfig(String type, PlatformConfiguration platformConfiguration) { + @POST + @Path("/{type}/configs") + public Response addDeviceTypePlatformConfig(@PathParam("type") String type, + PlatformConfiguration platformConfiguration) { boolean isSaved; if (platformConfiguration.getType() == null || !platformConfiguration.getType().equals(type)) { return Response.status(Response.Status.BAD_REQUEST).entity("Type name mismatch. Expected: '" + type + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js index ca8fa6dbd8..c39e797bc2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/business-controllers/device.js @@ -327,15 +327,6 @@ deviceModule = function () { return response; }; - publicMethods.getDeviceTypesConfig = function () { - var url = devicemgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"] + "/device-types/config"; - var response = privateMethods.callBackend(url, constants["HTTP_GET"]); - if (response.status == "success") { - response.content = parse(response.content); - } - return response; - }; - /* @Updated */ diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/edit.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/edit.js index 94284ac016..692f692302 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/edit.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/edit.js @@ -35,7 +35,7 @@ function onRequest(context) { var deviceType = request.getParameter("type"); var serviceInvokers = require("/app/modules/oauth/token-protected-service-invokers.js")["invokers"]; var restAPIEndpoint = deviceMgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"] - + "/device-types/config/" + deviceType; + + "/device-types/" + deviceType; displayData.name = deviceType; serviceInvokers.XMLHttp.get( restAPIEndpoint, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/public/js/bottomJs.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/public/js/bottomJs.js index 3fd2548a6f..320d630efe 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/public/js/bottomJs.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devicetype.edit/public/js/bottomJs.js @@ -210,7 +210,7 @@ $(document).ready(function () { }); deviceType.deviceTypeMetaDefinition.features = features; - var addRoleAPI = apiBasePath + "/admin/device-types"; + var addRoleAPI = apiBasePath + "/admin/device-types/" + deviceType.name; invokerUtil.put( addRoleAPI, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.device-view/device-view.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.device-view/device-view.js index cf716ef35c..a431c66a71 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.device-view/device-view.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.device-view/device-view.js @@ -42,7 +42,7 @@ function onRequest(context) { var displayData = {}; var restAPIEndpoint = devicemgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"] - + "/device-types/config/" + deviceType; + + "/device-types/" + deviceType; displayData.deviceType = deviceType; displayData.tenantDomain = tenantDomain; serviceInvokers.XMLHttp.get( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/type-view.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/type-view.js index 0f3563bad1..0f24173632 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/type-view.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.default.device.type.type-view/type-view.js @@ -32,7 +32,7 @@ function onRequest(context) { return opts.inverse(this); }); var restAPIEndpoint = deviceMgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"] - + "/device-types/config/" + deviceType; + + "/device-types/" + deviceType; displayData.deviceType = deviceType; displayData.tenantDomain = tenantDomain; serviceInvokers.XMLHttp.get( From 0d0daa5b8b56bc352155233636f22da6dfd64ce5 Mon Sep 17 00:00:00 2001 From: charitha Date: Thu, 15 Aug 2019 14:09:37 +0530 Subject: [PATCH 09/27] Fix CN extraction issue --- .../mgt/core/impl/CertificateGenerator.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java index 71ce11b6b1..b25837154f 100755 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java @@ -324,9 +324,14 @@ public class CertificateGenerator { KeyStoreReader keyStoreReader = new KeyStoreReader(); if (distinguishedName != null && !distinguishedName.isEmpty()) { if (distinguishedName.contains("/CN=")) { - String[] dnSplits = distinguishedName.split("/CN="); - String commonNameExtracted = dnSplits[dnSplits.length - 1]; - lookUpCertificate = keyStoreReader.getCertificateBySerial(commonNameExtracted); + String[] dnSplits = distinguishedName.split("/"); + for (String dnPart : dnSplits) { + if (dnPart.contains("CN=")) { + String commonNameExtracted = dnPart.replace("CN=", ""); + lookUpCertificate = keyStoreReader.getCertificateBySerial(commonNameExtracted); + break; + } + } } else { LdapName ldapName; try { @@ -711,4 +716,4 @@ public class CertificateGenerator { return generateCertificateFromCSR(privateKeyCA, certificationRequest, certCA.getIssuerX500Principal().getName()); } -} \ No newline at end of file +} From 18218a351c4e72b92008abd03bd8802d1aeba1b5 Mon Sep 17 00:00:00 2001 From: Ace Date: Thu, 15 Aug 2019 15:12:42 +0530 Subject: [PATCH 10/27] Fixing issues with searching devices with groupID as a param --- .../carbon/device/mgt/core/dao/DeviceDAO.java | 11 ++ .../dao/impl/device/GenericDeviceDAOImpl.java | 131 ++++++++++++++++++ .../dao/impl/device/OracleDeviceDAOImpl.java | 131 ++++++++++++++++++ .../impl/device/PostgreSQLDeviceDAOImpl.java | 130 +++++++++++++++++ .../impl/device/SQLServerDeviceDAOImpl.java | 130 +++++++++++++++++ .../DeviceManagementProviderServiceImpl.java | 6 +- .../cdmf.page.devices/public/js/listing.js | 5 +- .../dataTables.extended.serversidepaging.js | 3 + 8 files changed, 544 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index 5ea2a87b5b..6cb16016e6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -277,6 +277,17 @@ public interface DeviceDAO { */ List getDevices(PaginationRequest request, int tenantId) throws DeviceManagementDAOException; + + /** + * This method is used to search for devices within a specific group. + * + * @param request PaginationRequest object holding the data for pagination + * @param tenantId tenant id. + * @return returns paginated list of devices. + * @throws DeviceManagementDAOException + */ + List searchDevicesInGroup(PaginationRequest request, int tenantId) throws DeviceManagementDAOException; + /** * This method is used to retrieve all the devices of a given tenant and device type. * diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java index 872ea7c285..8f38bc9d73 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java @@ -153,6 +153,137 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + + @Override + public List searchDevicesInGroup(PaginationRequest request, int tenantId) + throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List devices = null; + + int groupId = request.getGroupId(); + String deviceType = request.getDeviceType(); + boolean isDeviceTypeProvided = false; + String deviceName = request.getDeviceName(); + boolean isDeviceNameProvided = false; + String owner = request.getOwner(); + boolean isOwnerProvided = false; + String ownerPattern = request.getOwnerPattern(); + boolean isOwnerPatternProvided = false; + String ownership = request.getOwnership(); + boolean isOwnershipProvided = false; + String status = request.getStatus(); + boolean isStatusProvided = false; + Date since = request.getSince(); + boolean isSinceProvided = false; + + try { + conn = this.getConnection(); + String sql = "SELECT d1.DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.DATE_OF_LAST_UPDATE, " + + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, " + + "(SELECT gd.DEVICE_ID, gd.DESCRIPTION, gd.NAME, gd.DEVICE_IDENTIFICATION, t.NAME AS DEVICE_TYPE " + + "FROM (SELECT d.ID AS DEVICE_ID, d.DESCRIPTION, d.NAME, d.DEVICE_IDENTIFICATION, d.DEVICE_TYPE_ID " + + "FROM DM_DEVICE d, (SELECT dgm.DEVICE_ID FROM DM_DEVICE_GROUP_MAP dgm WHERE dgm.GROUP_ID = ?) dgm1 WHERE" + + " d.ID = dgm1.DEVICE_ID AND d.TENANT_ID = ?"; + + + //Add the query for device-name + if (deviceName != null && !deviceName.isEmpty()) { + sql = sql + " AND d.NAME LIKE ?"; + isDeviceNameProvided = true; + } + + sql = sql + ") gd, DM_DEVICE_TYPE t"; + + if (since != null) { + sql = sql + ", DM_DEVICE_DETAIL dt"; + isSinceProvided = true; + } + + sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID"; + + //Add query for last updated timestamp + if (isSinceProvided) { + sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?"; + } + + //Add the query for device-type + if (deviceType != null && !deviceType.isEmpty()) { + sql = sql + " AND t.NAME = ?"; + isDeviceTypeProvided = true; + } + + sql = sql + " ) d1 WHERE d1.DEVICE_ID = e.DEVICE_ID AND TENANT_ID = ? "; + + //Add the query for ownership + if (ownership != null && !ownership.isEmpty()) { + sql = sql + " AND e.OWNERSHIP = ?"; + isOwnershipProvided = true; + } + //Add the query for owner + if (owner != null && !owner.isEmpty()) { + sql = sql + " AND e.OWNER = ?"; + isOwnerProvided = true; + } else if (ownerPattern != null && !ownerPattern.isEmpty()) { + sql = sql + " AND e.OWNER LIKE ?"; + isOwnerPatternProvided = true; + } + //Add the query for status + if (status != null && !status.isEmpty()) { + sql = sql + " AND e.STATUS = ?"; + isStatusProvided = true; + } + + sql = sql + " LIMIT ?,?"; + + stmt = conn.prepareStatement(sql); + + stmt.setInt(1, groupId); + stmt.setInt(2, tenantId); + + int paramIdx = 3; + if (isDeviceNameProvided) { + stmt.setString(paramIdx++, deviceName + "%"); + } + if (isSinceProvided) { + stmt.setLong(paramIdx++, since.getTime()); + } + if (isDeviceTypeProvided) { + stmt.setString(paramIdx++, deviceType); + } + + stmt.setInt(paramIdx++, tenantId); + if (isOwnershipProvided) { + stmt.setString(paramIdx++, ownership); + } + if (isOwnerProvided) { + stmt.setString(paramIdx++, owner); + } else if (isOwnerPatternProvided) { + stmt.setString(paramIdx++, ownerPattern + "%"); + } + if (isStatusProvided) { + stmt.setString(paramIdx++, status); + } + stmt.setInt(paramIdx++, request.getStartIndex()); + stmt.setInt(paramIdx, request.getRowCount()); + + rs = stmt.executeQuery(); + devices = new ArrayList<>(); + while (rs.next()) { + Device device = DeviceManagementDAOUtil.loadDevice(rs); + devices.add(device); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred while retrieving information of" + + " devices belonging to group : " + groupId, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return devices; + } + @Override public List getDevicesOfUser(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java index 33875fc9c7..2d568fed7e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java @@ -159,6 +159,137 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public List searchDevicesInGroup(PaginationRequest request, int tenantId) + throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List devices = null; + + int groupId = request.getGroupId(); + String deviceType = request.getDeviceType(); + boolean isDeviceTypeProvided = false; + String deviceName = request.getDeviceName(); + boolean isDeviceNameProvided = false; + String owner = request.getOwner(); + boolean isOwnerProvided = false; + String ownerPattern = request.getOwnerPattern(); + boolean isOwnerPatternProvided = false; + String ownership = request.getOwnership(); + boolean isOwnershipProvided = false; + String status = request.getStatus(); + boolean isStatusProvided = false; + Date since = request.getSince(); + boolean isSinceProvided = false; + + try { + conn = this.getConnection(); + String sql = "SELECT d1.DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.DATE_OF_LAST_UPDATE, " + + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, " + + "(SELECT gd.DEVICE_ID, gd.DESCRIPTION, gd.NAME, gd.DEVICE_IDENTIFICATION, t.NAME AS DEVICE_TYPE " + + "FROM (SELECT d.ID AS DEVICE_ID, d.DESCRIPTION, d.NAME, d.DEVICE_IDENTIFICATION, d.DEVICE_TYPE_ID " + + "FROM DM_DEVICE d, (SELECT dgm.DEVICE_ID FROM DM_DEVICE_GROUP_MAP dgm WHERE dgm.GROUP_ID = ?) dgm1 WHERE" + + " d.ID = dgm1.DEVICE_ID AND d.TENANT_ID = ?"; + + + //Add the query for device-name + if (deviceName != null && !deviceName.isEmpty()) { + sql = sql + " AND d.NAME LIKE ?"; + isDeviceNameProvided = true; + } + + sql = sql + ") gd, DM_DEVICE_TYPE t"; + + if (since != null) { + sql = sql + ", DM_DEVICE_DETAIL dt"; + isSinceProvided = true; + } + + sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID"; + + //Add query for last updated timestamp + if (isSinceProvided) { + sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?"; + } + + //Add the query for device-type + if (deviceType != null && !deviceType.isEmpty()) { + sql = sql + " AND t.NAME = ?"; + isDeviceTypeProvided = true; + } + + sql = sql + " ) d1 WHERE d1.DEVICE_ID = e.DEVICE_ID AND TENANT_ID = ? "; + + //Add the query for ownership + if (ownership != null && !ownership.isEmpty()) { + sql = sql + " AND e.OWNERSHIP = ?"; + isOwnershipProvided = true; + } + //Add the query for owner + if (owner != null && !owner.isEmpty()) { + sql = sql + " AND e.OWNER = ?"; + isOwnerProvided = true; + } else if (ownerPattern != null && !ownerPattern.isEmpty()) { + sql = sql + " AND e.OWNER LIKE ?"; + isOwnerPatternProvided = true; + } + //Add the query for status + if (status != null && !status.isEmpty()) { + sql = sql + " AND e.STATUS = ?"; + isStatusProvided = true; + } + + sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + + stmt = conn.prepareStatement(sql); + + stmt.setInt(1, groupId); + stmt.setInt(2, tenantId); + + int paramIdx = 3; + if (isDeviceNameProvided) { + stmt.setString(paramIdx++, deviceName + "%"); + } + if (isSinceProvided) { + stmt.setLong(paramIdx++, since.getTime()); + } + if (isDeviceTypeProvided) { + stmt.setString(paramIdx++, deviceType); + } + + stmt.setInt(paramIdx++, tenantId); + if (isOwnershipProvided) { + stmt.setString(paramIdx++, ownership); + } + if (isOwnerProvided) { + stmt.setString(paramIdx++, owner); + } else if (isOwnerPatternProvided) { + stmt.setString(paramIdx++, ownerPattern + "%"); + } + if (isStatusProvided) { + stmt.setString(paramIdx++, status); + } + stmt.setInt(paramIdx++, request.getStartIndex()); + stmt.setInt(paramIdx, request.getRowCount()); + + rs = stmt.executeQuery(); + devices = new ArrayList<>(); + while (rs.next()) { + Device device = DeviceManagementDAOUtil.loadDevice(rs); + devices.add(device); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred while retrieving information of" + + " devices belonging to group : " + groupId, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return devices; + } + + @Override public List getDevicesOfUser(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java index f8bce9b286..e46d460bcb 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java @@ -140,6 +140,136 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public List searchDevicesInGroup(PaginationRequest request, int tenantId) + throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List devices = null; + + int groupId = request.getGroupId(); + String deviceType = request.getDeviceType(); + boolean isDeviceTypeProvided = false; + String deviceName = request.getDeviceName(); + boolean isDeviceNameProvided = false; + String owner = request.getOwner(); + boolean isOwnerProvided = false; + String ownerPattern = request.getOwnerPattern(); + boolean isOwnerPatternProvided = false; + String ownership = request.getOwnership(); + boolean isOwnershipProvided = false; + String status = request.getStatus(); + boolean isStatusProvided = false; + Date since = request.getSince(); + boolean isSinceProvided = false; + + try { + conn = this.getConnection(); + String sql = "SELECT d1.DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.DATE_OF_LAST_UPDATE, " + + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, " + + "(SELECT gd.DEVICE_ID, gd.DESCRIPTION, gd.NAME, gd.DEVICE_IDENTIFICATION, t.NAME AS DEVICE_TYPE " + + "FROM (SELECT d.ID AS DEVICE_ID, d.DESCRIPTION, d.NAME, d.DEVICE_IDENTIFICATION, d.DEVICE_TYPE_ID " + + "FROM DM_DEVICE d, (SELECT dgm.DEVICE_ID FROM DM_DEVICE_GROUP_MAP dgm WHERE dgm.GROUP_ID = ?) dgm1 WHERE" + + " d.ID = dgm1.DEVICE_ID AND d.TENANT_ID = ?"; + + + //Add the query for device-name + if (deviceName != null && !deviceName.isEmpty()) { + sql = sql + " AND d.NAME LIKE ?"; + isDeviceNameProvided = true; + } + + sql = sql + ") gd, DM_DEVICE_TYPE t"; + + if (since != null) { + sql = sql + ", DM_DEVICE_DETAIL dt"; + isSinceProvided = true; + } + + sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID"; + + //Add query for last updated timestamp + if (isSinceProvided) { + sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?"; + } + + //Add the query for device-type + if (deviceType != null && !deviceType.isEmpty()) { + sql = sql + " AND t.NAME = ?"; + isDeviceTypeProvided = true; + } + + sql = sql + " ) d1 WHERE d1.DEVICE_ID = e.DEVICE_ID AND TENANT_ID = ? "; + + //Add the query for ownership + if (ownership != null && !ownership.isEmpty()) { + sql = sql + " AND e.OWNERSHIP = ?"; + isOwnershipProvided = true; + } + //Add the query for owner + if (owner != null && !owner.isEmpty()) { + sql = sql + " AND e.OWNER = ?"; + isOwnerProvided = true; + } else if (ownerPattern != null && !ownerPattern.isEmpty()) { + sql = sql + " AND e.OWNER LIKE ?"; + isOwnerPatternProvided = true; + } + //Add the query for status + if (status != null && !status.isEmpty()) { + sql = sql + " AND e.STATUS = ?"; + isStatusProvided = true; + } + + sql = sql + " LIMIT ? OFFSET ?"; + + stmt = conn.prepareStatement(sql); + + stmt.setInt(1, groupId); + stmt.setInt(2, tenantId); + + int paramIdx = 3; + if (isDeviceNameProvided) { + stmt.setString(paramIdx++, deviceName + "%"); + } + if (isSinceProvided) { + stmt.setLong(paramIdx++, since.getTime()); + } + if (isDeviceTypeProvided) { + stmt.setString(paramIdx++, deviceType); + } + + stmt.setInt(paramIdx++, tenantId); + if (isOwnershipProvided) { + stmt.setString(paramIdx++, ownership); + } + if (isOwnerProvided) { + stmt.setString(paramIdx++, owner); + } else if (isOwnerPatternProvided) { + stmt.setString(paramIdx++, ownerPattern + "%"); + } + if (isStatusProvided) { + stmt.setString(paramIdx++, status); + } + stmt.setInt(paramIdx, request.getRowCount()); + stmt.setInt(paramIdx++, request.getStartIndex()); + + rs = stmt.executeQuery(); + devices = new ArrayList<>(); + while (rs.next()) { + Device device = DeviceManagementDAOUtil.loadDevice(rs); + devices.add(device); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred while retrieving information of" + + " devices belonging to group : " + groupId, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return devices; + } + @Override public List getDevicesOfUser(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java index ee60068fa8..12635fd1a1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java @@ -156,6 +156,136 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public List searchDevicesInGroup(PaginationRequest request, int tenantId) + throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List devices = null; + + int groupId = request.getGroupId(); + String deviceType = request.getDeviceType(); + boolean isDeviceTypeProvided = false; + String deviceName = request.getDeviceName(); + boolean isDeviceNameProvided = false; + String owner = request.getOwner(); + boolean isOwnerProvided = false; + String ownerPattern = request.getOwnerPattern(); + boolean isOwnerPatternProvided = false; + String ownership = request.getOwnership(); + boolean isOwnershipProvided = false; + String status = request.getStatus(); + boolean isStatusProvided = false; + Date since = request.getSince(); + boolean isSinceProvided = false; + + try { + conn = this.getConnection(); + String sql = "SELECT d1.DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.DATE_OF_LAST_UPDATE, " + + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, " + + "(SELECT gd.DEVICE_ID, gd.DESCRIPTION, gd.NAME, gd.DEVICE_IDENTIFICATION, t.NAME AS DEVICE_TYPE " + + "FROM (SELECT d.ID AS DEVICE_ID, d.DESCRIPTION, d.NAME, d.DEVICE_IDENTIFICATION, d.DEVICE_TYPE_ID " + + "FROM DM_DEVICE d, (SELECT dgm.DEVICE_ID FROM DM_DEVICE_GROUP_MAP dgm WHERE dgm.GROUP_ID = ?) dgm1 WHERE" + + " d.ID = dgm1.DEVICE_ID AND d.TENANT_ID = ?"; + + + //Add the query for device-name + if (deviceName != null && !deviceName.isEmpty()) { + sql = sql + " AND d.NAME LIKE ?"; + isDeviceNameProvided = true; + } + + sql = sql + ") gd, DM_DEVICE_TYPE t"; + + if (since != null) { + sql = sql + ", DM_DEVICE_DETAIL dt"; + isSinceProvided = true; + } + + sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID"; + + //Add query for last updated timestamp + if (isSinceProvided) { + sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?"; + } + + //Add the query for device-type + if (deviceType != null && !deviceType.isEmpty()) { + sql = sql + " AND t.NAME = ?"; + isDeviceTypeProvided = true; + } + + sql = sql + " ) d1 WHERE d1.DEVICE_ID = e.DEVICE_ID AND TENANT_ID = ? "; + + //Add the query for ownership + if (ownership != null && !ownership.isEmpty()) { + sql = sql + " AND e.OWNERSHIP = ?"; + isOwnershipProvided = true; + } + //Add the query for owner + if (owner != null && !owner.isEmpty()) { + sql = sql + " AND e.OWNER = ?"; + isOwnerProvided = true; + } else if (ownerPattern != null && !ownerPattern.isEmpty()) { + sql = sql + " AND e.OWNER LIKE ?"; + isOwnerPatternProvided = true; + } + //Add the query for status + if (status != null && !status.isEmpty()) { + sql = sql + " AND e.STATUS = ?"; + isStatusProvided = true; + } + + sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + + stmt = conn.prepareStatement(sql); + + stmt.setInt(1, groupId); + stmt.setInt(2, tenantId); + + int paramIdx = 3; + if (isDeviceNameProvided) { + stmt.setString(paramIdx++, deviceName + "%"); + } + if (isSinceProvided) { + stmt.setLong(paramIdx++, since.getTime()); + } + if (isDeviceTypeProvided) { + stmt.setString(paramIdx++, deviceType); + } + + stmt.setInt(paramIdx++, tenantId); + if (isOwnershipProvided) { + stmt.setString(paramIdx++, ownership); + } + if (isOwnerProvided) { + stmt.setString(paramIdx++, owner); + } else if (isOwnerPatternProvided) { + stmt.setString(paramIdx++, ownerPattern + "%"); + } + if (isStatusProvided) { + stmt.setString(paramIdx++, status); + } + stmt.setInt(paramIdx++, request.getStartIndex()); + stmt.setInt(paramIdx, request.getRowCount()); + + rs = stmt.executeQuery(); + devices = new ArrayList<>(); + while (rs.next()) { + Device device = DeviceManagementDAOUtil.loadDevice(rs); + devices.add(device); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred while retrieving information of" + + " devices belonging to group : " + groupId, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return devices; + } + @Override public List getDevicesOfUser(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index 11b6866433..e3a2fb8fa9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -824,7 +824,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } else { try { DeviceManagementDAOFactory.openConnection(); - allDevices = deviceDAO.getDevices(request, tenantId); + if(request.getGroupId()!=0){ + allDevices = deviceDAO.searchDevicesInGroup(request, tenantId); + } else{ + allDevices = deviceDAO.getDevices(request, tenantId); + } count = deviceDAO.getDeviceCount(request, tenantId); } catch (DeviceManagementDAOException e) { String msg = "Error occurred while retrieving device list pertaining to the current tenant"; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/public/js/listing.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/public/js/listing.js index fbba497e09..2448a89f8f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/public/js/listing.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.devices/public/js/listing.js @@ -506,7 +506,7 @@ function loadDevices(searchType, searchParam) { $('#device-grid').datatables_extended_serverside_paging( null, - serviceURL, + "/api/device-mgt/v1.0/devices/", dataFilter, columns, fnCreatedRow, @@ -525,7 +525,8 @@ function loadDevices(searchType, searchParam) { }, { "placeholder": "Top-Device-Name-Search", - "searchKey": "namePattern" + "searchKey": "namePattern", + "groupId": groupId } ); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.data-tables-extended/public/js/dataTables.extended.serversidepaging.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.data-tables-extended/public/js/dataTables.extended.serversidepaging.js index aff3ea3942..3f8e0a7b64 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.data-tables-extended/public/js/dataTables.extended.serversidepaging.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.data-tables-extended/public/js/dataTables.extended.serversidepaging.js @@ -76,6 +76,9 @@ $.fn.datatables_extended_serverside_paging = function (settings, url, dataFilter searchParams[params.columns[i].data] = encodeURIComponent(params.columns[i].search.value); } if (options) { + if (options.groupId){ + searchParams["groupId"] = options.groupId; + } searchParams[options.searchKey] = encodeURIComponent(params.search.value); } params.filter = JSON.stringify(searchParams); From 1c825af79d6c0da0ee87727531c93cd305bf615c Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 15 Aug 2019 17:08:21 +0530 Subject: [PATCH 11/27] Move delete device permanently to device-mgt admin API --- .../service/api/DeviceManagementService.java | 7 +- .../admin/DeviceManagementAdminService.java | 90 +++++++++++++++++++ .../impl/DeviceManagementServiceImpl.java | 14 +-- .../DeviceManagementAdminServiceImpl.java | 45 +++++++++- .../impl/DeviceManagementServiceImplTest.java | 9 +- 5 files changed, 138 insertions(+), 27 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index 4cf332c0b8..aba6d9819c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -901,12 +901,7 @@ public interface DeviceManagementService { required = true) @PathParam("device-id") @Size(max = 45) - String deviceId, - @ApiParam( - name = "permanentDelete", - value = "Boolean flag indicating whether to permanently delete the device.", - required = false) - @QueryParam("permanentDelete") boolean permanentDelete); + String deviceId); @GET @Path("/{type}/{id}/features") diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java index b96977adfb..4377c9d185 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java @@ -15,6 +15,22 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.jaxrs.service.api.admin; @@ -76,6 +92,12 @@ import java.util.List; description = "Update the ownership of the device", key = "perm:admin:devices:update-enrollment", permissions = {"/device-mgt/admin/devices/update-enrollment"} + ), + @Scope( + name = "Permanently Delete the device specified by device id", + description = "Permanently Delete the device specified by device id", + key = "perm:devices:permanent-delete", + permissions = {"/device-mgt/admin/devices/permanent-delete"} ) } ) @@ -225,4 +247,72 @@ public interface DeviceManagementAdminService { value = "List of device identifiers.", required = true) List deviceIdentifiers); + + @DELETE + @Path("/type/{device-type}/id/{device-id}") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + consumes = MediaType.APPLICATION_JSON, + httpMethod = "DELETE", + value = "Permanently remove the Device Specified by the Device ID", + notes = "Returns the status of the permanently deleted device operation and the details of the deleted device.", + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:permanent-delete") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully deleted the device permanently.", + response = Device.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource has been modified the last time.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 304, + message = "Not Modified. Empty body because the client already has the latest " + + "version of the requested resource."), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n No device is found under the provided type and id.", + response = ErrorResponse.class), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while retrieving information requested device.", + response = ErrorResponse.class) + }) + Response deleteDevicePermanently( + @ApiParam( + name = "device-type", + value = "The device type, such as ios, android, or windows.", + required = true) + @PathParam("device-type") + @Size(max = 45) + String deviceType, + @ApiParam( + name = "device-id", + value = "The device identifier of the device.", + required = true) + @PathParam("device-id") + @Size(max = 45) + String deviceId); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index 2e7aeb9e53..33cf2ec35b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -105,7 +105,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Map; @Path("/devices") @Produces(MediaType.APPLICATION_JSON) @@ -326,8 +325,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @Override @Path("/type/{device-type}/id/{device-id}") public Response deleteDevice(@PathParam("device-type") String deviceType, - @PathParam("device-id") String deviceId, - @QueryParam("permanentDelete") boolean permanentDelete) { + @PathParam("device-id") String deviceId) { DeviceManagementProviderService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceManagementService(); try { @@ -336,16 +334,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { if (persistedDevice == null) { return Response.status(Response.Status.NOT_FOUND).build(); } - - boolean response; - - if (permanentDelete) { - response = deviceManagementProviderService.deleteDevice(deviceIdentifier); - } else { - response = deviceManagementProviderService.disenrollDevice(deviceIdentifier); - } + boolean response = deviceManagementProviderService.disenrollDevice(deviceIdentifier); return Response.status(Response.Status.OK).entity(response).build(); - } catch (DeviceManagementException e) { String msg = "Error encountered while deleting device of type : " + deviceType + " and " + "ID : " + deviceId; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index ecae28ff4f..d3d0fe194c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -15,28 +15,43 @@ * specific language governing permissions and limitations * under the License. * + * + * Copyright (c) 2019, Entgra (pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.jaxrs.service.impl.admin; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.solr.common.StringUtils; -import org.wso2.carbon.apimgt.integration.generated.client.publisher.StringUtil; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.UserNotFoundException; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.DeviceManagementAdminService; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; -import javax.validation.constraints.Past; import javax.validation.constraints.Size; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; @@ -120,4 +135,28 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); } } + + @DELETE + @Override + @Path("/type/{device-type}/id/{device-id}") + public Response deleteDevicePermanently(@PathParam("device-type") String deviceType, + @PathParam("device-id") String deviceId) { + DeviceManagementProviderService deviceManagementProviderService = + DeviceMgtAPIUtils.getDeviceManagementService(); + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); + Device persistedDevice = deviceManagementProviderService.getDevice(deviceIdentifier, true); + if (persistedDevice == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + boolean response = deviceManagementProviderService.deleteDevice(deviceIdentifier); + return Response.status(Response.Status.OK).entity(response).build(); + } catch (DeviceManagementException e) { + String msg = "Error encountered while permanently deleting device of type : " + deviceType + " and " + + "ID : " + deviceId; + log.error(msg, e); + return Response.status(Response.Status.BAD_REQUEST) + .entity(new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java index 6b923ba775..fc26189f40 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java @@ -481,8 +481,7 @@ public class DeviceManagementServiceImplTest { public void testDeleteDevice() { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) .toReturn(this.deviceManagementProviderService); - Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString() - , false); + Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString()); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); } @@ -492,8 +491,7 @@ public class DeviceManagementServiceImplTest { .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService .getDevice(Mockito.any(DeviceIdentifier.class), Mockito.anyBoolean())).thenReturn(null); - Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString() - , false); + Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString()); Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); Mockito.reset(this.deviceManagementProviderService); } @@ -504,8 +502,7 @@ public class DeviceManagementServiceImplTest { .toReturn(this.deviceManagementProviderService); Mockito.when(this.deviceManagementProviderService.disenrollDevice(Mockito.any(DeviceIdentifier.class))) .thenThrow(new DeviceManagementException()); - Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString() - , false); + Response response = this.deviceManagementService.deleteDevice(TEST_DEVICE_TYPE, UUID.randomUUID().toString()); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); Mockito.reset(this.deviceManagementProviderService); } From 1cf86ee95888572f89e10780342fdb7952ba9560 Mon Sep 17 00:00:00 2001 From: Milan Perera Date: Thu, 15 Aug 2019 17:08:45 +0200 Subject: [PATCH 12/27] Remove additional HTTP call from mssl handler This fixes the entgra/product-iots#128 --- .../handlers/AuthenticationHandler.java | 13 +++----- .../carbon/apimgt/handlers/utils/Utils.java | 32 +++---------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java index 8bad3de1a8..5638f3ba58 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java @@ -95,7 +95,7 @@ public class AuthenticationHandler extends AbstractHandler { log.debug("Verify Cert:\n" + mdmSignature); } URI certVerifyUrl = new URI(iotServerConfiguration.getVerificationEndpoint() + "ios"); - Map certVerifyHeaders = this.setHeaders(this.restInvoker); + Map certVerifyHeaders = this.setHeaders(); Certificate certificate = new Certificate(); certificate.setPem(mdmSignature); @@ -127,7 +127,7 @@ public class AuthenticationHandler extends AbstractHandler { String deviceType = this.getDeviceType(messageContext.getTo().getAddress().trim()); URI certVerifyUrl = new URI(iotServerConfiguration.getVerificationEndpoint() + deviceType); - Map certVerifyHeaders = this.setHeaders(this.restInvoker); + Map certVerifyHeaders = this.setHeaders(); Certificate certificate = new Certificate(); certificate.setPem(subjectDN); certificate.setTenantId(tenantId); @@ -157,7 +157,7 @@ public class AuthenticationHandler extends AbstractHandler { } String deviceType = this.getDeviceType(messageContext.getTo().getAddress().trim()); URI certVerifyUrl = new URI(iotServerConfiguration.getVerificationEndpoint() + deviceType); - Map certVerifyHeaders = this.setHeaders(this.restInvoker); + Map certVerifyHeaders = this.setHeaders(); Certificate certificate = new Certificate(); certificate.setPem(encodedPem); @@ -184,9 +184,6 @@ public class AuthenticationHandler extends AbstractHandler { } catch (URISyntaxException e) { log.error("Error while processing certificate.", e); return false; - } catch (APIMCertificateMGTException e) { - log.error("Error while processing certificate.", e); - return false; } catch (CertificateException e) { log.error("Certificate issue occurred when generating converting PEM to x509Certificate", e); return false; @@ -212,9 +209,9 @@ public class AuthenticationHandler extends AbstractHandler { return null; } - private Map setHeaders(RESTInvoker restInvoker) throws APIMCertificateMGTException { + private Map setHeaders() { Map map = new HashMap<>(); - String accessToken = Utils.getAccessToken(iotServerConfiguration, restInvoker); + String accessToken = Utils.getBase64EncodedToken(iotServerConfiguration); map.put(AUTHORIZATION, BEARER + accessToken); map.put(CONTENT_TYPE, "application/json"); return map; diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/utils/Utils.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/utils/Utils.java index f149868e76..5be2c18705 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/utils/Utils.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/utils/Utils.java @@ -135,38 +135,14 @@ public class Utils { } /** - * This class get the access token from the key manager. + * This method is used to get the base64 encoded token. * * @param iotServerConfiguration Instance of the IoTsererConfiguration. * @return Access token will be returned. - * @throws APIMCertificateMGTException */ - public static String getAccessToken(IOTServerConfiguration iotServerConfiguration, RESTInvoker restInvoker) - throws APIMCertificateMGTException { - try { - if (clientId == null || clientSecret == null) { - getClientSecretes(iotServerConfiguration, restInvoker); - } - URI tokenUrl = new URI(iotServerConfiguration.getOauthTokenEndpoint()); - String tokenContent = "grant_type=password&username=" + iotServerConfiguration.getUsername() + "&password=" + - iotServerConfiguration.getPassword() + "&scope=activity-view"; - String tokenBasicAuth = "Basic " + Base64.encode((clientId + ":" + clientSecret).getBytes()); - Map tokenHeaders = new HashMap<>(); - tokenHeaders.put("Authorization", tokenBasicAuth); - tokenHeaders.put("Content-Type", "application/x-www-form-urlencoded"); - - RESTResponse response = restInvoker.invokePOST(tokenUrl, tokenHeaders, tokenContent); - if (log.isDebugEnabled()) { - log.debug("Token response:" + response.getContent()); - } - JSONObject jsonResponse = new JSONObject(response.getContent()); - return jsonResponse.getString("access_token"); - - } catch (URISyntaxException | IOException e) { - throw new APIMCertificateMGTException("Error occurred while trying to call oauth token endpoint", e); - } catch (JSONException e) { - throw new APIMCertificateMGTException("Error occurred while converting the json to object", e); - } + public static String getBase64EncodedToken(IOTServerConfiguration iotServerConfiguration) { + return Base64.encode((iotServerConfiguration.getUsername() + ":" + iotServerConfiguration.getPassword()). + getBytes()); } /** From b7757a65ce8e424cce3884a4dc2456e1b2170f84 Mon Sep 17 00:00:00 2001 From: Milan Perera Date: Thu, 15 Aug 2019 20:49:14 +0200 Subject: [PATCH 13/27] Enable basic authentication in cert-mgt webapp --- .../src/main/webapp/WEB-INF/web.xml | 4 ++++ .../src/main/webapp/WEB-INF/web.xml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.api/src/main/webapp/WEB-INF/web.xml b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.api/src/main/webapp/WEB-INF/web.xml index 6fd45f33b3..9722ee843e 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.api/src/main/webapp/WEB-INF/web.xml +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.api/src/main/webapp/WEB-INF/web.xml @@ -37,6 +37,10 @@ doAuthentication true + + basicAuth + true + diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.v09.api/src/main/webapp/WEB-INF/web.xml b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.v09.api/src/main/webapp/WEB-INF/web.xml index 9c7b5bea47..d642acfffa 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.v09.api/src/main/webapp/WEB-INF/web.xml +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.v09.api/src/main/webapp/WEB-INF/web.xml @@ -41,6 +41,10 @@ isDefault false + + basicAuth + true + From 439ce4f1ece64dcf6b6ef190fa0639a8e6aa95a8 Mon Sep 17 00:00:00 2001 From: Milan Perera Date: Thu, 15 Aug 2019 22:23:46 +0200 Subject: [PATCH 14/27] Fix apim handler test failures --- .../wso2/carbon/apimgt/handlers/AuthenticationHandler.java | 2 +- .../carbon/apimgt/handlers/AuthenticationHandlerTest.java | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java index 5638f3ba58..06d344a514 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandler.java @@ -55,7 +55,7 @@ public class AuthenticationHandler extends AbstractHandler { private static final String X_JWT_ASSERTION = "X-JWT-Assertion"; private static final String JWTTOKEN = "JWTToken"; private static final String AUTHORIZATION = "Authorization"; - private static final String BEARER = "Bearer "; + private static final String BEARER = "Basic "; private static final String CONTENT_TYPE = "Content-Type"; private IOTServerConfiguration iotServerConfiguration; diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/test/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandlerTest.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/test/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandlerTest.java index b3b8cdac78..23e6b251fc 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/test/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandlerTest.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/test/java/org/wso2/carbon/apimgt/handlers/AuthenticationHandlerTest.java @@ -92,8 +92,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.MDM_SIGNATURE, "some cert"); setMockClient(); - this.mockClient.setResponse(getDCRResponse()); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(getValidationResponse()); boolean response = this.handler.handleRequest(createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice")); @@ -107,7 +105,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.PROXY_MUTUAL_AUTH_HEADER, "Test Header"); setMockClient(); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(getValidationResponse()); boolean response = this.handler.handleRequest(createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice")); @@ -121,7 +118,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.MUTUAL_AUTH_HEADER, "Test Header"); setMockClient(); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(getValidationResponse()); MessageContext messageContext = createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice"); @@ -141,7 +137,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.ENCODED_PEM, "encoded pem"); setMockClient(); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(getValidationResponse()); MessageContext messageContext = createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice"); @@ -156,7 +151,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.ENCODED_PEM, "encoded pem"); setMockClient(); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(getInvalidResponse()); MessageContext messageContext = createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice"); @@ -185,7 +179,6 @@ public class AuthenticationHandlerTest extends BaseAPIHandlerTest { HashMap transportHeaders = new HashMap<>(); transportHeaders.put(AuthConstants.ENCODED_PEM, "encoded pem"); setMockClient(); - this.mockClient.setResponse(getAccessTokenReponse()); this.mockClient.setResponse(null); MessageContext messageContext = createSynapseMessageContext("", this.synapseConfiguration, transportHeaders, "https://test.com/testservice/device-mgt/testdevice"); From dd4a31beb70f54b41e7b7a70ce0b6129947ddf93 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Fri, 16 Aug 2019 13:49:49 +0530 Subject: [PATCH 15/27] Log and set message in response whend device not found to delete --- .../impl/admin/DeviceManagementAdminServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index d3d0fe194c..4a2fb4f25d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -147,7 +147,11 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); Device persistedDevice = deviceManagementProviderService.getDevice(deviceIdentifier, true); if (persistedDevice == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + String msg = "No device found with the device type: " + deviceType + + " having the device ID: " + deviceId + " to permanently delete."; + log.error(msg); + return Response.status(Response.Status.NOT_FOUND).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); } boolean response = deviceManagementProviderService.deleteDevice(deviceIdentifier); return Response.status(Response.Status.OK).entity(response).build(); @@ -155,8 +159,8 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe String msg = "Error encountered while permanently deleting device of type : " + deviceType + " and " + "ID : " + deviceId; log.error(msg, e); - return Response.status(Response.Status.BAD_REQUEST) - .entity(new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); } } } From 5271fc41635e80c6fb3bbb4a8f182842ae5165e9 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 1 Aug 2019 17:57:44 +0530 Subject: [PATCH 16/27] Add device type extension config --- .../DeviceTypeManagerExtensionConfig.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java new file mode 100644 index 0000000000..5cd564367a --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java @@ -0,0 +1,19 @@ +package org.wso2.carbon.device.mgt.extensions.device.type.template.config; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "DeviceTypeManagerExtensionConfig") +public class DeviceTypeManagerExtensionConfig { + + private String extensionClass; + + @XmlElement(name = "ExtensionClass", required = true) + public String getExtensionClass() { + return extensionClass; + } + + public void setExtensionClass(String extensionClass) { + this.extensionClass = extensionClass; + } +} From f1c6ee70685ec9bdf61814835ea1c4cc2d2d0f07 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 1 Aug 2019 17:58:05 +0530 Subject: [PATCH 17/27] Add interface for device type plugin dao --- .../DeviceTypeManagerExtensionService.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java new file mode 100644 index 0000000000..4155523595 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.spi; + +import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; + +public interface DeviceTypeManagerExtensionService { + + void setDeviceTypePluginDAOManager(DeviceTypePluginDAOManager deviceManager); +} From 9d81ee6cb40531583caeabf3aba8409436b3888e Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 1 Aug 2019 17:59:08 +0530 Subject: [PATCH 18/27] Expose device type extension dao plugin via device type deployer --- .../type/template/DeviceTypeManager.java | 32 +++++++++++++++++++ .../config/DeviceTypeConfiguration.java | 23 +++++++++++++ .../template/dao/DeviceTypeDAOHandler.java | 14 ++++++++ 3 files changed, 69 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java index 948e5a5ff6..fc331d8220 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java @@ -34,6 +34,7 @@ */ package org.wso2.carbon.device.mgt.extensions.device.type.template; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; @@ -48,9 +49,11 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManagementException; import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManager; +import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypeManagerExtensionService; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DataSource; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceDetails; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceTypeConfiguration; +import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceTypeManagerExtensionConfig; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.Feature; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.Table; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.TableConfig; @@ -213,6 +216,35 @@ public class DeviceTypeManager implements DeviceManager { } } } + setDeviceTypeManagerExtensionServices(deviceTypeConfiguration); + } + + private void setDeviceTypeManagerExtensionServices(DeviceTypeConfiguration deviceTypeConfiguration) { + DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig = deviceTypeConfiguration.getDeviceTypeExtensionConfig(); + if (deviceTypeExtensionConfig != null) { + String extensionClass = deviceTypeExtensionConfig.getExtensionClass(); + if (StringUtils.isNotEmpty(extensionClass)) { + try { + Class clz = Class.forName(extensionClass); + DeviceTypeManagerExtensionService deviceTypeManagerExtensionService = (DeviceTypeManagerExtensionService) clz.newInstance(); + if (deviceTypePluginDAOManager != null) { + deviceTypeManagerExtensionService.setDeviceTypePluginDAOManager(deviceTypePluginDAOManager); + } + } catch (ClassNotFoundException e) { + String msg = "Extension class cannot be located"; + log.error(msg, e); + throw new DeviceTypeDeployerPayloadException(msg, e); + } catch (IllegalAccessException e) { + String msg = "Cannot access the class or its constructor is not accessible."; + log.error(msg, e); + throw new DeviceTypeDeployerPayloadException(msg, e); + } catch (InstantiationException e) { + String msg = "Extension class instantiation is failed"; + log.error(msg, e); + throw new DeviceTypeDeployerPayloadException(msg, e); + } + } + } } @Override diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java index b1ba2d8fe8..568aa5ae73 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java @@ -105,6 +105,8 @@ public class DeviceTypeConfiguration { @XmlElementWrapper(name = "StartupOperationConfig") @XmlElement(name = "Operation", required = true) protected List startupOperations; + @XmlElement(name = "DeviceTypeManagerExtensionConfig") + private DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig; public List getOperations() { return operations; @@ -402,4 +404,25 @@ public class DeviceTypeConfiguration { public void setStartupOperations(List startupOperations) { this.startupOperations = startupOperations; } + + /** + * Gets the value of DeviceTypeManagerExtensionConfig + * + * @return possible object is + * {@link DeviceTypeManagerExtensionConfig} + */ + public DeviceTypeManagerExtensionConfig getDeviceTypeExtensionConfig() { + return deviceTypeExtensionConfig; + } + + /** + * Sets the value for DeviceTypeManagerExtensionConfig + * + * @param deviceTypeExtensionConfig possible object is + * {@link DeviceTypeManagerExtensionConfig} + */ + public void setDeviceTypeExtensionConfig( + DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig) { + this.deviceTypeExtensionConfig = deviceTypeExtensionConfig; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java index e31149fafe..b37eca5f85 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java @@ -2,6 +2,7 @@ package org.wso2.carbon.device.mgt.extensions.device.type.template.dao; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.IllegalTransactionStateException; import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypeDeployerPayloadException; import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypeMgtPluginException; @@ -35,6 +36,19 @@ public class DeviceTypeDAOHandler { } } + public void openConnection() throws DeviceTypeMgtPluginException { + try { + Connection conn = currentConnection.get(); + if (conn != null) { + throw new IllegalTransactionStateException("Database connection has already been obtained."); + } + conn = dataSource.getConnection(); + currentConnection.set(conn); + } catch (SQLException e) { + throw new DeviceTypeMgtPluginException("Failed to get a database connection.", e); + } + } + public void beginTransaction() throws DeviceTypeMgtPluginException { try { Connection conn = dataSource.getConnection(); From 0d203e0cd598b504a4a120fcc3359270f48c736f Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:38:33 +0530 Subject: [PATCH 19/27] Set device type plugin DAO manager in hashmap --- .../type/template/DeviceTypeManager.java | 108 +++++------------- .../DeviceTypeManagerExtensionService.java | 26 ----- 2 files changed, 29 insertions(+), 105 deletions(-) delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java index fc331d8220..1551d302b7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java @@ -49,11 +49,9 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManagementException; import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManager; -import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypeManagerExtensionService; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DataSource; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceDetails; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceTypeConfiguration; -import org.wso2.carbon.device.mgt.extensions.device.type.template.config.DeviceTypeManagerExtensionConfig; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.Feature; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.Table; import org.wso2.carbon.device.mgt.extensions.device.type.template.config.TableConfig; @@ -65,6 +63,7 @@ import org.wso2.carbon.device.mgt.extensions.device.type.template.feature.Config import org.wso2.carbon.device.mgt.extensions.device.type.template.util.DeviceTypePluginConstants; import org.wso2.carbon.device.mgt.extensions.device.type.template.util.DeviceTypeUtils; import org.wso2.carbon.device.mgt.extensions.license.mgt.registry.RegistryBasedLicenseManager; +import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypePluginExtensionService; import org.wso2.carbon.registry.api.RegistryException; import org.wso2.carbon.registry.api.Resource; import org.wso2.carbon.utils.CarbonUtils; @@ -216,34 +215,18 @@ public class DeviceTypeManager implements DeviceManager { } } } - setDeviceTypeManagerExtensionServices(deviceTypeConfiguration); + setDeviceTypePluginManager(); } - private void setDeviceTypeManagerExtensionServices(DeviceTypeConfiguration deviceTypeConfiguration) { - DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig = deviceTypeConfiguration.getDeviceTypeExtensionConfig(); - if (deviceTypeExtensionConfig != null) { - String extensionClass = deviceTypeExtensionConfig.getExtensionClass(); - if (StringUtils.isNotEmpty(extensionClass)) { - try { - Class clz = Class.forName(extensionClass); - DeviceTypeManagerExtensionService deviceTypeManagerExtensionService = (DeviceTypeManagerExtensionService) clz.newInstance(); - if (deviceTypePluginDAOManager != null) { - deviceTypeManagerExtensionService.setDeviceTypePluginDAOManager(deviceTypePluginDAOManager); - } - } catch (ClassNotFoundException e) { - String msg = "Extension class cannot be located"; - log.error(msg, e); - throw new DeviceTypeDeployerPayloadException(msg, e); - } catch (IllegalAccessException e) { - String msg = "Cannot access the class or its constructor is not accessible."; - log.error(msg, e); - throw new DeviceTypeDeployerPayloadException(msg, e); - } catch (InstantiationException e) { - String msg = "Extension class instantiation is failed"; - log.error(msg, e); - throw new DeviceTypeDeployerPayloadException(msg, e); - } - } + /** + * Set device type plugin DAO manager of each device type in a HashMap which can then be used via individual + * device type plugin in working with its DAO components + */ + private void setDeviceTypePluginManager() { + if (StringUtils.isNotEmpty(deviceType) && deviceTypePluginDAOManager != null) { + DeviceTypePluginExtensionService deviceTypeManagerExtensionService = + new DeviceTypePluginExtensionServiceImpl(); + deviceTypeManagerExtensionService.addPluginDAOManager(deviceType, deviceTypePluginDAOManager); } } @@ -339,15 +322,11 @@ public class DeviceTypeManager implements DeviceManager { deviceTypePluginDAOManager.getDeviceTypeDAOHandler().commitTransaction(); } } catch (DeviceTypeMgtPluginException e) { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); - } catch (DeviceTypeMgtPluginException ex) { - String msg = "Error occurred while roll back the device enrol transaction :" + - device.toString(); - log.warn(msg, ex); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); String msg = "Error while enrolling the " + deviceType + " device : " + device.getDeviceIdentifier(); throw new DeviceManagementException(msg, e); + } finally { + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return status; } @@ -366,16 +345,12 @@ public class DeviceTypeManager implements DeviceManager { status = deviceTypePluginDAOManager.getDeviceDAO().updateDevice(device); deviceTypePluginDAOManager.getDeviceTypeDAOHandler().commitTransaction(); } catch (DeviceTypeMgtPluginException e) { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); - } catch (DeviceTypeMgtPluginException mobileDAOEx) { - String msg = "Error occurred while roll back the update device transaction :" + - device.toString(); - log.warn(msg, mobileDAOEx); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); String msg = "Error while updating the enrollment of the " + deviceType + " device : " + device.getDeviceIdentifier(); throw new DeviceManagementException(msg, e); + } finally { + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return status; } @@ -410,13 +385,7 @@ public class DeviceTypeManager implements DeviceManager { deviceId.getId(); throw new DeviceManagementException(msg, e); } finally { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); - } catch (DeviceTypeMgtPluginException e) { - String msg = "Error occurred while closing the transaction to check device " + - deviceId.getId() + " is enrolled."; - log.warn(msg, e); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return isEnrolled; } @@ -451,12 +420,7 @@ public class DeviceTypeManager implements DeviceManager { throw new DeviceManagementException( "Error occurred while fetching the " + deviceType + " device: '" + deviceId.getId() + "'", e); } finally { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); - } catch (DeviceTypeMgtPluginException e) { - String msg = "Error occurred while closing the transaction to get device " + deviceId.getId(); - log.warn(msg, e); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return device; } @@ -479,14 +443,11 @@ public class DeviceTypeManager implements DeviceManager { status = deviceTypePluginDAOManager.getDeviceDAO().updateDevice(updatedDevice); deviceTypePluginDAOManager.getDeviceTypeDAOHandler().commitTransaction(); } catch (DeviceTypeMgtPluginException e) { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); - } catch (DeviceTypeMgtPluginException transactionException) { - String msg = "Error occurred while rolling back transaction for device: " + deviceId.getId(); - log.warn(msg, transactionException); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); throw new DeviceManagementException( "Error occurred while fetching the " + deviceType + " device: '" + deviceId.getId() + "'", e); + } finally { + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } } return status; @@ -576,15 +537,12 @@ public class DeviceTypeManager implements DeviceManager { status = deviceTypePluginDAOManager.getDeviceDAO().updateDevice(existingDevice); deviceTypePluginDAOManager.getDeviceTypeDAOHandler().commitTransaction(); } catch (DeviceTypeMgtPluginException e) { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); - } catch (DeviceTypeMgtPluginException e1) { - log.warn("Error occurred while roll back the update device info transaction : '" + - device.toString() + "'", e1); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); throw new DeviceManagementException( "Error occurred while updating the " + deviceType + " device: '" + device.getDeviceIdentifier() + "'", e); + } finally { + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return status; } @@ -604,12 +562,7 @@ public class DeviceTypeManager implements DeviceManager { } catch (DeviceTypeMgtPluginException e) { throw new DeviceManagementException("Error occurred while fetching all " + deviceType + " devices", e); } finally { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); - } catch (DeviceTypeMgtPluginException e) { - String msg = "Error occurred while closing the transaction to get all devices."; - log.warn(msg, e); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return devices; } @@ -632,15 +585,12 @@ public class DeviceTypeManager implements DeviceManager { status = deviceTypePluginDAOManager.getDeviceDAO().deleteDevice(existingDevice); deviceTypePluginDAOManager.getDeviceTypeDAOHandler().commitTransaction(); } catch (DeviceTypeMgtPluginException e) { - try { - deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); - } catch (DeviceTypeMgtPluginException e1) { - log.warn("Error occurred while roll back the delete device info transaction : '" + - device.toString() + "'", e1); - } + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().rollbackTransaction(); throw new DeviceManagementException( "Error occurred while deleting the " + deviceType + " device: '" + device.getDeviceIdentifier() + "'", e); + } finally { + deviceTypePluginDAOManager.getDeviceTypeDAOHandler().closeConnection(); } return status; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java deleted file mode 100644 index 4155523595..0000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypeManagerExtensionService.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved. - * - * Entgra (Pvt) Ltd. 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.spi; - -import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; - -public interface DeviceTypeManagerExtensionService { - - void setDeviceTypePluginDAOManager(DeviceTypePluginDAOManager deviceManager); -} From f0103f27c4cb70447a17e7157eb2836f2c84fd18 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:39:18 +0530 Subject: [PATCH 20/27] Modify error messages and exception handling --- .../template/dao/DeviceTypeDAOHandler.java | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java index b37eca5f85..6347aa136e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java @@ -70,25 +70,21 @@ public class DeviceTypeDAOHandler { return currentConnection.get(); } - public void commitTransaction() throws DeviceTypeMgtPluginException { + public void commitTransaction() { + Connection conn = currentConnection.get(); + if (conn == null) { + throw new IllegalStateException("No connection is associated with the current transaction. " + + "This might have ideally been caused by not properly initiating the " + + "transaction via 'beginTransaction'/'openConnection' methods"); + } try { - Connection conn = currentConnection.get(); - if (conn != null) { - conn.commit(); - } else { - if (log.isDebugEnabled()) { - log.debug("Datasource connection associated with the current thread is null, hence commit " - + "has not been attempted"); - } - } + conn.commit(); } catch (SQLException e) { - throw new DeviceTypeMgtPluginException("Error occurred while committing the transaction", e); - } finally { - closeConnection(); + log.error("Error occurred while committing the transaction.", e); } } - public void closeConnection() throws DeviceTypeMgtPluginException { + public void closeConnection() { Connection con = currentConnection.get(); if (con != null) { @@ -101,21 +97,17 @@ public class DeviceTypeDAOHandler { currentConnection.remove(); } - public void rollbackTransaction() throws DeviceTypeMgtPluginException { + public void rollbackTransaction() { + Connection conn = currentConnection.get(); + if (conn == null) { + throw new IllegalStateException("No connection is associated with the current transaction. " + + "This might have ideally been caused by not properly initiating the " + + "transaction via 'beginTransaction'/'openConnection' methods"); + } try { - Connection conn = currentConnection.get(); - if (conn != null) { - conn.rollback(); - } else { - if (log.isDebugEnabled()) { - log.debug("Datasource connection associated with the current thread is null, hence rollback " - + "has not been attempted"); - } - } + conn.rollback(); } catch (SQLException e) { - throw new DeviceTypeMgtPluginException("Error occurred while rollback the transaction", e); - } finally { - closeConnection(); + log.error("Error occurred while roll-backing the transaction.", e); } } } From 42b092d43ae9a06df12d3add14e14c6177a7d177 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:41:37 +0530 Subject: [PATCH 21/27] Add license header for DeviceTypeDAOHandler --- .../type/template/dao/DeviceTypeDAOHandler.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java index 6347aa136e..edbbba52c6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2019, Entgra (Pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.device.type.template.dao; import org.apache.commons.logging.Log; From c5b46415971024f30fe54bc7fe76953a943961a9 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:50:55 +0530 Subject: [PATCH 22/27] Add the interface of DeviceTypePluginExtensionService --- .../spi/DeviceTypePluginExtensionService.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java new file mode 100644 index 0000000000..3c57300cec --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, Entgra (Pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.spi; + +import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; + +/** + * This represents the device type plugin extension service which can be used by any device type plugin implementation + * intended to use the same plugin DAO instances to be used with its plugin level DAO components + */ +public interface DeviceTypePluginExtensionService { + + /** + * Save device type specific pluginDAOManager in a HashMap + * @param deviceType - Type of the device (i.e; android, ios, windows) + * @param pluginDAOManager - Device type plugin DAO manager instance to be saved against device type + */ + void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager); + + /** + * Retrieve the DeviceTypePluginDAOManager instance given the device type + * @param deviceType - Type of the device (i.e; android, ios, windows) + * @return an Instance of {@link DeviceTypePluginDAOManager} + */ + DeviceTypePluginDAOManager getPluginDAOManager(String deviceType); +} From b9bceadec88d582711eedc037359155de2799915 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:51:21 +0530 Subject: [PATCH 23/27] Add the implementation of DeviceTypePluginExtensionService --- .../DeviceTypePluginExtensionServiceImpl.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java new file mode 100644 index 0000000000..4ccaeadb60 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019, Entgra (Pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.device.type.template; + +import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; +import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypePluginExtensionService; + +import java.util.HashMap; +import java.util.Map; + +public class DeviceTypePluginExtensionServiceImpl implements DeviceTypePluginExtensionService { + + private static volatile Map pluginDAOManagers = new HashMap<>(); + + @Override + public void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager) { + if (pluginDAOManager != null) { + if (!pluginDAOManagers.containsKey(deviceType)) { + pluginDAOManagers.put(deviceType, pluginDAOManager); + } + } + } + + @Override + public DeviceTypePluginDAOManager getPluginDAOManager(String deviceType) { + return pluginDAOManagers.get(deviceType); + } +} From a246c16eb616aa2c8339e8037976e851c722c5a8 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Thu, 8 Aug 2019 16:53:28 +0530 Subject: [PATCH 24/27] Register DeviceTypePluginExtensionService --- .../DeviceTypeExtensionServiceComponent.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/internal/DeviceTypeExtensionServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/internal/DeviceTypeExtensionServiceComponent.java index e29af46f12..36ae9b11dc 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/internal/DeviceTypeExtensionServiceComponent.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/internal/DeviceTypeExtensionServiceComponent.java @@ -14,6 +14,23 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * + * + * Copyright (c) 2019, Entgra (Pvt) Ltd. (https://entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. 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.internal; @@ -23,6 +40,8 @@ import org.apache.commons.logging.LogFactory; import org.osgi.service.component.ComponentContext; import org.wso2.carbon.device.mgt.common.spi.DeviceTypeGeneratorService; import org.wso2.carbon.device.mgt.extensions.device.type.template.DeviceTypeGeneratorServiceImpl; +import org.wso2.carbon.device.mgt.extensions.device.type.template.DeviceTypePluginExtensionServiceImpl; +import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypePluginExtensionService; import org.wso2.carbon.ndatasource.core.DataSourceService; import org.wso2.carbon.registry.core.service.RegistryService; @@ -50,6 +69,8 @@ public class DeviceTypeExtensionServiceComponent { } ctx.getBundleContext() .registerService(DeviceTypeGeneratorService.class, new DeviceTypeGeneratorServiceImpl(), null); + ctx.getBundleContext().registerService(DeviceTypePluginExtensionService.class, + new DeviceTypePluginExtensionServiceImpl(), null); if (log.isDebugEnabled()) { log.debug("Device Type Extension Service Component successfully activated"); } From d6d91e4bc2f40e95c5055f2fea0b843cf70baa06 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Sat, 10 Aug 2019 23:11:08 +0530 Subject: [PATCH 25/27] Remove retrieving device type extension class from deployer file --- .../config/DeviceTypeConfiguration.java | 23 ------------------- .../DeviceTypeManagerExtensionConfig.java | 19 --------------- 2 files changed, 42 deletions(-) delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java index 568aa5ae73..b1ba2d8fe8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeConfiguration.java @@ -105,8 +105,6 @@ public class DeviceTypeConfiguration { @XmlElementWrapper(name = "StartupOperationConfig") @XmlElement(name = "Operation", required = true) protected List startupOperations; - @XmlElement(name = "DeviceTypeManagerExtensionConfig") - private DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig; public List getOperations() { return operations; @@ -404,25 +402,4 @@ public class DeviceTypeConfiguration { public void setStartupOperations(List startupOperations) { this.startupOperations = startupOperations; } - - /** - * Gets the value of DeviceTypeManagerExtensionConfig - * - * @return possible object is - * {@link DeviceTypeManagerExtensionConfig} - */ - public DeviceTypeManagerExtensionConfig getDeviceTypeExtensionConfig() { - return deviceTypeExtensionConfig; - } - - /** - * Sets the value for DeviceTypeManagerExtensionConfig - * - * @param deviceTypeExtensionConfig possible object is - * {@link DeviceTypeManagerExtensionConfig} - */ - public void setDeviceTypeExtensionConfig( - DeviceTypeManagerExtensionConfig deviceTypeExtensionConfig) { - this.deviceTypeExtensionConfig = deviceTypeExtensionConfig; - } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java deleted file mode 100644 index 5cd564367a..0000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/config/DeviceTypeManagerExtensionConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.wso2.carbon.device.mgt.extensions.device.type.template.config; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement(name = "DeviceTypeManagerExtensionConfig") -public class DeviceTypeManagerExtensionConfig { - - private String extensionClass; - - @XmlElement(name = "ExtensionClass", required = true) - public String getExtensionClass() { - return extensionClass; - } - - public void setExtensionClass(String extensionClass) { - this.extensionClass = extensionClass; - } -} From 0c7843f2fe8512e6c5c287d2e4c11d4df18b6dc2 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Tue, 13 Aug 2019 18:40:10 +0530 Subject: [PATCH 26/27] Modify logic of saving DeviceTypePluginDAOManager to support multi tenancy --- .../type/template/DeviceTypeManager.java | 18 +++++++++--- .../DeviceTypePluginExtensionServiceImpl.java | 29 +++++++++++++++++-- .../DeviceTypePluginExtensionException.java | 12 ++++++++ .../spi/DeviceTypePluginExtensionService.java | 4 +-- 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java index 1551d302b7..1169d7eebf 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java @@ -59,6 +59,7 @@ import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceDAOD import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypeDeployerPayloadException; import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypeMgtPluginException; +import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypePluginExtensionException; import org.wso2.carbon.device.mgt.extensions.device.type.template.feature.ConfigurationBasedFeatureManager; import org.wso2.carbon.device.mgt.extensions.device.type.template.util.DeviceTypePluginConstants; import org.wso2.carbon.device.mgt.extensions.device.type.template.util.DeviceTypeUtils; @@ -223,10 +224,19 @@ public class DeviceTypeManager implements DeviceManager { * device type plugin in working with its DAO components */ private void setDeviceTypePluginManager() { - if (StringUtils.isNotEmpty(deviceType) && deviceTypePluginDAOManager != null) { - DeviceTypePluginExtensionService deviceTypeManagerExtensionService = - new DeviceTypePluginExtensionServiceImpl(); - deviceTypeManagerExtensionService.addPluginDAOManager(deviceType, deviceTypePluginDAOManager); + if (StringUtils.isNotEmpty(deviceType)) { + if (deviceTypePluginDAOManager != null) { + DeviceTypePluginExtensionService deviceTypeManagerExtensionService = + new DeviceTypePluginExtensionServiceImpl(); + deviceTypeManagerExtensionService.addPluginDAOManager(deviceType, deviceTypePluginDAOManager); + } else { + log.warn("Could not save DeviceTypePluginDAOManager for device type: " + deviceType + + " since DeviceTypePluginDAOManager is null."); + } + } else { + String msg = "Could not save DeviceTypePluginDAOManager since device type is null or empty."; + log.error(msg); + throw new DeviceTypePluginExtensionException(msg); } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java index 4ccaeadb60..bfe01098b6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java @@ -17,7 +17,11 @@ */ package org.wso2.carbon.device.mgt.extensions.device.type.template; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; +import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypePluginExtensionException; import org.wso2.carbon.device.mgt.extensions.spi.DeviceTypePluginExtensionService; import java.util.HashMap; @@ -25,19 +29,38 @@ import java.util.Map; public class DeviceTypePluginExtensionServiceImpl implements DeviceTypePluginExtensionService { + private static final Log log = LogFactory.getLog(DeviceTypePluginExtensionServiceImpl.class); + private static volatile Map pluginDAOManagers = new HashMap<>(); @Override public void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager) { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); if (pluginDAOManager != null) { - if (!pluginDAOManagers.containsKey(deviceType)) { - pluginDAOManagers.put(deviceType, pluginDAOManager); + if (!pluginDAOManagers.containsKey(tenantId + deviceType)) { + if (log.isDebugEnabled()) { + log.debug("Saving DeviceTypePluginDAOManager against tenant id " + tenantId + + " and device type: " + deviceType); + } + pluginDAOManagers.put(tenantId + deviceType, pluginDAOManager); } } } @Override public DeviceTypePluginDAOManager getPluginDAOManager(String deviceType) { - return pluginDAOManagers.get(deviceType); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + if (pluginDAOManagers.containsKey(tenantId + deviceType)) { + if (log.isDebugEnabled()) { + log.debug("Retrieving DeviceTypePluginDAOManager against tenant id " + tenantId + + " and device type: " + deviceType); + } + return pluginDAOManagers.get(tenantId + deviceType); + } else { + String msg = "DeviceTypePluginDAOManager could not be found against tenant id " + tenantId + + " and device type: " + deviceType; + log.error(msg); + throw new DeviceTypePluginExtensionException(msg); + } } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java new file mode 100644 index 0000000000..7afbd12cd2 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java @@ -0,0 +1,12 @@ +package org.wso2.carbon.device.mgt.extensions.device.type.template.exception; + +public class DeviceTypePluginExtensionException extends RuntimeException { + + public DeviceTypePluginExtensionException(String msg) { + super(msg); + } + + public DeviceTypePluginExtensionException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java index 3c57300cec..26aaf481e2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java @@ -26,14 +26,14 @@ import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceType public interface DeviceTypePluginExtensionService { /** - * Save device type specific pluginDAOManager in a HashMap + * Save device type specific DeviceTypePluginDAOManager in a HashMap againast tenant ID and device type * @param deviceType - Type of the device (i.e; android, ios, windows) * @param pluginDAOManager - Device type plugin DAO manager instance to be saved against device type */ void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager); /** - * Retrieve the DeviceTypePluginDAOManager instance given the device type + * Retrieve the DeviceTypePluginDAOManager instance against tenant ID and given device type * @param deviceType - Type of the device (i.e; android, ios, windows) * @return an Instance of {@link DeviceTypePluginDAOManager} */ From 4a58aea2d05fc738eb9ca96c710889c7fdcb6758 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Mon, 19 Aug 2019 13:54:19 +0530 Subject: [PATCH 27/27] Handle exception and log error messages related to DeviceTypeDAOHandler --- .../type/template/DeviceTypeManager.java | 11 ++++- .../DeviceTypePluginExtensionServiceImpl.java | 23 ++++++---- .../template/dao/DeviceTypeDAOHandler.java | 46 +++++++++++++------ .../DeviceTypePluginExtensionException.java | 2 +- .../spi/DeviceTypePluginExtensionService.java | 8 +++- 5 files changed, 61 insertions(+), 29 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java index 1169d7eebf..4e60210424 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypeManager.java @@ -228,7 +228,14 @@ public class DeviceTypeManager implements DeviceManager { if (deviceTypePluginDAOManager != null) { DeviceTypePluginExtensionService deviceTypeManagerExtensionService = new DeviceTypePluginExtensionServiceImpl(); - deviceTypeManagerExtensionService.addPluginDAOManager(deviceType, deviceTypePluginDAOManager); + try { + deviceTypeManagerExtensionService.addPluginDAOManager(deviceType, deviceTypePluginDAOManager); + } catch (DeviceTypePluginExtensionException e) { + String msg = "Error occurred while saving DeviceTypePluginDAOManager for device type: " + + deviceType; + log.error(msg); + throw new DeviceTypeDeployerPayloadException(msg); + } } else { log.warn("Could not save DeviceTypePluginDAOManager for device type: " + deviceType + " since DeviceTypePluginDAOManager is null."); @@ -236,7 +243,7 @@ public class DeviceTypeManager implements DeviceManager { } else { String msg = "Could not save DeviceTypePluginDAOManager since device type is null or empty."; log.error(msg); - throw new DeviceTypePluginExtensionException(msg); + throw new DeviceTypeDeployerPayloadException(msg); } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java index bfe01098b6..e32c9e2d57 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/DeviceTypePluginExtensionServiceImpl.java @@ -34,21 +34,26 @@ public class DeviceTypePluginExtensionServiceImpl implements DeviceTypePluginExt private static volatile Map pluginDAOManagers = new HashMap<>(); @Override - public void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager) { + public void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager) + throws DeviceTypePluginExtensionException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); - if (pluginDAOManager != null) { - if (!pluginDAOManagers.containsKey(tenantId + deviceType)) { - if (log.isDebugEnabled()) { - log.debug("Saving DeviceTypePluginDAOManager against tenant id " + tenantId + - " and device type: " + deviceType); - } - pluginDAOManagers.put(tenantId + deviceType, pluginDAOManager); + if (pluginDAOManager == null) { + String msg = "Cannot save DeviceTypePluginDAOManager against tenant id " + tenantId + + " and device type: " + deviceType + " since DeviceTypePluginDAOManager is null"; + log.error(msg); + throw new DeviceTypePluginExtensionException(msg); + } + if (!pluginDAOManagers.containsKey(tenantId + deviceType)) { + if (log.isDebugEnabled()) { + log.debug("Saving DeviceTypePluginDAOManager against tenant id " + tenantId + + " and device type: " + deviceType); } + pluginDAOManagers.put(tenantId + deviceType, pluginDAOManager); } } @Override - public DeviceTypePluginDAOManager getPluginDAOManager(String deviceType) { + public DeviceTypePluginDAOManager getPluginDAOManager(String deviceType) throws DeviceTypePluginExtensionException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); if (pluginDAOManagers.containsKey(tenantId + deviceType)) { if (log.isDebugEnabled()) { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java index edbbba52c6..417d078868 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/dao/DeviceTypeDAOHandler.java @@ -49,7 +49,9 @@ public class DeviceTypeDAOHandler { Context ctx = new InitialContext(); dataSource = (DataSource) ctx.lookup(datasourceName); } catch (NamingException e) { - throw new DeviceTypeDeployerPayloadException("Error while looking up the data source: " + datasourceName, e); + String msg = "Error while looking up the data source: " + datasourceName; + log.error(msg, e); + throw new DeviceTypeDeployerPayloadException(msg, e); } } @@ -57,12 +59,16 @@ public class DeviceTypeDAOHandler { try { Connection conn = currentConnection.get(); if (conn != null) { - throw new IllegalTransactionStateException("Database connection has already been obtained."); + String msg = "Database connection has already been obtained."; + log.error(msg); + throw new IllegalTransactionStateException(msg); } conn = dataSource.getConnection(); currentConnection.set(conn); } catch (SQLException e) { - throw new DeviceTypeMgtPluginException("Failed to get a database connection.", e); + String msg = "Failed to get a database connection."; + log.error(msg, e); + throw new DeviceTypeMgtPluginException(msg, e); } } @@ -72,7 +78,9 @@ public class DeviceTypeDAOHandler { conn.setAutoCommit(false); currentConnection.set(conn); } catch (SQLException e) { - throw new DeviceTypeMgtPluginException("Error occurred while retrieving datasource connection", e); + String msg = "Error occurred while retrieving datasource connection"; + log.error(msg, e); + throw new DeviceTypeMgtPluginException(msg, e); } } @@ -81,7 +89,9 @@ public class DeviceTypeDAOHandler { try { currentConnection.set(dataSource.getConnection()); } catch (SQLException e) { - throw new DeviceTypeMgtPluginException("Error occurred while retrieving data source connection", e); + String msg = "Error occurred while retrieving data source connection"; + log.error(msg, e); + throw new DeviceTypeMgtPluginException(msg, e); } } return currentConnection.get(); @@ -90,25 +100,28 @@ public class DeviceTypeDAOHandler { public void commitTransaction() { Connection conn = currentConnection.get(); if (conn == null) { - throw new IllegalStateException("No connection is associated with the current transaction. " + - "This might have ideally been caused by not properly initiating the " + - "transaction via 'beginTransaction'/'openConnection' methods"); + String msg = "No connection is associated with the current transaction. This might have ideally been " + + "caused by not properly initiating the transaction via " + + "'beginTransaction'/'openConnection' methods"; + log.error(msg); + throw new IllegalStateException(msg); } try { conn.commit(); } catch (SQLException e) { - log.error("Error occurred while committing the transaction.", e); + String msg = "Error occurred while committing the transaction."; + log.error(msg, e); } } public void closeConnection() { - Connection con = currentConnection.get(); if (con != null) { try { con.close(); } catch (SQLException e) { - log.error("Error occurred while close the connection"); + String msg = "Error occurred while close the connection"; + log.error(msg, e); } } currentConnection.remove(); @@ -117,14 +130,17 @@ public class DeviceTypeDAOHandler { public void rollbackTransaction() { Connection conn = currentConnection.get(); if (conn == null) { - throw new IllegalStateException("No connection is associated with the current transaction. " + - "This might have ideally been caused by not properly initiating the " + - "transaction via 'beginTransaction'/'openConnection' methods"); + String msg = "No connection is associated with the current transaction. This might have ideally been " + + "caused by not properly initiating the transaction via " + + "'beginTransaction'/'openConnection' methods"; + log.error(msg); + throw new IllegalStateException(msg); } try { conn.rollback(); } catch (SQLException e) { - log.error("Error occurred while roll-backing the transaction.", e); + String msg = "Error occurred while roll-backing the transaction."; + log.error(msg, e); } } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java index 7afbd12cd2..b0603f43bf 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/template/exception/DeviceTypePluginExtensionException.java @@ -1,6 +1,6 @@ package org.wso2.carbon.device.mgt.extensions.device.type.template.exception; -public class DeviceTypePluginExtensionException extends RuntimeException { +public class DeviceTypePluginExtensionException extends Exception { public DeviceTypePluginExtensionException(String msg) { super(msg); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java index 26aaf481e2..f91ed2e985 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/main/java/org/wso2/carbon/device/mgt/extensions/spi/DeviceTypePluginExtensionService.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.extensions.spi; import org.wso2.carbon.device.mgt.extensions.device.type.template.dao.DeviceTypePluginDAOManager; +import org.wso2.carbon.device.mgt.extensions.device.type.template.exception.DeviceTypePluginExtensionException; /** * This represents the device type plugin extension service which can be used by any device type plugin implementation @@ -29,13 +30,16 @@ public interface DeviceTypePluginExtensionService { * Save device type specific DeviceTypePluginDAOManager in a HashMap againast tenant ID and device type * @param deviceType - Type of the device (i.e; android, ios, windows) * @param pluginDAOManager - Device type plugin DAO manager instance to be saved against device type + * @throws DeviceTypePluginExtensionException when pluginDAOManager is null */ - void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager); + void addPluginDAOManager(String deviceType, DeviceTypePluginDAOManager pluginDAOManager) + throws DeviceTypePluginExtensionException; /** * Retrieve the DeviceTypePluginDAOManager instance against tenant ID and given device type * @param deviceType - Type of the device (i.e; android, ios, windows) * @return an Instance of {@link DeviceTypePluginDAOManager} + * @throws DeviceTypePluginExtensionException when pluginDAOManager cannot be found */ - DeviceTypePluginDAOManager getPluginDAOManager(String deviceType); + DeviceTypePluginDAOManager getPluginDAOManager(String deviceType) throws DeviceTypePluginExtensionException; }