diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/PolicyReport.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/PolicyReport.js
index 2e3e859308..59143a5c5b 100644
--- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/PolicyReport.js
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/PolicyReport.js
@@ -132,7 +132,10 @@ class PolicyReport extends React.Component {
Policy Report
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppListDropDown.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppListDropDown.js
new file mode 100644
index 0000000000..d12cb3c079
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppListDropDown.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+import React from 'react';
+import { message, notification, Select } from 'antd';
+import axios from 'axios';
+import { withConfigContext } from '../../../context/ConfigContext';
+
+const { Option } = Select;
+
+class AppListDropDown extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ selectItem: [],
+ };
+ }
+
+ componentDidMount() {
+ this.fetchFullAppList();
+ }
+
+ fetchFullAppList = () => {
+ const config = this.props.context;
+ axios
+ .get(
+ window.location.origin +
+ config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ '/devices/android/applications?offset=0&limit=-1',
+ )
+ .then(res => {
+ if (res.status === 200) {
+ let selectItem;
+ selectItem = res.data.data.applicationList.map(data => (
+
+ ));
+ this.setState({ selectItem });
+ }
+ })
+ .catch(error => {
+ if (error.hasOwnProperty('response') && error.response.status === 401) {
+ // todo display a popop with error
+ message.error('You are not logged in');
+ window.location.href = window.location.origin + '/entgra/login';
+ } else {
+ notification.error({
+ message: 'There was a problem',
+ duration: 0,
+ description:
+ 'Error occurred while trying to load application list.',
+ });
+ }
+ });
+ };
+
+ onChange = (value, data) => {
+ this.props.getAppList(data.key);
+ };
+
+ render() {
+ const { selectItem } = this.state;
+ return (
+
+
+
+ );
+ }
+}
+
+export default withConfigContext(AppListDropDown);
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppVersionDropDown.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppVersionDropDown.js
new file mode 100644
index 0000000000..40e31a0fbe
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/AppVersionDropDown.js
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+import React from 'react';
+import { message, notification, Select } from 'antd';
+import axios from 'axios';
+import { withConfigContext } from '../../../context/ConfigContext';
+
+const { Option } = Select;
+
+class AppVersionDropDown extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ selectItem: [],
+ loading: false,
+ };
+ }
+
+ componentDidMount() {
+ if (this.props.packageName) {
+ this.fetchVersionList();
+ }
+ }
+
+ // Rerender component when parameters change
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ if (prevProps.packageName !== this.props.packageName) {
+ this.fetchVersionList();
+ }
+ }
+
+ fetchVersionList = () => {
+ const config = this.props.context;
+ this.setState({ loading: true });
+ axios
+ .get(
+ window.location.origin +
+ config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ '/devices/application/' +
+ this.props.packageName +
+ '/versions',
+ )
+ .then(res => {
+ if (res.status === 200) {
+ let selectItem;
+ selectItem = JSON.parse(res.data.data).map(data => (
+
+ ));
+ this.setState({ selectItem, loading: false });
+ }
+ })
+ .catch(error => {
+ if (error.hasOwnProperty('response') && error.response.status === 401) {
+ // todo display a popop with error
+ message.error('You are not logged in');
+ window.location.href = window.location.origin + '/entgra/login';
+ } else {
+ notification.error({
+ message: 'There was a problem',
+ duration: 0,
+ description:
+ 'Error occurred while trying to load application list.',
+ });
+ }
+ });
+ };
+
+ onChange = value => {
+ this.props.getVersion(value);
+ };
+
+ render() {
+ const { selectItem, loading } = this.state;
+ return (
+
+
+
+ );
+ }
+}
+
+export default withConfigContext(AppVersionDropDown);
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/ReportDevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/ReportDevicesTable.js
new file mode 100644
index 0000000000..5710a79882
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/ReportDevicesTable.js
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+import React from 'react';
+import axios from 'axios';
+import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
+import TimeAgo from 'javascript-time-ago';
+// Load locale-specific relative date/time formatting rules.
+import en from 'javascript-time-ago/locale/en';
+import { withConfigContext } from '../../../context/ConfigContext';
+
+let config = null;
+
+const columns = [
+ {
+ title: 'Device',
+ dataIndex: 'name',
+ width: 100,
+ },
+ {
+ title: 'Type',
+ dataIndex: 'type',
+ key: 'type',
+ // eslint-disable-next-line react/display-name
+ render: type => {
+ const defaultPlatformIcons = config.defaultPlatformIcons;
+ let icon = defaultPlatformIcons.default.icon;
+ let color = defaultPlatformIcons.default.color;
+ let theme = defaultPlatformIcons.default.theme;
+
+ if (defaultPlatformIcons.hasOwnProperty(type)) {
+ icon = defaultPlatformIcons[type].icon;
+ color = defaultPlatformIcons[type].color;
+ theme = defaultPlatformIcons[type].theme;
+ }
+
+ return (
+
+
+
+ );
+ },
+ // todo add filtering options
+ },
+ {
+ title: 'Owner',
+ dataIndex: 'enrolmentInfo',
+ key: 'owner',
+ render: enrolmentInfo => enrolmentInfo.owner,
+ // todo add filtering options
+ },
+ {
+ title: 'Ownership',
+ dataIndex: 'enrolmentInfo',
+ key: 'ownership',
+ render: enrolmentInfo => enrolmentInfo.ownership,
+ // todo add filtering options
+ },
+ {
+ title: 'Status',
+ dataIndex: 'enrolmentInfo',
+ key: 'status',
+ // eslint-disable-next-line react/display-name
+ render: enrolmentInfo => {
+ const status = enrolmentInfo.status.toLowerCase();
+ let color = '#f9ca24';
+ switch (status) {
+ case 'active':
+ color = '#badc58';
+ break;
+ case 'created':
+ color = '#6ab04c';
+ break;
+ case 'removed':
+ color = '#ff7979';
+ break;
+ case 'inactive':
+ color = '#f9ca24';
+ break;
+ case 'blocked':
+ color = '#636e72';
+ break;
+ }
+ return
{status};
+ },
+ // todo add filtering options
+ },
+ {
+ title: 'Last Updated',
+ dataIndex: 'enrolmentInfo',
+ key: 'dateOfLastUpdate',
+ // eslint-disable-next-line react/display-name
+ render: data => {
+ const { dateOfLastUpdate } = data;
+ const timeAgoString = getTimeAgo(dateOfLastUpdate);
+ return (
+
+ {timeAgoString}
+
+ );
+ },
+ // todo add filtering options
+ },
+];
+
+const getTimeAgo = time => {
+ const timeAgo = new TimeAgo('en-US');
+ return timeAgo.format(time);
+};
+
+class ReportDeviceTable extends React.Component {
+ constructor(props) {
+ super(props);
+ config = this.props.context;
+ TimeAgo.addLocale(en);
+ this.state = {
+ data: [],
+ pagination: {},
+ loading: false,
+ selectedRows: [],
+ paramsObj: {},
+ };
+ }
+
+ rowSelection = {
+ onChange: (selectedRowKeys, selectedRows) => {
+ this.setState({
+ selectedRows: selectedRows,
+ });
+ },
+ };
+
+ componentDidMount() {
+ if (this.props.apiUrl) {
+ this.fetch();
+ }
+ }
+
+ // Rerender component when parameters change
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ if (prevProps.apiUrl !== this.props.apiUrl) {
+ this.fetch();
+ }
+ }
+
+ // fetch data from api
+ fetch = (params = {}) => {
+ this.setState({ loading: true });
+ // get current page
+ const currentPage = params.hasOwnProperty('page') ? params.page : 1;
+
+ const extraParams = {
+ offset: 10 * (currentPage - 1), // calculate the offset
+ limit: 10,
+ };
+
+ const encodedExtraParams = Object.keys(extraParams)
+ .map(key => key + '=' + extraParams[key])
+ .join('&');
+
+ // send request to the invokerss
+ axios
+ .get(this.props.apiUrl + encodedExtraParams)
+ .then(res => {
+ if (res.status === 200) {
+ const pagination = { ...this.state.pagination };
+ this.setState({
+ loading: false,
+ data: res.data.data,
+ pagination,
+ });
+ }
+ })
+ .catch(error => {
+ if (error.hasOwnProperty('response') && error.response.status === 401) {
+ // todo display a popop with error
+ message.error('You are not logged in');
+ window.location.href = window.location.origin + '/entgra/login';
+ } else {
+ notification.error({
+ message: 'There was a problem',
+ duration: 0,
+ description: 'Error occurred while trying to load devices.',
+ });
+ }
+
+ this.setState({ loading: false });
+ });
+ };
+
+ handleTableChange = (pagination, filters, sorter) => {
+ const pager = { ...this.state.pagination };
+ pager.current = pagination.current;
+ this.setState({
+ pagination: pager,
+ });
+ this.fetch({
+ results: pagination.pageSize,
+ page: pagination.current,
+ sortField: sorter.field,
+ sortOrder: sorter.order,
+ ...filters,
+ });
+ };
+
+ render() {
+ const { data, pagination, loading } = this.state;
+ return (
+
+
+ record.deviceIdentifier +
+ record.enrolmentInfo.owner +
+ record.enrolmentInfo.ownership
+ }
+ dataSource={data.devices}
+ pagination={{
+ ...pagination,
+ size: 'small',
+ total: data.count,
+ showTotal: (total, range) =>
+ `showing ${range[0]}-${range[1]} of ${total} devices`,
+ }}
+ loading={loading}
+ onChange={this.handleTableChange}
+ rowSelection={this.rowSelection}
+ />
+
+ );
+ }
+}
+
+export default withConfigContext(ReportDeviceTable);
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js
index c081b3776c..acbd25f60e 100644
--- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js
@@ -31,6 +31,7 @@ import PolicyReport from './components/Reports/Templates/PolicyReport';
import DeviceStatusReport from './components/Reports/Templates/DeviceStatusReport';
import PolicyReportHome from './pages/Dashboard/Reports/PolicyReportHome';
import ReportDurationItemList from './pages/Dashboard/Reports/ReportDurationItemList';
+import AppNotInstalledDevicesReport from './components/Reports/Templates/AppNotInstalledDevicesReport';
const routes = [
{
@@ -128,6 +129,11 @@ const routes = [
component: DeviceStatusReport,
exact: true,
},
+ {
+ path: '/entgra/reports/app-not-installed',
+ component: AppNotInstalledDevicesReport,
+ exact: true,
+ },
],
},
];
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/PolicyReportHome.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/PolicyReportHome.js
index 9115112dac..10fbb61314 100644
--- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/PolicyReportHome.js
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/PolicyReportHome.js
@@ -146,6 +146,35 @@ class PolicyReportHome extends React.Component {
+
+
+
+
+
+
+
+ App NOT Installed Devices Report
+
+
Report for all device types
+
+
+
+
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/ApplicationList.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/ApplicationList.java
new file mode 100644
index 0000000000..2fe67e10bf
--- /dev/null
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/ApplicationList.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020, 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.beans;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+import org.wso2.carbon.device.mgt.common.app.mgt.Application;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ApplicationList extends BasePaginatedResult{
+
+ private List applicationList = new ArrayList<>();
+
+ @ApiModelProperty(value = "List of applications returned")
+ @JsonProperty("applications")
+ public List getList() {
+ return applicationList;
+ }
+
+ public void setList(List applicationList) {
+ this.applicationList = applicationList;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{\n");
+ sb.append(" count: ").append(getCount()).append(",\n");
+ sb.append(" applications: [").append(applicationList).append("\n");
+ sb.append("]}\n");
+ return sb.toString();
+ }
+}
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 be4cf349d2..a7b96b501a 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
@@ -60,6 +60,7 @@ import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
import org.wso2.carbon.device.mgt.common.search.PropertyMap;
import org.wso2.carbon.device.mgt.common.search.SearchContext;
+import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList;
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.beans.OperationRequest;
@@ -80,7 +81,6 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
-import java.util.Map;
/**
* Device related REST-API. This can be used to manipulated device related details.
@@ -2028,4 +2028,111 @@ public interface DeviceManagementService {
required = true)
@PathParam("id")
int id);
+
+ @GET
+ @Path("/{device-type}/applications")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Getting Details of Applications",
+ notes = "Provides details of installed applications in all the devices enrolled with Entgra IoT Server.",
+ tags = "Device Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:applications")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the list of applications.",
+ response = ApplicationList.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 = 404,
+ message = "Not Found. \n There are no applications.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 500,
+ message = "Error occurred while getting the application data.",
+ response = ErrorResponse.class)
+ })
+ Response getApplications(
+ @ApiParam(
+ name = "device-type",
+ value = "Device type (platform) of the application",
+ required = true)
+ @PathParam("device-type")
+ String deviceType,
+ @ApiParam(
+ name = "offset",
+ value = "The starting pagination index for the complete list of qualified items.",
+ defaultValue = "0")
+ @QueryParam("offset")
+ int offset,
+ @ApiParam(
+ name = "limit",
+ value = "Provide how many device details you require from the starting pagination index/offset.",
+ defaultValue = "10")
+ @QueryParam("limit")
+ int limit);
+
+ @GET
+ @Path("/application/{package-name}/versions")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Getting versions of a given application",
+ notes = "Provides versions of a given application installed in devices of Entgra IoT Server.",
+ tags = "Device Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:applications")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the list of app versions.",
+ 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 = 500,
+ message = "Error occurred while getting the version data.",
+ response = ErrorResponse.class)
+ })
+ Response getAppVersions(
+ @ApiParam(
+ name = "package-name",
+ value = "The package name of the app.",
+ required = true)
+ @PathParam("package-name")
+ String packageName);
}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java
index eee1613381..6a33957f27 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java
@@ -35,6 +35,7 @@ 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.util.Constants;
+import javax.validation.constraints.Size;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -369,4 +370,77 @@ public interface ReportManagementService {
defaultValue = "5")
@QueryParam("limit")
int limit);
+
+ @GET
+ @Path("/devices/{device-type}/{package-name}/not-installed")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Getting Details of Application Not Installed Devices",
+ notes = "Provides details of all the devices enrolled with Entgra IoT Server.",
+ tags = "Device Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the list of devices.",
+ response = DeviceList.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 = 404,
+ message = "Not Found. \n There are no devices.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. " +
+ "\n Server error occurred while fetching the device list.",
+ response = ErrorResponse.class)
+ })
+ Response getAppNotInstalledDevices(
+ @ApiParam(
+ name = "device-type",
+ value = "The device type name, such as ios, android, windows, or fire-alarm.",
+ required = true)
+ @PathParam("device-type")
+ String deviceType,
+ @ApiParam(
+ name = "package-name",
+ value = "The package name of the app.",
+ required = true)
+ @PathParam("package-name")
+ String packageName,
+ @ApiParam(
+ name = "app-version",
+ value = "Version of the app")
+ @QueryParam("app-version") String version,
+ @ApiParam(
+ name = "offset",
+ value = "The starting pagination index for the complete list of qualified items.",
+ defaultValue = "0")
+ @QueryParam("offset")
+ int offset,
+ @ApiParam(
+ name = "limit",
+ value = "Provide how many device details you require from the starting pagination index/offset.",
+ defaultValue = "5")
+ @QueryParam("limit")
+ int limit);
}
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 dbbff69e9f..cf697d57b2 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
@@ -87,6 +87,7 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest;
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
+import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList;
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
@@ -108,7 +109,6 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.DefaultValue;
-import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -1106,4 +1106,58 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
+
+ @GET
+ @Override
+ @Path("/{device-type}/applications")
+ public Response getApplications(
+ @PathParam("device-type") String deviceType,
+ @DefaultValue("0")
+ @QueryParam("offset") int offset,
+ @DefaultValue("10")
+ @QueryParam("limit") int limit) {
+ PaginationRequest request = new PaginationRequest(offset, limit);
+ ApplicationList applicationList = new ApplicationList();
+ request.setDeviceType(deviceType);
+ try {
+ PaginationResult paginationResult = DeviceMgtAPIUtils
+ .getDeviceManagementService()
+ .getApplications(request);
+
+ if (paginationResult.getData().isEmpty()) {
+ return Response.status(Response.Status.OK)
+ .entity("No applications are available under " + deviceType + " platform.").build();
+ } else {
+ applicationList.setList((List) paginationResult.getData());
+ applicationList.setCount(paginationResult.getRecordsTotal());
+ return Response.status(Response.Status.OK).entity(applicationList).build();
+ }
+ } catch (DeviceTypeNotFoundException e) {
+ String msg = "Error occurred while retrieving application list." +
+ " Device type (Application Platform): " + deviceType +
+ "is not valid";
+ log.error(msg);
+ return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
+ } catch (ApplicationManagementException e) {
+ String msg = "Error occurred while retrieving application list";
+ log.error(msg, e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+ }
+ }
+
+ @GET
+ @Path("/application/{package-name}/versions")
+ @Override
+ public Response getAppVersions(
+ @PathParam("package-name") String packageName) {
+ try {
+ List versions = DeviceMgtAPIUtils.getDeviceManagementService()
+ .getAppVersions(packageName);
+ return Response.status(Response.Status.OK).entity(versions).build();
+ } catch (ApplicationManagementException e) {
+ String msg = "Error occurred while retrieving version list for app with package name " + packageName;
+ log.error(msg, e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+ }
+ }
}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java
index 71948ec7cf..212c73177f 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java
@@ -34,6 +34,7 @@ import org.wso2.carbon.device.mgt.jaxrs.service.api.ReportManagementService;
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;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
@@ -197,4 +198,44 @@ public class ReportManagementServiceImpl implements ReportManagementService {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
+
+ @GET
+ @Path("/devices/{device-type}/{package-name}/not-installed")
+ @Override
+ public Response getAppNotInstalledDevices(
+ @PathParam("device-type") String deviceType,
+ @PathParam("package-name") String packageName,
+ @QueryParam("app-version") String version,
+ @DefaultValue("0")
+ @QueryParam("offset") int offset,
+ @DefaultValue("10")
+ @QueryParam("limit") int limit) {
+ try {
+ RequestValidationUtil.validatePaginationParameters(offset, limit);
+ PaginationRequest request = new PaginationRequest(offset, limit);
+ DeviceList devices = new DeviceList();
+ request.setDeviceType(deviceType);
+
+ PaginationResult result = DeviceMgtAPIUtils.getReportManagementService()
+ .getAppNotInstalledDevices(request, packageName, version);
+ if (result.getData().isEmpty()) {
+ return Response.status(Response.Status.OK)
+ .entity("App with package name " + packageName +
+ " is installed in all enrolled devices").build();
+ } else {
+ devices.setList((List) result.getData());
+ devices.setCount(result.getRecordsTotal());
+ return Response.status(Response.Status.OK).entity(devices).build();
+ }
+ } catch (DeviceTypeNotFoundException e) {
+ String msg = "Error occurred while retrieving devices list. Device type: " + deviceType +
+ "is not valid";
+ log.error(msg);
+ return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
+ } catch (ReportManagementException e) {
+ String msg = "Error occurred while retrieving device list";
+ log.error(msg, e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+ }
+ }
}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java
index 700d79d705..a8b24bae30 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java
@@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.common.report.mgt;
import com.google.gson.JsonObject;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
+import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
@@ -59,4 +60,17 @@ public interface ReportManagementService {
*/
PaginationResult getDevicesExpiredByOSVersion(PaginationRequest request)
throws ReportManagementException, DeviceTypeNotFoundException;
+
+ /**
+ * This method is used to get devices which have not installed the app with the given package name
+ *
+ * @param request Request object with device type
+ * @param packageName Package name of the application
+ * @param version Version of the application
+ * @return {@link PaginationResult}
+ * @throws ReportManagementException
+ * @throws DeviceTypeNotFoundException
+ */
+ PaginationResult getAppNotInstalledDevices(PaginationRequest request, String packageName, String version)
+ throws ReportManagementException, DeviceTypeNotFoundException;
}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/ApplicationDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/ApplicationDAO.java
index 1808d652da..a84d409958 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/ApplicationDAO.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/ApplicationDAO.java
@@ -18,6 +18,8 @@
*/
package org.wso2.carbon.device.mgt.core.dao;
+import org.wso2.carbon.device.mgt.common.PaginationRequest;
+import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import java.util.List;
@@ -38,4 +40,25 @@ public interface ApplicationDAO {
throws DeviceManagementDAOException;
List getInstalledApplications(int deviceId, int enrolmentId) throws DeviceManagementDAOException;
+
+ /**
+ * This method is used to get a list of applications installed in all enrolled devices
+ *
+ * @param request Request object with limit and offset
+ * @param tenantId ID of the current tenant
+ * @return List of {@link Application} objects
+ * @throws DeviceManagementDAOException If any database error occured
+ */
+ List getApplications(PaginationRequest request, int tenantId)
+ throws DeviceManagementDAOException;
+
+ /**
+ * This method is used to get a list of app versions when app package name is given.
+ *
+ * @param tenantId ID of the current tenant
+ * @param packageName Package name of the application
+ * @return String list of app versions
+ * @throws DeviceManagementDAOException If any database error occured
+ */
+ List getAppVersions(int tenantId, String packageName) throws DeviceManagementDAOException;
}
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 3de294f8f5..2ffd9d8451 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
@@ -634,4 +634,34 @@ public interface DeviceDAO {
*/
int getCountOfDeviceExpiredByOSVersion(String deviceType, long osBuildDate, int tenantId)
throws DeviceManagementDAOException;
+
+ /**
+ * This method is used to get devices which have not installed the app with the given package name
+ *
+ * @param request Request object with device type
+ * @param tenantId ID of the current tenant
+ * @param packageName Package name of the application
+ * @param version Version of the application
+ * @return A list of device objects
+ * @throws DeviceManagementDAOException Thrown if error occurs while database transactions
+ */
+ List getAppNotInstalledDevices(PaginationRequest request,
+ int tenantId,
+ String packageName,
+ String version) throws DeviceManagementDAOException;
+
+ /**
+ * This method is used to get count if devices which have not installed the app with the given package name
+ *
+ * @param request Request object with device type
+ * @param tenantId ID of the current tenant
+ * @param packageName Package name of the application
+ * @param version Version of the application
+ * @return Device count
+ * @throws DeviceManagementDAOException Thrown if error occurs while database transactions
+ */
+ int getCountOfAppNotInstalledDevices(PaginationRequest request,
+ int tenantId,
+ String packageName,
+ String version) 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/AbstractApplicationDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractApplicationDAOImpl.java
index ef37c22236..31a81e6ca0 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractApplicationDAOImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractApplicationDAOImpl.java
@@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.core.dao.ApplicationDAO;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
@@ -271,6 +272,81 @@ public abstract class AbstractApplicationDAOImpl implements ApplicationDAO {
return applications;
}
+ @Override
+ public List getApplications(PaginationRequest request, int tenantId)
+ throws DeviceManagementDAOException {
+ List applications = new ArrayList<>();
+ Application application;
+ String sql = "Select " +
+ "ID," +
+ " NAME, " +
+ "APP_IDENTIFIER, " +
+ "PLATFORM, " +
+ "CATEGORY, " +
+ "VERSION, " +
+ "TYPE, " +
+ "LOCATION_URL, " +
+ "IMAGE_URL, " +
+ "APP_PROPERTIES, " +
+ "MEMORY_USAGE, " +
+ "IS_ACTIVE, " +
+ "TENANT_ID " +
+ "From DM_APPLICATION " +
+ "WHERE PLATFORM = ? " +
+ "AND TENANT_ID = ? LIMIT ? OFFSET ?";
+ try {
+ Connection conn = this.getConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, request.getDeviceType());
+ stmt.setInt(2, tenantId);
+ stmt.setInt(3, request.getRowCount());
+ stmt.setInt(4, request.getStartIndex());
+ try (ResultSet rs = stmt.executeQuery()) {
+ while (rs.next()) {
+ application = loadApplication(rs);
+ applications.add(application);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ String msg = "SQL Error occurred while retrieving the list of Applications " +
+ "installed in all enrolled devices for device type " + request.getDeviceType() +
+ " under tenant id " + tenantId;
+ log.error(msg, e);
+ throw new DeviceManagementDAOException(msg, e);
+ }
+ return applications;
+ }
+
+ @Override
+ public List getAppVersions(int tenantId, String packageName) throws DeviceManagementDAOException {
+ String sql = "SELECT " +
+ "VERSION " +
+ "FROM DM_APPLICATION " +
+ "WHERE TENANT_ID=? " +
+ "AND APP_IDENTIFIER=?";
+ try {
+ Connection conn = this.getConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setInt(1, tenantId);
+ stmt.setString(2, packageName);
+
+ try (ResultSet rs = stmt.executeQuery()) {
+ List versions = new ArrayList<>();
+ while (rs.next()) {
+ versions.add(rs.getString("VERSION"));
+ }
+ return versions;
+ }
+ }
+ } catch (SQLException e) {
+ String msg = "Error occurred while retrieving information of all " +
+ "registered apps under tenant id " + tenantId;
+ log.error(msg, e);
+ throw new DeviceManagementDAOException(msg, e);
+ }
+ }
+
private Application loadApplication(ResultSet rs) throws DeviceManagementDAOException {
ByteArrayInputStream bais;
ObjectInputStream ois;
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java
index 97db197a1b..81fd4c7ce3 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java
@@ -1894,6 +1894,123 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
}
}
+ @Override
+ public List getAppNotInstalledDevices(
+ PaginationRequest request, int tenantId, String packageName, String version)
+ throws DeviceManagementDAOException {
+ List devices;
+ String deviceType = request.getDeviceType();
+ boolean isVersionProvided = false;
+
+ String sql = "SELECT " +
+ "d.ID AS DEVICE_ID, " +
+ "d.DESCRIPTION,d.NAME AS DEVICE_NAME, " +
+ "t.NAME AS DEVICE_TYPE, " +
+ "d.DEVICE_IDENTIFICATION, " +
+ "e.OWNER, " +
+ "e.OWNERSHIP, " +
+ "e.STATUS, " +
+ "e.DATE_OF_LAST_UPDATE, " +
+ "e.DATE_OF_ENROLMENT, " +
+ "e.ID AS ENROLMENT_ID " +
+ "FROM DM_DEVICE AS d " +
+ "INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
+ "INNER JOIN DM_DEVICE_TYPE AS t ON d.DEVICE_TYPE_ID = t.ID " +
+ "WHERE t.NAME = ? AND e.TENANT_ID = ? AND d.ID " +
+ "NOT IN (SELECT m.DEVICE_ID " +
+ "FROM DM_DEVICE_APPLICATION_MAPPING AS m " +
+ "INNER JOIN DM_APPLICATION AS a ON m.APPLICATION_ID=a.ID " +
+ "WHERE a.APP_IDENTIFIER = ?";
+
+ if (!StringUtils.isBlank(version)) {
+ sql = sql + " AND a.VERSION = ? ";
+ isVersionProvided = true;
+ }
+
+ sql = sql + ") LIMIT ? OFFSET ?";
+
+ try {
+ Connection conn = this.getConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ int paramIdx = 1;
+ stmt.setString(paramIdx++, deviceType);
+ stmt.setInt(paramIdx++, tenantId);
+ stmt.setString(paramIdx++, packageName);
+ if (isVersionProvided) {
+ stmt.setString(paramIdx++, version);
+ }
+ stmt.setInt(paramIdx++, request.getRowCount());
+ stmt.setInt(paramIdx, request.getStartIndex());
+
+ try (ResultSet rs = stmt.executeQuery()) {
+ devices = new ArrayList<>();
+ while (rs.next()) {
+ Device device = DeviceManagementDAOUtil.loadDevice(rs);
+ devices.add(device);
+ }
+ return devices;
+ }
+ }
+ } catch (SQLException e) {
+ String msg = "Error occurred while retrieving information of all " +
+ "registered devices under tenant id " + tenantId;
+ log.error(msg, e);
+ throw new DeviceManagementDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public int getCountOfAppNotInstalledDevices(
+ PaginationRequest request, int tenantId, String packageName, String version)
+ throws DeviceManagementDAOException {
+ String deviceType = request.getDeviceType();
+ boolean isVersionProvided = false;
+
+ String sql = "SELECT " +
+ "COUNT(d.ID) AS DEVICE_COUNT " +
+ "FROM DM_DEVICE AS d " +
+ "INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
+ "INNER JOIN DM_DEVICE_TYPE AS t ON d.DEVICE_TYPE_ID = t.ID " +
+ "WHERE t.NAME = ? AND e.TENANT_ID = ? AND d.ID " +
+ "NOT IN " +
+ "(SELECT m.DEVICE_ID " +
+ "FROM DM_DEVICE_APPLICATION_MAPPING AS m " +
+ "INNER JOIN DM_APPLICATION AS a ON m.APPLICATION_ID=a.ID " +
+ "WHERE a.APP_IDENTIFIER = ?";
+
+ if (!StringUtils.isBlank(version)) {
+ sql = sql + " AND a.VERSION = ? ";
+ isVersionProvided = true;
+ }
+
+ sql = sql + ")";
+
+ try {
+ Connection conn = this.getConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ int paramIdx = 1;
+ stmt.setString(paramIdx++, deviceType);
+ stmt.setInt(paramIdx++, tenantId);
+ stmt.setString(paramIdx++, packageName);
+ if (isVersionProvided) {
+ stmt.setString(paramIdx, version);
+ }
+ try (ResultSet rs = stmt.executeQuery()) {
+ int deviceCount = 0;
+ if (rs.next()) {
+ deviceCount = rs.getInt("DEVICE_COUNT");
+ }
+ return deviceCount;
+ }
+ }
+ } catch (SQLException e) {
+ String msg = "Error occurred while retrieving information of all " +
+ "registered devices under tenant id " + tenantId;
+ log.error(msg, e);
+ throw new DeviceManagementDAOException(msg, e);
+ }
+ }
+
/***
* This method removes records of a given list of devices from the DM_DEVICE_DETAIL table
* @param conn Connection object
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java
index 5d408447f5..06269c2cef 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java
@@ -23,12 +23,15 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.Count;
import org.wso2.carbon.device.mgt.common.Device;
+import org.wso2.carbon.device.mgt.common.app.mgt.Application;
+import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
import org.wso2.carbon.device.mgt.common.report.mgt.ReportManagementService;
+import org.wso2.carbon.device.mgt.core.dao.ApplicationDAO;
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
@@ -39,7 +42,6 @@ import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Calendar;
@@ -54,9 +56,11 @@ public class ReportManagementServiceImpl implements ReportManagementService {
private static final Log log = LogFactory.getLog(ReportManagementServiceImpl.class);
private DeviceDAO deviceDAO;
+ private ApplicationDAO applicationDAO;
public ReportManagementServiceImpl() {
this.deviceDAO = DeviceManagementDAOFactory.getDeviceDAO();
+ this.applicationDAO = DeviceManagementDAOFactory.getApplicationDAO();
}
@Override
@@ -270,4 +274,62 @@ public class ReportManagementServiceImpl implements ReportManagementService {
}
return resultObject;
}
+
+ @Override
+ public PaginationResult getAppNotInstalledDevices(PaginationRequest request, String packageName, String version)
+ throws ReportManagementException, DeviceTypeNotFoundException {
+ PaginationResult paginationResult = new PaginationResult();
+ if(StringUtils.isBlank(packageName)){
+ String msg = "Error, application package name is not given";
+ log.error(msg);
+ throw new ReportManagementException(msg);
+ }
+ try {
+ int tenantId = DeviceManagementDAOUtil.getTenantId();
+ request = DeviceManagerUtil.validateDeviceListPageSize(request);
+
+ String deviceType = request.getDeviceType();
+ DeviceType deviceTypeObj = DeviceManagerUtil.getDeviceType(
+ deviceType, tenantId);
+ if (deviceTypeObj == null) {
+ String msg = "Error, device of type: " + deviceType + " does not exist";
+ log.error(msg);
+ throw new DeviceTypeNotFoundException(msg);
+ }
+
+ try {
+ DeviceManagementDAOFactory.openConnection();
+ List devices = deviceDAO.getAppNotInstalledDevices(
+ request,
+ tenantId,
+ packageName,
+ version
+ );
+ paginationResult.setData(devices);
+ int deviceCount = deviceDAO.getCountOfAppNotInstalledDevices(
+ request,
+ tenantId,
+ packageName,
+ version);
+ paginationResult.setRecordsTotal(deviceCount);
+ return paginationResult;
+ } catch (SQLException e) {
+ String msg = "Error occurred while opening a connection " +
+ "to the data source";
+ log.error(msg, e);
+ throw new ReportManagementException(msg, e);
+ } finally {
+ DeviceManagementDAOFactory.closeConnection();
+ }
+
+ } catch (DeviceManagementException e) {
+ String msg = "Error occurred while validating device list page size";
+ log.error(msg, e);
+ throw new ReportManagementException(msg, e);
+ } catch (DeviceManagementDAOException e) {
+ String msg = "Error occurred while retrieving Tenant ID";
+ log.error(msg, e);
+ throw new ReportManagementException(msg, e);
+ }
+ }
}
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 346264755e..15667409f7 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
@@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import org.wso2.carbon.device.mgt.common.MonitoringOperation;
import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
+import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
@@ -855,4 +856,23 @@ public interface DeviceManagementProviderService {
*/
PaginationResult getAppSubscribedDevices(int offsetValue, int limitValue,
List devicesIds, String status) throws DeviceManagementException;
+
+ /**
+ * This method is used to get a list of applications installed in all enrolled devices
+ *
+ * @param request Request object with limit and offset
+ * @return {@link PaginationResult}
+ * @throws ApplicationManagementException if any service level or DAO level error occurs.
+ */
+ PaginationResult getApplications(PaginationRequest request)
+ throws ApplicationManagementException, DeviceTypeNotFoundException;
+
+ /**
+ * This method is used to get a list of app versions when app package name is given.
+ *
+ * @param packageName Package name of the application
+ * @return String list of app versions
+ * @throws ApplicationManagementException if any service level or DAO level error occurs.
+ */
+ List getAppVersions(String packageName) throws ApplicationManagementException;
}
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 a5da653b0f..60ebdb7ab6 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
@@ -63,6 +63,7 @@ import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import org.wso2.carbon.device.mgt.common.DevicePropertyNotification;
import org.wso2.carbon.device.mgt.common.DeviceEnrollmentInfoNotification;
import org.wso2.carbon.device.mgt.common.DeviceNotification;
+import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
@@ -114,6 +115,7 @@ import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.DeviceTypeDAO;
import org.wso2.carbon.device.mgt.core.dao.EnrollmentDAO;
+import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO;
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsMgtDAOException;
@@ -3967,6 +3969,76 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
return paginationResult;
}
+ @Override
+ public PaginationResult getApplications(PaginationRequest request)
+ throws ApplicationManagementException, DeviceTypeNotFoundException {
+ PaginationResult paginationResult = new PaginationResult();
+ try {
+ int tenantId = DeviceManagementDAOUtil.getTenantId();
+ request = DeviceManagerUtil.validateDeviceListPageSize(request);
+
+ String deviceType = request.getDeviceType();
+ DeviceType deviceTypeObj = DeviceManagerUtil.getDeviceType(
+ deviceType, tenantId);
+ if (deviceTypeObj == null) {
+ String msg = "Error, device of type (application platform): " + deviceType + " does not exist";
+ log.error(msg);
+ throw new DeviceTypeNotFoundException(msg);
+ }
+
+ try {
+ DeviceManagementDAOFactory.openConnection();
+ List applicationList = applicationDAO.getApplications(
+ request,
+ tenantId
+ );
+ paginationResult.setData(applicationList);
+ paginationResult.setRecordsTotal(applicationList.size());
+ return paginationResult;
+ } catch (SQLException e) {
+ String msg = "Error occurred while opening a connection " +
+ "to the data source";
+ log.error(msg, e);
+ throw new ApplicationManagementException(msg, e);
+ } finally {
+ DeviceManagementDAOFactory.closeConnection();
+ }
+
+ } catch (DeviceManagementException e) {
+ String msg = "Error occurred while validating device list page size";
+ log.error(msg, e);
+ throw new ApplicationManagementException(msg, e);
+ } catch (DeviceManagementDAOException e) {
+ String msg = "Error occurred while retrieving Tenant ID";
+ log.error(msg, e);
+ throw new ApplicationManagementException(msg, e);
+ }
+ }
+
+ @Override
+ public List getAppVersions(String packageName)
+ throws ApplicationManagementException {
+ try {
+ DeviceManagementDAOFactory.openConnection();
+ List versions = applicationDAO.getAppVersions(
+ DeviceManagementDAOUtil.getTenantId(),
+ packageName
+ );
+ return versions;
+ } catch (SQLException e) {
+ String msg = "Error occurred while opening a connection " +
+ "to the data source";
+ log.error(msg, e);
+ throw new ApplicationManagementException(msg, e);
+ } catch (DeviceManagementDAOException e) {
+ String msg = "Error occurred while retrieving Tenant ID";
+ log.error(msg, e);
+ throw new ApplicationManagementException(msg, e);
+ } finally {
+ DeviceManagementDAOFactory.closeConnection();
+ }
+ }
+
/**
* Wrap the device configuration data into DeviceConfiguration bean
* @param device Device queried using the properties