Compare commits

Invalid templates have been ignored

1 invalid template(s) found pull_request_template.md: frontmatter must start with a separator line

...

104 Commits

Author SHA1 Message Date
builder 0950520514 [maven-release-plugin] prepare for next development iteration
2 years ago
builder 790537773c [maven-release-plugin] prepare release v4.2.0
2 years ago
Entgra Builder 82013715c9 [maven-release-plugin] prepare for next development iteration
2 years ago
Pahansith Gunathilake 395063ca3b Merge branch 'app-uninstallation' into 'support-4.1.15'
2 years ago
navodzoysa 15edc3852c Add Windows app uninstallation feature
2 years ago
Pahansith Gunathilake c0a00e2207 Merge branch 'windows-perm' into 'support-4.1.15'
3 years ago
navodzoysa b50db4f93f Add missing permission scopes for windows device operations
3 years ago
Charitha Goonetilleke 7cf8ff8516 Fix incorrect response handling logic
3 years ago
Charitha Goonetilleke 5ed5754991 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Charitha Goonetilleke 367a87697a Allow retrieving activities for multiple device ids
3 years ago
Charitha Goonetilleke ee00a00437 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Pahansith Gunathilake 786f247adc Revert "Fix test failures"
3 years ago
Pahansith Gunathilake 23dcac5fa7 Revert "Add timestamp issue fixes"
3 years ago
Pahansith Gunathilake 10b8e0de53 Fix test failures
3 years ago
Pahansith Gunathilake 4691b1d7bd Add timestamp issue fixes
3 years ago
Pahansith Gunathilake cf4f45c89d Change time filtering DB column
3 years ago
Pahansith Gunathilake 007b309c71 Add time duration filtering to activities EP
3 years ago
Pahansith Gunathilake 86495d9ba5 Add missing ios scopes into mdm-ui-config.xml
3 years ago
Pahansith Gunathilake b7a098ccf0 Merge branch 'support-4.1.15' of gitlab.com:entgra-support/support-carbon-device-mgt into support-4.1.15
3 years ago
Pahansith Gunathilake 265241ecfc Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
lasantha a2ca28dfcb Add app subscribing feature improvement
3 years ago
inoshperera 852fa3ad39 Remove duplicate app subscriptions
3 years ago
Charitha Goonetilleke a0c953d027 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Charitha Goonetilleke bb8ffe0f5e Allow users with CDM Admin permission to retrieve activities
3 years ago
Charitha Goonetilleke 58959705c6 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Charitha Goonetilleke 73571107b1 Add missing initiated by field in operation retrieval
3 years ago
Charitha Goonetilleke 1d3f6fdac9 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Saad Sahibjan b9d889cad6 Update device property table in dm db when updating properties
3 years ago
Charitha Goonetilleke 4bb356cae1 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Saad Sahibjan 4296d874c5 Add new device status ASSIGNED
3 years ago
Pahansith Gunathilake b213742642 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Pahansith bf81f36fa6 Fix error while adding app install to a device group
3 years ago
Charitha Goonetilleke 51e1bc002c Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Saad Sahibjan 0613396eff Fix having UPPER in query of groups retrieval
3 years ago
Charitha Goonetilleke bc4e76eed7 Merge remote-tracking branch 'support/support-4.1.15' into support-4.1.15
3 years ago
Charitha Goonetilleke 41cadeb517 Fix location update timestamp overwrite issue
3 years ago
Pahansith Gunathilake 6dbc6dd0a1 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Muhammad Rashad 5795db1360 Block Uninstall Policy Feature
3 years ago
Vigneshan Seshamany 36f132d363 Improve refresh token handling mechanism
3 years ago
Vigneshan Seshamany 4d2f598529 Modify login cache implementatation with LRU cache
3 years ago
Saad Sahibjan aea460c0d5 Move slash to a constant
3 years ago
Saad Sahibjan 996309f063 Update all children groups when updating a group
3 years ago
Saad Sahibjan dabc0dc8ec Fix test cases related to hierarchical group changes
3 years ago
Saad Sahibjan a12b942d86 Add and update api layer related to hierarchical changes
3 years ago
Saad Sahibjan 90d8b94455 Add and update service layer related to hierarchical changes
3 years ago
Saad Sahibjan 3e310d4dbf Add and update dao layer methods related to hierarchical changes
3 years ago
Saad Sahibjan 5bc39dd7dc Update device group and request beans classes to have new variable
3 years ago
Saad Sahibjan abefba8b44 Add PARENT_PATH column to DM_GROUP table
3 years ago
Charitha Goonetilleke fc34595cfd Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Vigneshan Seshamany cff28b4d88 Improve refresh token handling mechanism
3 years ago
Vigneshan Seshamany d85d2c2272 Modify login cache implementatation with LRU cache
3 years ago
navodzoysa 2b4ba189c7 Fix date range shown in reverse in MDM Reports
3 years ago
Dharmakeerthi Lasantha bb4780f58a Revert "Merge branch 'master' into 'master'"
3 years ago
lasantha a8ec609bb0 Improve App subscribing flow
3 years ago
Kaveesha 07b779323c Add API for get app subscribed device list from a subscription group
3 years ago
Charitha Goonetilleke 2b9ef49a52 Update .gitlab-ci.yml
3 years ago
Kaveesha 06eb836f11 Update DM_DEVICE_INFO table
3 years ago
Pahansith Gunathilake b193627c87 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Pahansith Gunathilake 963fb6d628 Merge branch 'support-4.1.15' into 'support-4.1.15'
3 years ago
Farheen99 fc67a3eee8 Add a query to get the applications sort according to latest timestamp order
3 years ago
sandaru 4810ceb0d0 Add default sim update operation scope
3 years ago
Charitha Goonetilleke 25ca3d22e8 Add geo view API
3 years ago
Kaveesha bcab5f3bfe Update item bean class to get documentation link from xml
3 years ago
Pahansith Gunathilake c23d0026ea Merge branch 'support-4.1.15-new' into 'support-4.1.15'
3 years ago
Farheen99 726d37847f Add code changes to read a new xml element named scope from android.xml file
3 years ago
MalshaPiumini 0c3185f7d6 Increase session time for sso and non-sso login.
3 years ago
inoshperera 83047b497f Support AE with QR code based enrollment
3 years ago
Vigneshan Seshamany f725151e91 Fix session expire issue during sso authorization
3 years ago
Pahansith b68d24cec4 Add session scope handler
3 years ago
MalshaPiumini 12ebc03d12 Increase session time for sso and non-sso login.
4 years ago
Charitha Goonetilleke 9419eef7f9 Add geo view API
4 years ago
inoshperera 554e20e389 Support AE with QR code based enrollment
4 years ago
Kaveesha 233f09a676 Update item bean class to get documentation link from xml
4 years ago
Vigneshan Seshamany 19268aaa5b Fix session expire issue during sso authorization
4 years ago
Pahansith f64007bcc8 Add session scope handler
4 years ago
Farheen99 3816e09b1d Add a query to get the applications sort according to latest timestamp order
4 years ago
Charitha Goonetilleke e824091396 Consider not now operations as pending
4 years ago
Inosh Perara 14e5ceb5f2 Merge branch 'support-4.1.15' into 'support-4.1.15'
4 years ago
MalshaPiumini fd6947fffc Formatting the SQL query.
4 years ago
MalshaPiumini 3b09a43d85 Solved test case failure.
4 years ago
MalshaPiumini d16a7a7fb8 Added device filter using serial number.
4 years ago
Charitha Goonetilleke a16c82bebd Allow dynamic control of operations
4 years ago
Charitha Goonetilleke c5e26804dc Add NOTNOW status to activity result
4 years ago
MalshaPiumini fc67e8b7aa Added new filter in subscription details page
4 years ago
MalshaPiumini 4664bb24e5 Added validations
4 years ago
MalshaPiumini 82ebe79f2d Code modified
4 years ago
MalshaPiumini f3d1ad4f0d Device search in store subscription details page
4 years ago
MalshaPiumini 8793b413af Device search in store uninstall modal
4 years ago
Pahansith 9b8894240e Add DAO fix for app schedule subscription
4 years ago
Inosh Perara 34465294f5 Merge branch 'support-4.1.15' into 'support-4.1.15'
4 years ago
Pahansith e50da86bdb Fix schedule install DAO issue
4 years ago
Pahansith cfeeb85387 Fix app schedule installation issue in single node
4 years ago
Vigneshan Seshamany 555d2398fe Fix token refresh issue
4 years ago
Pahansith Gunathilake 6ce53f55b1 Merge branch 'support-4.1.15' into 'support-4.1.15'
4 years ago
Charitha Goonetilleke 1b1085fda8 Fix executing policy monitoring continuously
4 years ago
Pahansith Gunathilake ae92a985fa Merge branch 'support-4.1.15' into 'support-4.1.15'
4 years ago
Vigneshan Seshamany 143d62efd5 Add login cache for sso and non-sso flow
4 years ago
Farheen Boosary 6a7099f97f Handle execution of queries contain IN clause with empty array
4 years ago
inoshperera 4394ceaeed Add enterprise API tag to allowed tags
4 years ago
Inosh Perara 836a6e8001 Merge branch 'support-4.1.15' into 'support-4.1.15'
4 years ago
inoshperera 573d1f2e6c Add enterprise API tag to allowed tags
4 years ago
Pahansith e6257482de Fix error in unmanaged app uninstall
4 years ago
inoshperera 190c896a86 Fix wrong zip codes from agents persisting
4 years ago
inoshperera 0e7c445a56 Add token expiry time to QR payload
4 years ago

@ -25,3 +25,4 @@ deploy:
- mvn $MAVEN_CLI_OPTS deploy -Dmaven.test.skip=true
only:
- master@entgra/carbon-device-mgt
- kernel-4.6.x@entgra/carbon-device-mgt

@ -22,13 +22,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.annotations</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Annotations</name>
<description>WSO2 Carbon - API Management Custom Annotation Module</description>

@ -21,12 +21,12 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<artifactId>org.wso2.carbon.apimgt.application.extension.api</artifactId>
<packaging>war</packaging>
<name>WSO2 Carbon - API Application Management API</name>

@ -48,6 +48,7 @@ public class APIUtil {
private static final String DEFAULT_APP_MGT_SUB_MGT_TAG = "subscription_management";
private static final String DEFAULT_ANALYTICS_ARTIFACT_TAG = "analytics_artifacts_management";
private static final String DEFAULT_TRANSPORT_MGT_TAG = "transport_management";
private static final String DEFAULT_ENTERPRISE_TAG= "androidforwork";
public static final String PERMISSION_PROPERTY_NAME = "name";
@ -118,6 +119,11 @@ public class APIUtil {
allowedApisTags.add(DEFAULT_APP_MGT_SUB_MGT_TAG);
allowedApisTags.add(DEFAULT_ANALYTICS_ARTIFACT_TAG);
allowedApisTags.add(DEFAULT_TRANSPORT_MGT_TAG);
// In an environment only super tenant should be capable of calling this API tag
if (PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() ==
MultitenantConstants.SUPER_TENANT_ID) {
allowedApisTags.add(DEFAULT_ENTERPRISE_TAG);
}
return allowedApisTags;
}

@ -22,12 +22,12 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<artifactId>org.wso2.carbon.apimgt.application.extension</artifactId>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Application Management</name>

@ -21,6 +21,7 @@ package org.wso2.carbon.apimgt.application.extension;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.apimgt.integration.client.store.StoreClient;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
/**
* This comprise on operation that is been done with api manager from CDMF. This service needs to be implemented in APIM.
@ -88,7 +89,7 @@ public interface APIManagementProviderService {
* @throws APIManagerException if error occurred while getting the access token for given scopes,
* validity period etc.
*/
String getAccessToken(String scopes, String[] tags, String applicationName, String tokenType, String validityPeriod)
AccessTokenInfo getAccessToken(String scopes, String[] tags, String applicationName, String tokenType, String validityPeriod)
throws APIManagerException;
}

@ -238,7 +238,7 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
}
@Override
public String getAccessToken(String scopes, String[] tags, String applicationName, String tokenType,
public AccessTokenInfo getAccessToken(String scopes, String[] tags, String applicationName, String tokenType,
String validityPeriod) throws APIManagerException {
try {
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(true);
@ -262,7 +262,7 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
.getAccessToken(clientCredentials.getConsumerKey(), clientCredentials.getConsumerSecret(), user,
scopes);
return accessTokenForAdmin.getAccessToken();
return accessTokenForAdmin;
} catch (JWTClientException e) {
String msg = "JWT Error occurred while registering Application to get access token.";
log.error(msg, e);

@ -21,13 +21,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.handlers</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Security Handler Component</name>
<description>WSO2 Carbon - API Management Security Handler Module</description>

@ -13,13 +13,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.integration.client</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Integration Client</name>
<description>WSO2 Carbon - API Management Integration Client</description>

@ -13,13 +13,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.integration.generated.client</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Integration Generated Client</name>
<description>WSO2 Carbon - API Management Integration Client</description>

@ -22,13 +22,13 @@
<parent>
<artifactId>apimgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.apimgt.webapp.publisher</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - API Management Webapp Publisher</name>
<description>WSO2 Carbon - API Management Webapp Publisher</description>

@ -22,13 +22,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apimgt-extensions</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WSO2 Carbon - API Management Extensions Component</name>
<url>http://wso2.org</url>

@ -3,13 +3,13 @@
<parent>
<artifactId>application-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.addons</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<name>WSO2 Carbon - Application Management Add-Ons</name>
<description>WSO2 Carbon - Application Management Add-Ons</description>
<url>https://entgra.io</url>

@ -22,13 +22,13 @@
<parent>
<artifactId>application-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.api</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>WSO2 Carbon - Application Management API</name>
<description>WSO2 Carbon - Application Management API</description>

@ -21,13 +21,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.common</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Application Management Common</name>
<description>WSO2 Carbon - Application Management Common</description>

@ -24,7 +24,7 @@ import java.sql.Timestamp;
public class DeviceSubscriptionData {
private String action;
private Timestamp actionTriggeredTimestamp;
private long actionTriggeredTimestamp;
private String actionTriggeredBy;
private String actionType;
private String status;
@ -38,11 +38,11 @@ public class DeviceSubscriptionData {
this.action = action;
}
public Timestamp getActionTriggeredTimestamp() {
public long getActionTriggeredTimestamp() {
return actionTriggeredTimestamp;
}
public void setActionTriggeredTimestamp(Timestamp actionTriggeredTimestamp) {
public void setActionTriggeredTimestamp(long actionTriggeredTimestamp) {
this.actionTriggeredTimestamp = actionTriggeredTimestamp;
}

@ -69,7 +69,7 @@ public class ScheduledSubscriptionDTO {
/**
* Scheduled time of subscription.
*/
private LocalDateTime scheduledAt;
private long scheduledAt;
/**
* Username of the scheduler.
@ -86,7 +86,7 @@ public class ScheduledSubscriptionDTO {
}
public ScheduledSubscriptionDTO(String taskName, String applicationUUID, LocalDateTime scheduledAt,
public ScheduledSubscriptionDTO(String taskName, String applicationUUID, long scheduledAt,
List<?> subscriberList, String scheduledBy) {
this.taskName = taskName;
this.applicationUUID = applicationUUID;
@ -135,11 +135,11 @@ public class ScheduledSubscriptionDTO {
this.status = status;
}
public LocalDateTime getScheduledAt() {
public long getScheduledAt() {
return scheduledAt;
}
public void setScheduledAt(LocalDateTime scheduledAt) {
public void setScheduledAt(long scheduledAt) {
this.scheduledAt = scheduledAt;
}

@ -22,32 +22,54 @@ import org.wso2.carbon.device.application.mgt.common.dto.ScheduledSubscriptionDT
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.SubscriptionManagementException;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
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.App;
import java.util.List;
import java.util.Properties;
/**
* This interface manages all the operations related with ApplicationDTO Subscription.
*/
public interface SubscriptionManager {
/**
* Performs bulk subscription operation for a given application and a subscriber list.
*
* @param applicationUUID UUID of the application to subscribe/unsubscribe
* @param params list of subscribers. This list can be of either
* {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is equal
* to DEVICE or
* {@link String} if {@param subType} is USER, ROLE or GROUP
* @param subType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code> {@see {
* @param action subscription action. E.g. <code>INSTALL/UNINSTALL</code> {@see {
* @param params list of subscribers.
* This list can be of either {@link DeviceIdentifier} if {@param subType} is equal to
* DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
* @param subType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code>
* @param action subscription action. E.g. <code>INSTALL/UNINSTALL</code>
* @param <T> generic type of the method.
* @param properties Application properties that need to be sent with operation payload to the device
* @return {@link ApplicationInstallResponse}
* @throws ApplicationManagementException if error occurs when subscribing to the given application
*/
<T> ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List<T> params, String subType,
String action, Properties properties)
throws ApplicationManagementException;
/**
* Performs bulk subscription operation for a given application and a subscriber list.
* @param applicationUUID UUID of the application to subscribe/unsubscribe
* @param params list of subscribers.
* This list can be of either {@link DeviceIdentifier} if {@param subType} is equal to
* DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
* @param subType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code>
* @param action subscription action. E.g. <code>INSTALL/UNINSTALL</code>
* @param <T> generic type of the method.
* @param properties Application properties that need to be sent with operation payload to the device
* @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
* already subscribed application successfully.
* @return {@link ApplicationInstallResponse}
* @throws ApplicationManagementException if error occurs when subscribing to the given application
* @link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
* @link org.wso2.carbon.device.application.mgt.common.SubAction}}
*/
<T> ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List<T> params, String subType,
String action) throws ApplicationManagementException;
String action, Properties properties,
boolean isOperationReExecutingDisabled)
throws ApplicationManagementException;
/**
* Create an entry related to the scheduled task in the database.
@ -116,25 +138,22 @@ public interface SubscriptionManager {
* This is used in enterprise app installing policy.
*
* @param deviceIdentifier Device identifiers
* @param releaseUUID UUIs of applicatios
* @param apps Applications
* @throws ApplicationManagementException if error occurred while installing given applications into the given
* device
*/
void installAppsForDevice(DeviceIdentifier deviceIdentifier, List<String> releaseUUID)
void installAppsForDevice(DeviceIdentifier deviceIdentifier, List<App> apps)
throws ApplicationManagementException;
/***
* This method used to get the app id ,device ids and pass them to DM service method.
*
* @param appUUID UUID of the application release.
* @param offsetValue offset value for get paginated request.
* @param limitValue limit value for get paginated request.
* @param status status of the devices.
* @param request paginated request object.
* @return deviceDetails - device details for given application release.
* @throws {@link ApplicationManagementException} Exception of the application management
*/
PaginationResult getAppInstalledDevices(int offsetValue, int limitValue, String appUUID,
List<String> status) throws ApplicationManagementException;
PaginationResult getAppInstalledDevices(PaginationRequest request, String appUUID) throws ApplicationManagementException;
/***
* This method used to get category details.
@ -152,14 +171,27 @@ public interface SubscriptionManager {
/**
* This method is responsible to provide application subscription data for given application release UUID.
*
* @param offsetValue offset
* @param limitValue limit
* @param request paginated request object.
* @param actionStatus status of the operation.
* @param action action related to the device.
* @param appUUID application release UUID
* @return {@link PaginationResult}
* @throws ApplicationManagementException if offset or limit contains incorrect values, if it couldn't find an
* application release for given UUID, if an error occurred while getting device details of subscribed device ids,
* if an error occurred while getting subscription details of given application release UUID.
*/
PaginationResult getAppSubscriptionDetails(int offsetValue, int limitValue, String appUUID)
PaginationResult getAppSubscriptionDetails(PaginationRequest request, String appUUID, String actionStatus, String action)
throws ApplicationManagementException;
/***
* This method is responsible to provide application subscription devices data for given application release UUID.
* @param request PaginationRequest object holding the data for pagination
* @param appUUID UUID of the application release.
* @param subType subscription type of the application(eg: GROUP, USER, ...)
* @param subTypeName subscription type name of the application (Name of the group, Name of the user, ...).
* @return {@link PaginationResult} pagination result of the category details.
* @throws {@link ApplicationManagementException} Exception of the application management
*/
PaginationResult getAppInstalledSubscribeDevices(PaginationRequest request, String appUUID, String subType,
String subTypeName) throws ApplicationManagementException;
}

@ -21,13 +21,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.core</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Application Management Core</name>
<description>WSO2 Carbon - Application Management Core</description>

@ -81,7 +81,7 @@ public interface SubscriptionDAO {
void addGroupSubscriptions(int tenantId, String subscribedBy, List<String> groups, int releaseId, String action)
throws ApplicationManagementDAOException;
List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId) throws
List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId, String actionStatus, String action) throws
ApplicationManagementDAOException;
Map<Integer, DeviceSubscriptionDTO> getDeviceSubscriptions(List<Integer> deviceIds, int appReleaseId, int tenantId)
@ -124,7 +124,7 @@ public interface SubscriptionDAO {
* @param scheduledBy username of the user who scheduled the subscription
* @throws ApplicationManagementDAOException if error occurred while updating the entry
*/
boolean updateScheduledSubscription(int id, LocalDateTime scheduledAt, String scheduledBy)
boolean updateScheduledSubscription(int id, long scheduledAt, String scheduledBy)
throws ApplicationManagementDAOException;
/**
@ -228,4 +228,16 @@ public interface SubscriptionDAO {
throws ApplicationManagementDAOException;
int getSubscribedGroupCount(int appReleaseId, int tenantId) throws ApplicationManagementDAOException;
/**
* This method is used to get the details of subscribed groups
*
* @param tenantId id of the current tenant
* @param appReleaseId id of the application release..
* @param subtype application subscribed type.
* @return subscribedDevices - list of app subscribed devices under the subtype.
* @throws {@link ApplicationManagementDAOException} if connections establishment fails.
*/
List<Integer> getAppSubscribedDevicesForGroups(int appReleaseId, String subtype, int tenantId)
throws ApplicationManagementDAOException;
}

@ -24,6 +24,7 @@ import org.wso2.carbon.device.application.mgt.common.AppLifecycleState;
import org.wso2.carbon.device.application.mgt.common.dto.ApplicationDTO;
import org.wso2.carbon.device.application.mgt.common.dto.CategoryDTO;
import org.wso2.carbon.device.application.mgt.common.Filter;
import org.wso2.carbon.device.application.mgt.common.dto.ReviewDTO;
import org.wso2.carbon.device.application.mgt.common.dto.TagDTO;
import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException;
import org.wso2.carbon.device.application.mgt.core.dao.ApplicationDAO;
@ -133,7 +134,8 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
+ "AP_APP_RELEASE.SUPPORTED_OS_VERSIONS AS RELEASE_SUP_OS_VERSIONS, "
+ "AP_APP_RELEASE.RATING AS RELEASE_RATING, "
+ "AP_APP_RELEASE.CURRENT_STATE AS RELEASE_CURRENT_STATE, "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT, "
+ "NEW_AP_APP_LIFECYCLE_STATE.UPDATED_AT AS LATEST_UPDATE "
+ "FROM AP_APP "
+ "INNER JOIN AP_APP_RELEASE ON "
+ "AP_APP.ID = AP_APP_RELEASE.AP_APP_ID "
@ -180,7 +182,17 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
if (filter.getLimit() != -1) {
sql += "LIMIT ? OFFSET ? ";
}
sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
sql += ") AS app_data ON app_data.ID = AP_APP.ID "
+ "INNER JOIN ("
+ "SELECT AP_APP_LIFECYCLE_STATE.UPDATED_AT, AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "FROM AP_APP_LIFECYCLE_STATE WHERE AP_APP_LIFECYCLE_STATE.ID "
+ "IN(SELECT MAX(AP_APP_LIFECYCLE_STATE.ID) "
+ "FROM AP_APP_LIFECYCLE_STATE "
+ "GROUP BY AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID)) AS NEW_AP_APP_LIFECYCLE_STATE "
+ "ON AP_APP_RELEASE.ID = NEW_AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "WHERE AP_APP.TENANT_ID = ? "
+ "ORDER BY AP_APP.ID, LATEST_UPDATE DESC";
try {
Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -491,6 +503,9 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
+ " from the database");
}
try {
if (packageNames.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
int index = 1;
StringJoiner joiner = new StringJoiner(",",
@ -826,9 +841,12 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
log.debug("Request received in DAO Layer to get category ids for given category names");
}
try {
List<Integer> tagIds = new ArrayList<>();
if (categoryNames.isEmpty()) {
return tagIds;
}
Connection conn = this.getDBConnection();
int index = 1;
List<Integer> tagIds = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT AP_APP_CATEGORY.ID AS ID FROM AP_APP_CATEGORY WHERE AP_APP_CATEGORY.CATEGORY IN (",
") AND TENANT_ID = ?");
@ -1117,9 +1135,12 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
log.debug("Request received in DAO Layer to get tag ids for given tag names");
}
try {
List<Integer> tagIds = new ArrayList<>();
if (tagNames.isEmpty()) {
return tagIds;
}
Connection conn = this.getDBConnection();
int index = 1;
List<Integer> tagIds = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT AP_APP_TAG.ID AS ID FROM AP_APP_TAG WHERE AP_APP_TAG.TAG IN (",
") AND TENANT_ID = ?");

@ -80,7 +80,8 @@ public class OracleApplicationDAOImpl extends GenericApplicationDAOImpl {
+ "AP_APP_RELEASE.SUPPORTED_OS_VERSIONS AS RELEASE_SUP_OS_VERSIONS, "
+ "AP_APP_RELEASE.RATING AS RELEASE_RATING, "
+ "AP_APP_RELEASE.CURRENT_STATE AS RELEASE_CURRENT_STATE, "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT, "
+ "NEW_AP_APP_LIFECYCLE_STATE.UPDATED_AT AS LATEST_UPDATE "
+ "FROM AP_APP "
+ "INNER JOIN AP_APP_RELEASE ON "
+ "AP_APP.ID = AP_APP_RELEASE.AP_APP_ID "
@ -125,7 +126,17 @@ public class OracleApplicationDAOImpl extends GenericApplicationDAOImpl {
if (filter.getLimit() != -1) {
sql += "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";
}
sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
sql += ") AS app_data ON app_data.ID = AP_APP.ID "
+ "INNER JOIN ("
+ "SELECT AP_APP_LIFECYCLE_STATE.UPDATED_AT, AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "FROM AP_APP_LIFECYCLE_STATE WHERE AP_APP_LIFECYCLE_STATE.ID "
+ "IN(SELECT MAX(AP_APP_LIFECYCLE_STATE.ID) "
+ "FROM AP_APP_LIFECYCLE_STATE "
+ "GROUP BY AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID)) AS NEW_AP_APP_LIFECYCLE_STATE "
+ "ON AP_APP_RELEASE.ID = NEW_AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "WHERE AP_APP.TENANT_ID = ? "
+ "ORDER BY AP_APP.ID, LATEST_UPDATE DESC";
try {
Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {

@ -79,7 +79,8 @@ public class SQLServerApplicationDAOImpl extends GenericApplicationDAOImpl {
+ "AP_APP_RELEASE.SUPPORTED_OS_VERSIONS AS RELEASE_SUP_OS_VERSIONS, "
+ "AP_APP_RELEASE.RATING AS RELEASE_RATING, "
+ "AP_APP_RELEASE.CURRENT_STATE AS RELEASE_CURRENT_STATE, "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT "
+ "AP_APP_RELEASE.RATED_USERS AS RATED_USER_COUNT, "
+ "NEW_AP_APP_LIFECYCLE_STATE.UPDATED_AT AS LATEST_UPDATE "
+ "FROM AP_APP "
+ "INNER JOIN AP_APP_RELEASE ON "
+ "AP_APP.ID = AP_APP_RELEASE.AP_APP_ID "
@ -124,7 +125,17 @@ public class SQLServerApplicationDAOImpl extends GenericApplicationDAOImpl {
if (filter.getLimit() != -1) {
sql += "ORDER BY ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";
}
sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
sql += ") AS app_data ON app_data.ID = AP_APP.ID "
+ "INNER JOIN ("
+ "SELECT AP_APP_LIFECYCLE_STATE.UPDATED_AT, AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "FROM AP_APP_LIFECYCLE_STATE WHERE AP_APP_LIFECYCLE_STATE.ID "
+ "IN(SELECT MAX(AP_APP_LIFECYCLE_STATE.ID) "
+ "FROM AP_APP_LIFECYCLE_STATE "
+ "GROUP BY AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID)) AS NEW_AP_APP_LIFECYCLE_STATE "
+ "ON AP_APP_RELEASE.ID = NEW_AP_APP_LIFECYCLE_STATE.AP_APP_RELEASE_ID "
+ "WHERE AP_APP.TENANT_ID = ? "
+ "ORDER BY AP_APP.ID, LATEST_UPDATE DESC";
try {
Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {

@ -564,6 +564,11 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
public List<ApplicationReleaseDTO> getReleaseByPackages(List<String> packages, int tenantId) throws
ApplicationManagementDAOException {
List<ApplicationReleaseDTO> releaseDTOs = new ArrayList<>();
if (packages.isEmpty()) {
return releaseDTOs;
}
String sql = "SELECT "
+ "AR.ID AS RELEASE_ID, "
+ "AR.DESCRIPTION AS RELEASE_DESCRIPTION, "
@ -600,7 +605,6 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
}
statement.setInt(index, tenantId);
try (ResultSet resultSet = statement.executeQuery()) {
List<ApplicationReleaseDTO> releaseDTOs = new ArrayList<>();
while (resultSet.next()) {
releaseDTOs.add(DAOUtil.constructAppReleaseDTO(resultSet));
}

@ -110,6 +110,9 @@ public class GenericReviewDAOImpl extends AbstractDAOImpl implements ReviewDAO {
+ "application. Commenting user: " + username + " and tenant-id: " + tenantId);
}
try {
if (appReleaseIds.isEmpty()) {
return false;
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT rv.ID FROM AP_APP_REVIEW rv WHERE rv.AP_APP_RELEASE_ID IN (",
@ -283,6 +286,9 @@ public class GenericReviewDAOImpl extends AbstractDAOImpl implements ReviewDAO {
log.debug("DAO request is received to Get all active application reviews.");
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT " + "AP_APP_REVIEW.ID AS ID, "
@ -336,6 +342,9 @@ public class GenericReviewDAOImpl extends AbstractDAOImpl implements ReviewDAO {
log.debug("DAO request is received to Get all active application reviews of user " + username);
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT "
@ -473,6 +482,10 @@ public class GenericReviewDAOImpl extends AbstractDAOImpl implements ReviewDAO {
log.debug("DAO request is received to Get all application rating values of an application.");
}
try {
List<Integer> reviews = new ArrayList<>();
if (uuids.isEmpty()) {
return reviews;
}
int index = 1;
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
@ -487,7 +500,6 @@ public class GenericReviewDAOImpl extends AbstractDAOImpl implements ReviewDAO {
}
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
List<Integer> reviews = new ArrayList<>();
while (rs.next()) {
reviews.add(rs.getInt("RATING"));
}

@ -97,6 +97,9 @@ public class OracleReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all active application reviews.");
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT " + "AP_APP_REVIEW.ID AS ID, "
@ -150,6 +153,9 @@ public class OracleReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all active application reviews of user " + username);
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT "
@ -203,6 +209,10 @@ public class OracleReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all application rating values of an application.");
}
try {
List<Integer> reviews = new ArrayList<>();
if (uuids.isEmpty()) {
return reviews;
}
int index = 1;
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
@ -217,7 +227,6 @@ public class OracleReviewDAOImpl extends GenericReviewDAOImpl {
}
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
List<Integer> reviews = new ArrayList<>();
while (rs.next()) {
reviews.add(rs.getInt("RATING"));
}

@ -97,6 +97,9 @@ public class SQLServerReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all active application reviews.");
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT " + "AP_APP_REVIEW.ID AS ID, "
@ -150,6 +153,9 @@ public class SQLServerReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all active application reviews of user " + username);
}
try {
if (releaseIds.isEmpty()) {
return new ArrayList<>();
}
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
"SELECT "
@ -203,6 +209,10 @@ public class SQLServerReviewDAOImpl extends GenericReviewDAOImpl {
log.debug("DAO request is received to Get all application rating values of an application.");
}
try {
List<Integer> reviews = new ArrayList<>();
if (uuids.isEmpty()) {
return reviews;
}
int index = 1;
Connection conn = this.getDBConnection();
StringJoiner joiner = new StringJoiner(",",
@ -217,7 +227,6 @@ public class SQLServerReviewDAOImpl extends GenericReviewDAOImpl {
}
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
List<Integer> reviews = new ArrayList<>();
while (rs.next()) {
reviews.add(rs.getInt("RATING"));
}

@ -332,12 +332,15 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
}
@Override
public List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId) throws
public List<DeviceSubscriptionDTO> getDeviceSubscriptions(int appReleaseId, int tenantId, String actionStatus, String action) throws
ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Getting device subscriptions for the application release id " + appReleaseId
+ " from the database");
}
boolean isActionStatusProvided = false;
boolean isActionProvided = false;
int index = 1;
String sql = "SELECT "
+ "DS.ID AS ID, "
+ "DS.SUBSCRIBED_BY AS SUBSCRIBED_BY, "
@ -350,11 +353,30 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
+ "DS.DM_DEVICE_ID AS DEVICE_ID "
+ "FROM AP_DEVICE_SUBSCRIPTION DS "
+ "WHERE DS.AP_APP_RELEASE_ID = ? AND DS.TENANT_ID=?";
if (actionStatus != null && !actionStatus.isEmpty()) {
sql += " AND DS.STATUS= ?";
isActionStatusProvided = true;
}
if (action != null && !action.isEmpty()) {
sql += " AND DS.UNSUBSCRIBED= ?";
isActionProvided = true;
}
try {
Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, appReleaseId);
stmt.setInt(2, tenantId);
stmt.setInt(index++, appReleaseId);
stmt.setInt(index++, tenantId);
if (isActionStatusProvided) {
stmt.setString(index++, actionStatus);
}
if (isActionProvided) {
if (action.equals("SUBSCRIBED")) {
stmt.setString(index, "FALSE");
} else {
stmt.setString(index, "TRUE");
}
}
try (ResultSet rs = stmt.executeQuery()) {
if (log.isDebugEnabled()) {
log.debug("Successfully retrieved device subscriptions for application release id "
@ -383,9 +405,12 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.debug("Request received in DAO Layer to get device subscriptions for given device ids.");
}
try {
Map<Integer, DeviceSubscriptionDTO> deviceSubscriptionDTOHashMap = new HashMap<>();
if (deviceIds.isEmpty()) {
return deviceSubscriptionDTOHashMap;
}
Connection conn = this.getDBConnection();
int index = 1;
Map<Integer, DeviceSubscriptionDTO> deviceSubscriptionDTOHashMap = new HashMap<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT "
+ "DS.ID AS ID, "
@ -439,9 +464,12 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.debug("Request received in DAO Layer to get already subscribed users for given list of user names.");
}
try {
List<String> subscribedUsers = new ArrayList<>();
if (users.isEmpty()) {
return subscribedUsers;
}
Connection conn = this.getDBConnection();
int index = 1;
List<String> subscribedUsers = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT US.USER_NAME AS USER_NAME "
+ "FROM AP_USER_SUBSCRIPTION US "
@ -479,9 +507,12 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.debug("Request received in DAO Layer to get already subscribed role names for given list of roles.");
}
try {
List<String> subscribedRoles = new ArrayList<>();
if (roles.isEmpty()) {
return subscribedRoles;
}
Connection conn = this.getDBConnection();
int index = 1;
List<String> subscribedUsers = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT RS.ROLE_NAME AS ROLE "
+ "FROM AP_ROLE_SUBSCRIPTION RS "
@ -496,11 +527,11 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
subscribedUsers.add(rs.getString("ROLE"));
subscribedRoles.add(rs.getString("ROLE"));
}
}
}
return subscribedUsers;
return subscribedRoles;
} catch (DBConnectionException e) {
String msg = "Error occurred while obtaining the DB connection to getg subscribed roles for given role "
+ "names.";
@ -520,9 +551,12 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.debug("Request received in DAO Layer to get already subscribed groups for given list of groups.");
}
try {
List<String> subscribedGroups = new ArrayList<>();
if (groups.isEmpty()) {
return subscribedGroups;
}
Connection conn = this.getDBConnection();
int index = 1;
List<String> subscribedUsers = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT GS.GROUP_NAME AS GROUP_NAME "
+ "FROM AP_GROUP_SUBSCRIPTION GS "
@ -537,11 +571,11 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
ps.setInt(index, tenantId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
subscribedUsers.add(rs.getString("GROUP_NAME"));
subscribedGroups.add(rs.getString("GROUP_NAME"));
}
}
}
return subscribedUsers;
return subscribedGroups;
} catch (DBConnectionException e) {
String msg = "Error occurred while obtaining the DB connection to get already subscribed groups for given "
+ "group names.";
@ -562,9 +596,12 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
log.debug("Request received to DAO Layer to get already subscribed dvice Ids for given list of device Ids.");
}
try {
List<Integer> subscribedDevices = new ArrayList<>();
if (deviceIds.isEmpty()) {
return subscribedDevices;
}
Connection conn = this.getDBConnection();
int index = 1;
List<Integer> subscribedDevices = new ArrayList<>();
StringJoiner joiner = new StringJoiner(",",
"SELECT DS.ID AS DEVICE_SUBSCRIPTION_ID "
+ "FROM AP_DEVICE_SUBSCRIPTION DS "
@ -695,6 +732,9 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
public boolean updateDeviceSubStatus(int deviceId, List<Integer> deviceSubIds, String status, int tenantId)
throws ApplicationManagementDAOException {
try {
if (deviceSubIds.isEmpty()) {
return false;
}
Connection conn = this.getDBConnection();
int index = 1;
StringJoiner joiner = new StringJoiner(",",
@ -747,7 +787,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
stmt.setString(2, subscriptionDTO.getApplicationUUID());
stmt.setString(3, subscriptionDTO.getSubscribersString());
stmt.setString(4, ExecutionStatus.PENDING.toString());
stmt.setTimestamp(5, Timestamp.valueOf(subscriptionDTO.getScheduledAt()));
stmt.setLong(5, subscriptionDTO.getScheduledAt());
stmt.setTimestamp(6, new Timestamp(calendar.getTime().getTime()));
stmt.setString(7, subscriptionDTO.getScheduledBy());
stmt.setBoolean(8, false);
@ -767,7 +807,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
}
@Override
public boolean updateScheduledSubscription(int id, LocalDateTime scheduledAt, String scheduledBy)
public boolean updateScheduledSubscription(int id, long scheduledAt, String scheduledBy)
throws ApplicationManagementDAOException {
String sql = "UPDATE AP_SCHEDULED_SUBSCRIPTION "
+ "SET "
@ -779,7 +819,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
Calendar calendar = Calendar.getInstance();
stmt.setTimestamp(1, Timestamp.valueOf(scheduledAt));
stmt.setLong(1, scheduledAt);
stmt.setString(2, scheduledBy);
stmt.setTimestamp(3, new Timestamp(calendar.getTime().getTime()));
stmt.setInt(4, id);
@ -941,7 +981,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
"ON " +
"AP_DEVICE_SUBSCRIPTION.AP_APP_RELEASE_ID = AP_APP_RELEASE.AP_APP_ID " +
"WHERE PACKAGE_NAME = ? " +
"AND DM_DEVICE_ID = ?" +
"AND DM_DEVICE_ID = ? " +
"AND UNSUBSCRIBED = 'FALSE' " +
"AND STATUS = 'COMPLETED';";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -1019,7 +1059,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, ExecutionStatus.PENDING.toString());
stmt.setBoolean(2, false);
stmt.setTimestamp(3, new Timestamp(Calendar.getInstance().getTime().getTime()));
stmt.setLong(3, Calendar.getInstance().getTime().getTime() / 1000);
try (ResultSet rs = stmt.executeQuery()) {
return DAOUtil.loadScheduledSubscriptions(rs);
}
@ -1231,4 +1271,45 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc
throw new ApplicationManagementDAOException(msg, e);
}
}
@Override
public List<Integer> getAppSubscribedDevicesForGroups(int appReleaseId, String subType, int tenantId)
throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Request received in DAO Layer to get already subscribed devices for " +
"given app release id.");
}
// retrieve all device list by action triggered type and app release id
try {
Connection conn = this.getDBConnection();
List<Integer> subscribedGroupDevices = new ArrayList<>();
String sql = "SELECT "
+ "AP_DEVICE_SUBSCRIPTION.DM_DEVICE_ID AS DEVICES "
+ "FROM AP_DEVICE_SUBSCRIPTION "
+ "WHERE "
+ "AP_APP_RELEASE_ID = ? AND ACTION_TRIGGERED_FROM=? AND "
+ "UNSUBSCRIBED=FALSE AND TENANT_ID = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, appReleaseId);
ps.setString(2, subType.toLowerCase());;
ps.setInt(3, tenantId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
subscribedGroupDevices.add(rs.getInt("DEVICES"));
}
}
return subscribedGroupDevices;
}
} catch (DBConnectionException e) {
String msg = "Error occurred while obtaining the DB connection to get already " +
"subscribed groups for given app release id.";
log.error(msg, e);
throw new ApplicationManagementDAOException(msg, e);
} catch (SQLException e) {
String msg = "SQL Error occurred while getting subscribed devices for given " +
"app release id.";
log.error(msg, e);
throw new ApplicationManagementDAOException(msg, e);
}
}
}

@ -1445,7 +1445,7 @@ ApplicationManagerImpl implements ApplicationManager {
log.error(msg);
throw new ForbiddenException(msg);
}
if (!subscriptionDAO.getDeviceSubscriptions(applicationReleaseDTO.getId(), tenantId).isEmpty()) {
if (!subscriptionDAO.getDeviceSubscriptions(applicationReleaseDTO.getId(), tenantId, null, null).isEmpty()) {
String msg = "Application release which has UUID: " + applicationReleaseDTO.getUuid()
+ " either subscribed to device/s or it had subscribed to device/s. Therefore you are not "
+ "permitted to delete the application release.";
@ -1580,7 +1580,7 @@ ApplicationManagerImpl implements ApplicationManager {
try {
ConnectionManagerUtil.beginDBTransaction();
List<DeviceSubscriptionDTO> deviceSubscriptionDTOS = subscriptionDAO
.getDeviceSubscriptions(applicationReleaseDTO.getId(), tenantId);
.getDeviceSubscriptions(applicationReleaseDTO.getId(), tenantId, null, null);
if (!deviceSubscriptionDTOS.isEmpty()) {
String msg = "Application release which has UUID: " + applicationReleaseDTO.getUuid()
+ " either subscribed to device/s or it had subscribed to device/s. Therefore you "

@ -65,10 +65,7 @@ import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import org.wso2.carbon.device.application.mgt.core.util.Constants;
import org.wso2.carbon.device.application.mgt.core.util.HelperUtil;
import org.wso2.carbon.device.application.mgt.core.util.OAuthUtils;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.MDMAppConstants;
import org.wso2.carbon.device.mgt.common.*;
import org.wso2.carbon.device.mgt.common.app.mgt.App;
import org.wso2.carbon.device.mgt.common.app.mgt.MobileAppTypes;
import org.wso2.carbon.device.mgt.common.app.mgt.android.CustomApplication;
@ -88,7 +85,6 @@ import org.wso2.carbon.device.mgt.core.util.MDMIOSOperationUtil;
import org.wso2.carbon.device.mgt.core.util.MDMWindowsOperationUtil;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import javax.ws.rs.core.MediaType;
import java.io.BufferedReader;
@ -101,9 +97,11 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
@ -125,7 +123,16 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
@Override
public <T> ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List<T> params,
String subType, String action) throws ApplicationManagementException {
String subType, String action, Properties properties)
throws ApplicationManagementException {
return performBulkAppOperation(applicationUUID, params, subType, action, properties, false);
}
@Override
public <T> ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List<T> params,
String subType, String action, Properties properties,
boolean isOperationReExecutingDisabled)
throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application release which has UUID " + applicationUUID + " to " + params.size()
+ " users.");
@ -138,7 +145,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
params);
ApplicationInstallResponse applicationInstallResponse = performActionOnDevices(
applicationSubscriptionInfo.getAppSupportingDeviceTypeName(), applicationSubscriptionInfo.getDevices(),
applicationDTO, subType, applicationSubscriptionInfo.getSubscribers(), action);
applicationDTO, subType, applicationSubscriptionInfo.getSubscribers(), action, properties, isOperationReExecutingDisabled);
applicationInstallResponse.setErrorDeviceIdentifiers(applicationSubscriptionInfo.getErrorDeviceIdentifiers());
return applicationInstallResponse;
@ -351,7 +358,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public void installAppsForDevice(DeviceIdentifier deviceIdentifier, List<String> releaseUUIDs)
public void installAppsForDevice(DeviceIdentifier deviceIdentifier, List<App> apps)
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
@ -374,14 +381,15 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
List<DeviceIdentifier> appInstallingDevices = new ArrayList<>();
for (String releaseUUID : releaseUUIDs) {
for (App app : apps) {
String releaseUUID = app.getId();
try {
ConnectionManagerUtil.openDBConnection();
ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(releaseUUID, tenantId);
if (applicationDTO != null) {
List<DeviceSubscriptionDTO> deviceSubscriptionDTOS = this.subscriptionDAO
.getDeviceSubscriptions(applicationDTO.getApplicationReleaseDTOs().get(0).getId(),
tenantId);
tenantId, null, null);
AtomicBoolean isAppSubscribable = new AtomicBoolean(true);
for (DeviceSubscriptionDTO deviceSubscriptionDTO : deviceSubscriptionDTOS) {
@ -413,7 +421,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
if (!appInstallingDevices.isEmpty()) {
performBulkAppOperation(releaseUUID, appInstallingDevices, SubscriptionType.DEVICE.toString(),
SubAction.INSTALL.toString());
SubAction.INSTALL.toString(), app.getProperties());
}
}
}
@ -437,7 +445,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
GroupManagementProviderService groupManagementProviderService = HelperUtil.getGroupManagementProviderService();
List<Device> devices = new ArrayList<>();
Set<Device> devices = new HashSet<>();
List<String> subscribers = new ArrayList<>();
List<DeviceIdentifier> errorDeviceIdentifiers = new ArrayList<>();
String deviceTypeName = null;
@ -514,8 +522,10 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
devices.removeIf(device -> !tmpDeviceTypeName.equals(device.getType()));
}
List<Device> deviceList = new ArrayList<>();
deviceList.addAll(devices);
ApplicationSubscriptionInfo applicationSubscriptionInfo = new ApplicationSubscriptionInfo();
applicationSubscriptionInfo.setDevices(devices);
applicationSubscriptionInfo.setDevices(deviceList);
applicationSubscriptionInfo.setSubscribers(subscribers);
applicationSubscriptionInfo.setErrorDeviceIdentifiers(errorDeviceIdentifiers);
applicationSubscriptionInfo.setAppSupportingDeviceTypeName(deviceTypeName);
@ -620,12 +630,17 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
* @param subType Subscription type (i.e USER, ROLE, GROUP or DEVICE)
* @param subscribers Subscribers
* @param action Performing action. (i.e INSTALL or UNINSTALL)
* @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
* already subscribed application successfully.
* @return {@link ApplicationInstallResponse}
* @throws ApplicationManagementException if error occured when adding operation on device or updating subscription
* @throws ApplicationManagementException if error occurred when adding operation on device or updating subscription
* data.
*/
private ApplicationInstallResponse performActionOnDevices(String deviceType, List<Device> devices,
ApplicationDTO applicationDTO, String subType, List<String> subscribers, String action)
ApplicationDTO applicationDTO, String subType,
List<String> subscribers, String action,
Properties properties,
boolean isOperationReExecutingDisabled)
throws ApplicationManagementException {
//Get app subscribing info of each device
@ -640,15 +655,19 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReInstallableDevices().keySet()));
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
} else {
if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
if (!isOperationReExecutingDisabled) {
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
deviceIdentifiers
.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReUnInstallableDevices().keySet()));
ignoredDeviceIdentifiers
.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
}
} else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
deviceIdentifiers
.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReUnInstallableDevices().keySet()));
ignoredDeviceIdentifiers
.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
} else {
String msg = "Found invalid Action: " + action + ". Hence, terminating the application subscribing.";
log.error(msg);
throw new ApplicationManagementException(msg);
}
if (deviceIdentifiers.isEmpty()) {
@ -671,11 +690,11 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
for (Map.Entry<String, List<DeviceIdentifier>> entry : deviceIdentifierMap.entrySet()) {
Activity activity = addAppOperationOnDevices(applicationDTO, new ArrayList<>(entry.getValue()),
entry.getKey(), action);
entry.getKey(), action, properties);
activityList.add(activity);
}
} else {
Activity activity = addAppOperationOnDevices(applicationDTO, deviceIdentifiers, deviceType, action);
Activity activity = addAppOperationOnDevices(applicationDTO, deviceIdentifiers, deviceType, action, properties);
activityList.add(activity);
}
@ -720,15 +739,14 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} else {
if (deviceSubscriptionDTO.isUnsubscribed()) {
if (!Operation.Status.COMPLETED.toString().equals(deviceSubscriptionDTO.getStatus())) {
/*We can't ensure whether app is uninstalled successfully or not hence allow to perform both
install and uninstall operations*/
/*If the uninstalling operation has failed, we can't ensure whether the app is uninstalled
successfully or not. Therefore, allowing to perform both install and uninstall operations*/
subscribingDeviceIdHolder.getAppReUnInstallableDevices()
.put(deviceIdentifier, device.getId());
}
subscribingDeviceIdHolder.getAppReInstallableDevices().put(deviceIdentifier, device.getId());
} else {
if (!deviceSubscriptionDTO.isUnsubscribed() && Operation.Status.COMPLETED.toString()
.equals(deviceSubscriptionDTO.getStatus())) {
if (Operation.Status.COMPLETED.toString().equals(deviceSubscriptionDTO.getStatus())) {
subscribingDeviceIdHolder.getAppInstalledDevices().put(deviceIdentifier, device.getId());
} else {
subscribingDeviceIdHolder.getAppReInstallableDevices()
@ -963,11 +981,11 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
ConnectionManagerUtil.openDBConnection();
return this.subscriptionDAO.getDeviceSubscriptions(deviceIds, appReleaseId, tenantId);
} catch (ApplicationManagementDAOException e) {
String msg = "Error occured when getting device subscriptions for given device IDs";
String msg = "Error occurred when getting device subscriptions for given device IDs";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (DBConnectionException e) {
String msg = "Error occured while getting database connection for getting device subscriptions.";
String msg = "Error occurred while getting database connection for getting device subscriptions.";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
@ -986,13 +1004,13 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
* @throws ApplicationManagementException if found an invalid device.
*/
private Activity addAppOperationOnDevices(ApplicationDTO applicationDTO,
List<DeviceIdentifier> deviceIdentifierList, String deviceType, String action)
List<DeviceIdentifier> deviceIdentifierList, String deviceType, String action, Properties properties)
throws ApplicationManagementException {
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
try {
Application application = APIUtil.appDtoToAppResponse(applicationDTO);
Operation operation = generateOperationPayloadByDeviceType(deviceType, application, action);
Operation operation = generateOperationPayloadByDeviceType(deviceType, application, action, properties);
return deviceManagementProviderService.addOperation(deviceType, operation, deviceIdentifierList);
} catch (OperationManagementException e) {
String msg = "Error occurred while adding the application install operation to devices";
@ -1014,7 +1032,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
* @throws ApplicationManagementException if unknown application type is found to generate operation payload or
* invalid action is found to generate operation payload.
*/
private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action)
private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action, Properties properties)
throws ApplicationManagementException {
try {
if (ApplicationType.CUSTOM.toString().equalsIgnoreCase(application.getType())) {
@ -1050,6 +1068,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
app.setLocation(application.getApplicationReleases().get(0).getInstallerPath());
app.setIdentifier(application.getPackageName());
app.setName(application.getName());
app.setProperties(properties);
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
return MDMAndroidOperationUtil.createInstallAppOperation(app);
} else {
@ -1071,7 +1090,6 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
app.setType(mobileAppType);
app.setLocation(plistDownloadEndpoint);
app.setIconImage(application.getApplicationReleases().get(0).getIconPath());
Properties properties = new Properties();
properties.put(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP, true);
properties.put(MDMAppConstants.IOSConstants.IS_REMOVE_APP, true);
properties.put(MDMAppConstants.IOSConstants.I_TUNES_ID, application.getPackageName());
@ -1111,9 +1129,13 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
return MDMWindowsOperationUtil.createInstallAppOperation(app);
} else {
String msg = "Invalid Action is found. Action: " + action;
log.error(msg);
throw new ApplicationManagementException(msg);
if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
return MDMWindowsOperationUtil.createUninstallAppOperation(app);
} else {
String msg = "Invalid Action is found. Action: " + action;
log.error(msg);
throw new ApplicationManagementException(msg);
}
}
} else {
String msg = "Invalid device type is found. Device Type: " + deviceType;
@ -1223,7 +1245,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public PaginationResult getAppInstalledDevices(int offsetValue, int limitValue, String appUUID, List<String> status)
public PaginationResult getAppInstalledDevices(PaginationRequest request, String appUUID)
throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
@ -1235,7 +1257,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
int applicationReleaseId = applicationDTO.getApplicationReleaseDTOs().get(0).getId();
List<DeviceSubscriptionDTO> deviceSubscriptionDTOS = subscriptionDAO
.getDeviceSubscriptions(applicationReleaseId, tenantId);
.getDeviceSubscriptions(applicationReleaseId, tenantId, null, null);
if (deviceSubscriptionDTOS.isEmpty()) {
PaginationResult paginationResult = new PaginationResult();
paginationResult.setData(new ArrayList<>());
@ -1262,8 +1284,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
//pass the device id list to device manager service method
try {
PaginationResult deviceDetails = deviceManagementProviderService
.getAppSubscribedDevices(offsetValue, limitValue, deviceIdList, status);
PaginationResult deviceDetails = deviceManagementProviderService.getAppSubscribedDevices
(request, deviceIdList);
if (deviceDetails == null) {
String msg = "Couldn't found an subscribed devices details for device ids: " + deviceIdList;
@ -1342,8 +1364,10 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public PaginationResult getAppSubscriptionDetails(int offsetValue, int limitValue, String appUUID)
throws ApplicationManagementException {
public PaginationResult getAppSubscriptionDetails(PaginationRequest request, String appUUID, String actionStatus,
String action) throws ApplicationManagementException {
int limitValue = request.getRowCount();
int offsetValue = request.getStartIndex();
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
@ -1365,7 +1389,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
int applicationReleaseId = applicationDTO.getApplicationReleaseDTOs().get(0).getId();
List<DeviceSubscriptionDTO> deviceSubscriptionDTOS = subscriptionDAO
.getDeviceSubscriptions(applicationReleaseId, tenantId);
.getDeviceSubscriptions(applicationReleaseId, tenantId, actionStatus, action);
if (deviceSubscriptionDTOS.isEmpty()) {
PaginationResult paginationResult = new PaginationResult();
paginationResult.setData(new ArrayList<>());
@ -1377,8 +1401,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
.collect(Collectors.toList());
try {
//pass the device id list to device manager service method
PaginationResult paginationResult = deviceManagementProviderService
.getAppSubscribedDevices(offsetValue, limitValue, deviceIdList, null);
PaginationResult paginationResult = deviceManagementProviderService.getAppSubscribedDevices
(request, deviceIdList);
List<DeviceSubscriptionData> deviceSubscriptionDataList = new ArrayList<>();
if (!paginationResult.getData().isEmpty()) {
@ -1392,12 +1416,12 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
deviceSubscriptionData.setAction(Constants.UNSUBSCRIBED);
deviceSubscriptionData.setActionTriggeredBy(subscription.getUnsubscribedBy());
deviceSubscriptionData
.setActionTriggeredTimestamp(subscription.getUnsubscribedTimestamp());
.setActionTriggeredTimestamp(subscription.getUnsubscribedTimestamp().getTime() / 1000);
} else {
deviceSubscriptionData.setAction(Constants.SUBSCRIBED);
deviceSubscriptionData.setActionTriggeredBy(subscription.getSubscribedBy());
deviceSubscriptionData
.setActionTriggeredTimestamp(subscription.getSubscribedTimestamp());
.setActionTriggeredTimestamp(subscription.getSubscribedTimestamp().getTime() / 1000);
}
deviceSubscriptionData.setActionType(subscription.getActionTriggeredFrom());
deviceSubscriptionData.setStatus(subscription.getStatus());
@ -1429,4 +1453,50 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override
public PaginationResult getAppInstalledSubscribeDevices(PaginationRequest request, String appUUID, String subType,
String subTypeName) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
try {
ConnectionManagerUtil.openDBConnection();
ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(appUUID, tenantId);
int applicationReleaseId = applicationDTO.getApplicationReleaseDTOs().get(0).getId();
List<Integer> subscriptionDeviceList = new ArrayList<>();
//todo update the API for other subscription types
if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) {
subscriptionDeviceList = subscriptionDAO
.getAppSubscribedDevicesForGroups(applicationReleaseId, subType, tenantId);
} else {
String msg = "Found invalid sub type: " + subType;
log.error(msg);
throw new NotFoundException(msg);
}
if (subscriptionDeviceList.isEmpty()) {
PaginationResult paginationResult = new PaginationResult();
paginationResult.setData(subscriptionDeviceList);
paginationResult.setRecordsFiltered(0);
paginationResult.setRecordsTotal(0);
return paginationResult;
}
return deviceManagementProviderService.getDevicesDetails(request, subscriptionDeviceList, subTypeName);
} catch (DeviceManagementException e) {
String msg = "service error occurred while getting device data from the device management service.";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (ApplicationManagementDAOException e) {
String msg = "Error occurred when get application release devices data for application release UUID: "
+ appUUID;
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (DBConnectionException e) {
String msg = "DB Connection error occurred while getting category details that given application id";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
}

@ -40,7 +40,7 @@ public class ScheduledAppSubscriptionCleanupTask extends RandomlyAssignedSchedul
@Override
public void executeRandomlyAssignedTask() {
try {
if(super.isQualifiedToExecuteTask()) {
if(isQualifiedToExecuteTask()) {
subscriptionManager.cleanScheduledSubscriptions();
}
} catch (SubscriptionManagementException e) {

@ -37,14 +37,16 @@ import org.wso2.carbon.device.mgt.core.task.impl.RandomlyAssignedScheduleTask;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
private static Log log = LogFactory.getLog(ScheduledAppSubscriptionTask.class);
private static final Log log = LogFactory.getLog(ScheduledAppSubscriptionTask.class);
private static final String TASK_NAME = "SCHEDULE_APP_SUBSCRIPTION";
private SubscriptionManager subscriptionManager;
private String payload;
private String subscribers;
private String subscriptionType;
private String application;
@ -53,10 +55,12 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
private String tenantDomain;
private String taskName;
private int tenantId;
private boolean isOperationReExecutingDisabled;
@Override
public void setProperties(Map<String, String> map) {
this.subscribers = map.get(Constants.SUBSCRIBERS);
this.payload = map.get(Constants.PAYLOAD);
this.subscriptionType = map.get(Constants.SUB_TYPE);
this.application = map.get(Constants.APP_UUID);
this.action = map.get(Constants.ACTION);
@ -64,11 +68,12 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
this.tenantDomain = map.get(Constants.TENANT_DOMAIN);
this.tenantId = Integer.parseInt(map.get(Constants.TENANT_ID));
this.taskName = map.get(Constants.TASK_NAME);
this.isOperationReExecutingDisabled = Boolean.parseBoolean(map.get(Constants.OPERATION_RE_EXECUtING));
}
@Override
public void executeRandomlyAssignedTask() {
if(super.isQualifiedToExecuteTask()) {
if(isQualifiedToExecuteTask()) {
try {
ScheduledSubscriptionDTO subscriptionDTO = subscriptionManager.getPendingScheduledSubscription(
this.taskName);
@ -89,8 +94,9 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
new TypeToken<List<DeviceIdentifier>>() {
}.getType());
try {
Properties properties = new Gson().fromJson(payload, Properties.class);
subscriptionManager.performBulkAppOperation(this.application, deviceIdentifiers,
this.subscriptionType, this.action);
this.subscriptionType, this.action, properties);
subscriptionDTO.setStatus(ExecutionStatus.EXECUTED);
} catch (ApplicationManagementException e) {
log.error(
@ -102,8 +108,9 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
List<String> subscriberList = Pattern.compile(",").splitAsStream(this.subscribers).collect(
Collectors.toList());
try {
Properties properties = new Gson().fromJson(payload, Properties.class);
subscriptionManager.performBulkAppOperation(this.application, subscriberList,
this.subscriptionType, this.action);
this.subscriptionType, this.action, properties, isOperationReExecutingDisabled);
subscriptionDTO.setStatus(ExecutionStatus.EXECUTED);
} catch (ApplicationManagementException e) {
log.error(

@ -40,10 +40,13 @@ import org.wso2.carbon.ntask.core.service.TaskService;
import java.time.LocalDateTime;
import java.time.format.TextStyle;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
public class ScheduledAppSubscriptionTaskManager {
@ -64,24 +67,31 @@ public class ScheduledAppSubscriptionTaskManager {
* either {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is
* equal to DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
* @param subscriptionType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code>
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
* {@see {@link SubscriptionType}}
* @param action action subscription action. E.g. {@code INSTALL/UNINSTALL}
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
* {@see {@link SubAction}}
* @param timestamp timestamp to schedule the application subscription
* @param properties Properties sending to the device via operation
* @param isOperationReExecutingDisabled To prevent adding the application subscribing
* already subscribed application successfully.
* @throws ApplicationOperationTaskException if error occurred while scheduling the subscription
*/
public void scheduleAppSubscriptionTask(String applicationUUID, List<?> subscribers,
SubscriptionType subscriptionType, SubAction action, LocalDateTime timestamp)
SubscriptionType subscriptionType, SubAction action, long timestamp,
Properties properties, boolean isOperationReExecutingDisabled)
throws ApplicationOperationTaskException {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(timestamp * 1000));
String space = " ";
String cronExpression =
String.valueOf(timestamp.getSecond()) + space + timestamp.getMinute() + space + timestamp.getHour()
+ space + timestamp.getDayOfMonth() + space + timestamp.getMonth().getDisplayName(TextStyle.SHORT,
Locale.getDefault()).toUpperCase() + " ? " + timestamp.getYear();
calendar.get(Calendar.SECOND) + space + calendar.get(Calendar.MINUTE) + space
+ calendar.get(Calendar.HOUR_OF_DAY) + space + calendar.get(Calendar.DAY_OF_MONTH) + space
+ calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()).toUpperCase() + " ? "
+ calendar.get(Calendar.YEAR);
if (!CronExpression.isValidExpression(cronExpression)) {
String msg = "The cron expression [" + cronExpression + "] generated by the" + " timestamp [" + timestamp
.toString() + "] is invalid";
+ "] is invalid";
log.error(msg);
throw new ApplicationOperationTaskException(msg);
}
@ -101,14 +111,18 @@ public class ScheduledAppSubscriptionTaskManager {
taskProperties.put(Constants.APP_UUID, applicationUUID);
taskProperties.put(Constants.TENANT_DOMAIN, carbonContext.getTenantDomain(true));
taskProperties.put(Constants.SUBSCRIBER, carbonContext.getUsername());
taskProperties.put(Constants.OPERATION_RE_EXECUtING, String.valueOf(isOperationReExecutingDisabled));
String subscribersString;
if (SubscriptionType.DEVICE.equals(subscriptionType)) {
subscribersString = new Gson().toJson(subscribers);
taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
} else {
subscribersString = subscribers.stream().map(String.class::cast).collect(Collectors.joining(","));
taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
}
taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
if(properties != null) {
String payload = new Gson().toJson(properties);
taskProperties.put(Constants.PAYLOAD, payload);
}
if (log.isDebugEnabled()) {
log.debug("Scheduling a task to " + action.toString() + " application: " + applicationUUID +

@ -58,7 +58,9 @@ public class Constants {
public static final String SUB_TYPE = "SUBSCRIPTION_TYPE";
public static final String ACTION = "ACTION";
public static final String APP_UUID = "APP_UUID";
public static final String APP_PROPERTIES = "APP_PROPERTIES";
public static final String SUBSCRIBER = "SUBSCRIBER";
public static final String OPERATION_RE_EXECUtING = "OPERATION_RE_EXECUtING";
public static final String TENANT_DOMAIN = "TENANT_DOMAIN";
public static final String TENANT_ID = "__TENANT_ID_PROP__";
public static final String TASK_NAME = "TASK_NAME";

@ -274,7 +274,7 @@ public class DAOUtil {
}
subscription.setStatus(ExecutionStatus.valueOf(rs.getString("STATUS")));
subscription.setScheduledAt(rs.getTimestamp("SCHEDULED_AT").toLocalDateTime());
subscription.setScheduledAt(rs.getLong("SCHEDULED_AT"));
subscription.setScheduledBy(rs.getString("SCHEDULED_BY"));
subscription.setDeleted(rs.getBoolean("DELETED"));
subscriptionDTOS.add(subscription);

@ -22,13 +22,13 @@
<parent>
<artifactId>application-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.publisher.api</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>WSO2 Carbon - Application Management Publisher API</name>
<description>WSO2 Carbon - Application Management Publisher API</description>

@ -22,13 +22,13 @@
<parent>
<artifactId>application-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.application.mgt.store.api</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>WSO2 Carbon - Application Management Store API</name>
<description>WSO2 Carbon - Application Management Store API</description>

@ -32,6 +32,7 @@ import org.wso2.carbon.device.application.mgt.common.ErrorResponse;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import javax.validation.Valid;
import javax.validation.constraints.Size;
import javax.ws.rs.Path;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
@ -129,7 +130,12 @@ public interface SubscriptionManagementAPI {
name = "timestamp",
value = "Timestamp of scheduled install/uninstall operation"
)
@QueryParam("timestamp") String timestamp
@QueryParam("timestamp") long timestamp,
@ApiParam(
name = "block-uninstall",
value = "App removal status of the install operation"
)
@QueryParam("block-uninstall") Boolean isUninstallBlocked
);
@POST
@ -182,7 +188,17 @@ public interface SubscriptionManagementAPI {
name = "timestamp",
value = "Timestamp of scheduled install/uninstall operation"
)
@QueryParam("timestamp") String timestamp
@QueryParam("timestamp") long timestamp,
@ApiParam(
name = "block-uninstall",
value = "App removal status of the install operation"
)
@QueryParam("block-uninstall") Boolean isUninstallBlocked,
@ApiParam(
name = "disable-operation-re-executing",
value = "Disable Operation re-executing"
)
@QueryParam("disable-operation-re-executing") boolean isOperationReExecutingDisabled
);
@POST
@ -229,7 +245,7 @@ public interface SubscriptionManagementAPI {
name = "timestamp",
value = "Timestamp of scheduled ent. install operation"
)
@QueryParam("timestamp") String timestamp,
@QueryParam("timestamp") long timestamp,
@ApiParam(
name = "requiresUpdatingExternal",
value = "Should external system such as Google EMM APIs need to be updated."
@ -287,7 +303,7 @@ public interface SubscriptionManagementAPI {
name = "timestamp",
value = "Timestamp of scheduled ent app install operation"
)
@QueryParam("timestamp") String timestamp,
@QueryParam("timestamp") long timestamp,
@ApiParam(
name = "requiresUpdatingExternal",
value = "Should external system such as Google EMM APIs need to be updated."
@ -337,6 +353,28 @@ public interface SubscriptionManagementAPI {
response = ErrorResponse.class)
})
Response getAppInstalledDevices(
@ApiParam(
name = "name",
value = "The device name. For example, Nexus devices can have names, suhc as shamu, bullhead or angler.",
required = false)
@Size(max = 45)
String name,
@ApiParam(
name = "user",
value = "The username of the owner of the device.",
required = false)
@QueryParam("user")
String user,
@ApiParam(
name = "ownership",
allowableValues = "BYOD, COPE",
value = "Provide the ownership status of the device. The following values can be assigned:\n" +
"- BYOD: Bring Your Own Device\n" +
"- COPE: Corporate-Owned, Personally-Enabled",
required = false)
@QueryParam("ownership")
@Size(max = 45)
String ownership,
@ApiParam(
name="uuid",
value="uuid of the application release.",
@ -423,4 +461,101 @@ public interface SubscriptionManagementAPI {
defaultValue = "5")
@QueryParam("limit") int limit
);
@GET
@Path("/{uuid}/{subType}/{subTypeName}/devices")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Get device details in categories that have a given application install",
notes = "This will get the category's device details that have a given application install, if exists",
tags = "Subscription Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "perm:app:subscription:uninstall")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully retrieved device details.",
response = List.class,
responseContainer = "List"),
@ApiResponse(
code = 404,
message = "Not Found. \n No Devices found which has application " +
"release of UUID.",
response = ErrorResponse.class),
@ApiResponse(
code = 400,
message = "Bad Request. \n Found invalid payload with the request.",
response = List.class),
@ApiResponse(
code = 403,
message = "Forbidden. \n Don't have permission to get the details.",
response = List.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error occurred while getting data",
response = ErrorResponse.class)
})
Response getAppInstalledDevicesOnCategories(
@ApiParam(
name="uuid",
value="uuid of the application release.",
required = true)
@PathParam("uuid") String uuid,
@ApiParam(
name="subType",
value="Subscription type of the application release.",
required = true)
@PathParam("subType") String subType,
@ApiParam(
name="subTypeName",
value="Subscription type name of the application release.",
required = true)
@PathParam("subTypeName") String subTypeName,
@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,
@ApiParam(
name = "name",
value = "The device name. For example, Nexus devices can have names, such as shamu, bullhead or angler.",
required = false)
@Size(max = 45)
String name,
@ApiParam(
name = "user",
value = "The username of the owner of the device.",
required = false)
@QueryParam("user")
String user,
@ApiParam(
name = "ownership",
allowableValues = "BYOD, COPE",
value = "Provide the ownership status of the device. The following values can be assigned:\n" +
"- BYOD: Bring Your Own Device\n" +
"- COPE: Corporate-Owned, Personally-Enabled",
required = false)
@QueryParam("ownership")
@Size(max = 45)
String ownership,
@ApiParam(
name = "status",
value = "Provide the device status details, such as active or inactive.")
@QueryParam("status") List<String> status
);
}

@ -31,6 +31,7 @@ import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.application.mgt.common.ErrorResponse;
import javax.validation.constraints.Size;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@ -111,6 +112,32 @@ public interface SubscriptionManagementAdminAPI {
response = ErrorResponse.class)
})
Response getAppInstalledDevices(
@ApiParam(
name = "name",
value = "The device name. For example, Nexus devices can have names, suhc as shamu, bullhead or angler.",
required = false)
@Size(max = 45)
String name,
@ApiParam(
name = "user",
value = "The username of the owner of the device.",
required = false)
@QueryParam("user")
String user,
@ApiParam(
name = "action",
value = "The action, subscribed or unsubscribed.",
required = false)
@Size(max = 45)
@QueryParam("action") String action,
@ApiParam(
name = "actionStatus",
value = "Provide the action status details")
@QueryParam("actionStatus") String actionStatus,
@ApiParam(
name = "status",
value = "Provide the device status details, such as active or inactive.")
@QueryParam("status") List<String> status,
@ApiParam(
name = "uuid",
value = "uuid of the application release.",

@ -33,7 +33,7 @@ import org.wso2.carbon.device.application.mgt.common.BasicUserInfo;
import org.wso2.carbon.device.application.mgt.common.BasicUserInfoList;
import org.wso2.carbon.device.application.mgt.common.RoleList;
import org.wso2.carbon.device.application.mgt.common.DeviceGroupList;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.application.mgt.store.api.services.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException;
import org.wso2.carbon.device.application.mgt.core.exception.ForbiddenException;
import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException;
@ -42,6 +42,9 @@ import org.wso2.carbon.device.application.mgt.core.util.APIUtil;
import org.wso2.carbon.device.application.mgt.store.api.services.SubscriptionManagementAPI;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.MDMAppConstants;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import javax.validation.Valid;
import javax.ws.rs.Path;
@ -53,9 +56,8 @@ import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.core.Response;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
/**
* Implementation of Subscription Management related APIs.
@ -73,16 +75,22 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@PathParam("uuid") String uuid,
@PathParam("action") String action,
@Valid List<DeviceIdentifier> deviceIdentifiers,
@QueryParam("timestamp") String timestamp) {
@QueryParam("timestamp") long timestamp,
@QueryParam("block-uninstall") Boolean isUninstallBlocked
) {
Properties properties = new Properties();
if(isUninstallBlocked != null) {
properties.put(MDMAppConstants.AndroidConstants.IS_BLOCK_UNINSTALL, isUninstallBlocked);
}
try {
if (StringUtils.isEmpty(timestamp)) {
if (0 == timestamp) {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
ApplicationInstallResponse response = subscriptionManager
.performBulkAppOperation(uuid, deviceIdentifiers, SubscriptionType.DEVICE.toString(), action);
.performBulkAppOperation(uuid, deviceIdentifiers, SubscriptionType.DEVICE.toString(), action, properties);
return Response.status(Response.Status.OK).entity(response).build();
} else {
return scheduleApplicationOperationTask(uuid, deviceIdentifiers, SubscriptionType.DEVICE,
SubAction.valueOf(action.toUpperCase()), timestamp);
SubAction.valueOf(action.toUpperCase()), timestamp, properties);
}
} catch (NotFoundException e) {
String msg = "Couldn't found an application release for UUI: " + uuid;
@ -114,17 +122,25 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@PathParam("subType") String subType,
@PathParam("action") String action,
@Valid List<String> subscribers,
@QueryParam("timestamp") String timestamp) {
@QueryParam("timestamp") long timestamp,
@QueryParam("block-uninstall") Boolean isUninstallBlocked,
@QueryParam("disable-operation-re-executing") boolean isOperationReExecutingDisabled
) {
Properties properties = new Properties();
if (isUninstallBlocked != null) {
properties.put(MDMAppConstants.AndroidConstants.IS_BLOCK_UNINSTALL, isUninstallBlocked);
}
try {
if (StringUtils.isEmpty(timestamp)) {
if (0 == timestamp) {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
ApplicationInstallResponse response = subscriptionManager
.performBulkAppOperation(uuid, subscribers, subType, action);
ApplicationInstallResponse response =
subscriptionManager.performBulkAppOperation(uuid, subscribers, subType, action, properties,
isOperationReExecutingDisabled);
return Response.status(Response.Status.OK).entity(response).build();
} else {
return scheduleApplicationOperationTask(uuid, subscribers,
SubscriptionType.valueOf(subType.toUpperCase()), SubAction.valueOf(action.toUpperCase()),
timestamp);
timestamp, properties, isOperationReExecutingDisabled);
}
} catch (NotFoundException e) {
String msg = "Couldn't found an application release for UUID: " + uuid + ". Hence, verify the payload";
@ -155,10 +171,10 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@PathParam("uuid") String uuid,
@PathParam("action") String action,
@Valid List<DeviceIdentifier> deviceIdentifiers,
@QueryParam("timestamp") String timestamp,
@QueryParam("timestamp") long timestamp,
@QueryParam("requiresUpdatingExternal") boolean requiresUpdatingExternal) {
try {
if (StringUtils.isEmpty(timestamp)) {
if (0 == timestamp) {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
subscriptionManager
.performEntAppSubscription(uuid, deviceIdentifiers, SubscriptionType.DEVICE.toString(),
@ -168,7 +184,7 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
return Response.status(Response.Status.OK).entity(msg).build();
} else {
return scheduleApplicationOperationTask(uuid, deviceIdentifiers, SubscriptionType.DEVICE,
SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp);
SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp, null);
}
} catch (NotFoundException e) {
String msg = "Couldn't found an application release for UUI: " + uuid + " to perform ent app installation "
@ -202,10 +218,10 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@PathParam("subType") String subType,
@PathParam("action") String action,
@Valid List<String> subscribers,
@QueryParam("timestamp") String timestamp,
@QueryParam("timestamp") long timestamp,
@QueryParam("requiresUpdatingExternal") boolean requiresUpdatingExternal) {
try {
if (StringUtils.isEmpty(timestamp)) {
if (0 == timestamp) {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
subscriptionManager.performEntAppSubscription(uuid, subscribers, subType, action, requiresUpdatingExternal);
String msg = "Application release which has UUID " + uuid + " is installed to subscriber's valid device"
@ -214,7 +230,7 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
} else {
return scheduleApplicationOperationTask(uuid, subscribers,
SubscriptionType.valueOf(subType.toUpperCase()),
SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp);
SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp, null);
}
} catch (NotFoundException e) {
String msg = "Couldn't found an application release for UUID: " + uuid + ". Hence, verify the payload";
@ -238,6 +254,28 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
}
}
/**
* Schedule the application subscription for the given timestamp
*
* @param applicationUUID UUID of the application to install
* @param subscribers list of subscribers. This list can be of
* either {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is
* equal to DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
* @param subType subscription type. E.g. <code>DEVICE, USER, ROLE, GROUP</code>
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
* @param subAction action subscription action. E.g. <code>INSTALL/UNINSTALL</code>
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
* @param payload Properties sending to the device via operation
* @param timestamp timestamp to schedule the application subscription
* @return {@link Response} of the operation
*/
private Response scheduleApplicationOperationTask(String applicationUUID, List<?> subscribers,
SubscriptionType subType, SubAction subAction, long timestamp,
Properties payload) {
return scheduleApplicationOperationTask(applicationUUID, subscribers, subType, subAction, timestamp, payload,
false);
}
/**
* Schedule the application subscription for the given timestamp
*
@ -250,14 +288,18 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
* @param subAction action subscription action. E.g. <code>INSTALL/UNINSTALL</code>
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
* @param timestamp timestamp to schedule the application subscription
* @param payload Properties sending to the device via operation
* @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
* already subscribed application successfully.
* @return {@link Response} of the operation
*/
private Response scheduleApplicationOperationTask(String applicationUUID, List<?> subscribers,
SubscriptionType subType, SubAction subAction, String timestamp) {
SubscriptionType subType, SubAction subAction, long timestamp,
Properties payload, boolean isOperationReExecutingDisabled) {
try {
ScheduledAppSubscriptionTaskManager subscriptionTaskManager = new ScheduledAppSubscriptionTaskManager();
subscriptionTaskManager.scheduleAppSubscriptionTask(applicationUUID, subscribers, subType, subAction,
LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
timestamp, payload, isOperationReExecutingDisabled);
} catch (ApplicationOperationTaskException e) {
String msg = "Error occurred while scheduling the application install operation";
log.error(msg, e);
@ -273,6 +315,9 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@Produces("application/json")
@Path("/{uuid}/devices")
public Response getAppInstalledDevices(
@QueryParam("name") String name,
@QueryParam("user") String user,
@QueryParam("ownership") String ownership,
@PathParam("uuid") String uuid,
@DefaultValue("0")
@QueryParam("offset") int offset,
@ -281,8 +326,31 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@QueryParam("status") List<String> status) {
try {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
PaginationResult subscribedDeviceDetails = subscriptionManager
.getAppInstalledDevices(offset, limit, uuid, status);
PaginationRequest request = new PaginationRequest(offset, limit);
if (name != null && !name.isEmpty()) {
request.setDeviceName(name);
}
if (user != null && !user.isEmpty()) {
request.setOwner(user);
}
if (ownership != null && !ownership.isEmpty()) {
RequestValidationUtil.validateOwnershipType(ownership);
request.setOwnership(ownership);
}
if (status != null && !status.isEmpty()) {
boolean isStatusEmpty = true;
for (String statusString : status) {
if (StringUtils.isNotBlank(statusString)) {
isStatusEmpty = false;
break;
}
}
if (!isStatusEmpty) {
RequestValidationUtil.validateStatus(status);
request.setStatusList(status);
}
}
PaginationResult subscribedDeviceDetails = subscriptionManager.getAppInstalledDevices(request, uuid);
DeviceList devices = new DeviceList();
devices.setList((List<Device>) subscribedDeviceDetails.getData());
devices.setCount(subscribedDeviceDetails.getRecordsTotal());
@ -292,8 +360,7 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (BadRequestException e) {
String msg = "Found invalid payload for getting application which has UUID: " + uuid
+ ". Hence verify the payload";
String msg = "User requested details are not valid";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (ForbiddenException e) {
@ -303,7 +370,7 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while getting application with the application release uuid: "
+ uuid;
+ uuid;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
@ -358,17 +425,86 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (BadRequestException e) {
String msg = "Found invalid payload for getting application which has UUID: " + uuid
+ ". Hence verify the payload";
+ ". Hence verify the payload";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (ForbiddenException e) {
String msg = "Application release is not in the installable state."
+ "Hence you are not permitted to get the devices details.";
+ "Hence you are not permitted to get the devices details.";
log.error(msg, e);
return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while getting application with the application " +
"release uuid: " + uuid;
"release uuid: " + uuid;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@GET
@Consumes("application/json")
@Produces("application/json")
@Path("/{uuid}/{subType}/{subTypeName}/devices")
public Response getAppInstalledDevicesOnCategories(
@PathParam("uuid") String uuid,
@PathParam("subType") String subType,
@PathParam("subTypeName") String subTypeName,
@DefaultValue("0")
@QueryParam("offset") int offset,
@DefaultValue("5")
@QueryParam("limit") int limit,
@QueryParam("name") String name,
@QueryParam("user") String user,
@QueryParam("ownership") String ownership,
@QueryParam("status") List<String> status) {
try {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
PaginationRequest request = new PaginationRequest(offset, limit);
if (StringUtils.isNotBlank(name)) {
request.setDeviceName(name);
}
if (StringUtils.isNotBlank(user)) {
request.setOwner(user);
}
if (StringUtils.isNotBlank(ownership)) {
RequestValidationUtil.validateOwnershipType(ownership);
request.setOwnership(ownership);
}
if (status != null && !status.isEmpty()) {
boolean isStatusEmpty = true;
for (String statusString : status) {
if (StringUtils.isNotBlank(statusString)) {
isStatusEmpty = false;
break;
}
}
if (!isStatusEmpty) {
RequestValidationUtil.validateStatus(status);
request.setStatusList(status);
}
}
//todo need to update the API for other subscription types
if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) {
PaginationResult subscribedCategoryDetails = subscriptionManager
.getAppInstalledSubscribeDevices(request, uuid, subType, subTypeName);
DeviceList devices = new DeviceList();
devices.setList((List<Device>) subscribedCategoryDetails.getData());
devices.setCount(subscribedCategoryDetails.getRecordsTotal());
return Response.status(Response.Status.OK).entity(devices).build();
} else {
String msg = "Found invalid sub type: " + subType;
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
} catch (NotFoundException e) {
String msg = "Application with application release UUID: " + uuid + " is not found";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while getting application with the application " +
"release uuid: " + uuid;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}

@ -18,6 +18,7 @@
package org.wso2.carbon.device.application.mgt.store.api.services.impl.admin;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
@ -26,6 +27,8 @@ import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException
import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException;
import org.wso2.carbon.device.application.mgt.core.util.APIUtil;
import org.wso2.carbon.device.application.mgt.store.api.services.admin.SubscriptionManagementAdminAPI;
import org.wso2.carbon.device.application.mgt.store.api.services.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import javax.ws.rs.Consumes;
@ -36,6 +39,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* Implementation of Subscription Management related APIs.
@ -51,6 +55,11 @@ public class SubscriptionManagementAdminAPIImpl implements SubscriptionManagemen
@Produces("application/json")
@Path("/{uuid}")
public Response getAppInstalledDevices(
@QueryParam("name") String name,
@QueryParam("user") String user,
@QueryParam("action") String action,
@QueryParam("actionStatus") String actionStatus,
@QueryParam("status") List<String> status,
@PathParam("uuid") String uuid,
@DefaultValue("0")
@QueryParam("offset") int offset,
@ -58,22 +67,49 @@ public class SubscriptionManagementAdminAPIImpl implements SubscriptionManagemen
@QueryParam("limit") int limit) {
try {
PaginationRequest request = new PaginationRequest(offset, limit);
if (name != null && !name.isEmpty()) {
request.setDeviceName(name);
}
if (user != null && !user.isEmpty()) {
request.setOwner(user);
}
if (action != null && !action.isEmpty()) {
RequestValidationUtil.validateAction(action);
}
if (status != null && !status.isEmpty()) {
boolean isStatusEmpty = true;
for (String statusString : status) {
if (StringUtils.isNotBlank(statusString)) {
isStatusEmpty = false;
break;
}
}
if (!isStatusEmpty) {
RequestValidationUtil.validateStatus(status);
request.setStatusList(status);
}
}
if (actionStatus != null && !actionStatus.isEmpty()) {
if (StringUtils.isNotBlank(actionStatus)) {
RequestValidationUtil.validateStatusFiltering(actionStatus);
}
}
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
PaginationResult subscriptionData = subscriptionManager
.getAppSubscriptionDetails(offset, limit, uuid);
PaginationResult subscriptionData = subscriptionManager.getAppSubscriptionDetails
(request, uuid, actionStatus, action);
return Response.status(Response.Status.OK).entity(subscriptionData).build();
} catch (NotFoundException e) {
String msg = "Application with application release UUID: " + uuid + " is not found";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (BadRequestException e) {
String msg = "Found invalid payload for getting application which has UUID: " + uuid
+ ". Hence verify the payload";
String msg = "User requested details are not valid";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (ApplicationManagementException e) {
String msg = "Error occurred while getting app installed devices which has application release UUID of: "
+ uuid;
+ uuid;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}

@ -0,0 +1,116 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.store.api.services.impl.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.application.mgt.core.exception.BadRequestException;
import org.wso2.carbon.device.application.mgt.store.api.util.Constants;
import java.util.List;
public class RequestValidationUtil {
private static final Log log = LogFactory.getLog(RequestValidationUtil.class);
/**
* Checks if user requested status codes are valid.
*
* @param statusList status codes upon to filter operation logs using status
*/
public static void validateStatus(List<String> statusList) throws BadRequestException {
for (String status : statusList) {
switch (status) {
case "ACTIVE":
case "INACTIVE":
case "UNCLAIMED":
case "UNREACHABLE":
case "SUSPENDED":
case "DISENROLLMENT_REQUESTED":
case "REMOVED":
case "BLOCKED":
case "CREATED":
break;
default:
String msg = "Invalid enrollment status type: " + status + ". \nValid status types " +
"are ACTIVE | INACTIVE | UNCLAIMED | UNREACHABLE | SUSPENDED | " +
"DISENROLLMENT_REQUESTED | REMOVED | BLOCKED | CREATED";
log.error(msg);
throw new BadRequestException(msg);
}
}
}
/**
* Checks if user requested action is valid.
*
* @param action action upon to filter devices using action
*/
public static void validateAction(String action) throws BadRequestException {
if (action.equals("SUBSCRIBED") || action.equals("UNSUBSCRIBED")) {
} else {
String msg = "Invalid action type received.Valid action types are SUBSCRIBED | UNSUBSCRIBED";
log.error(msg);
throw new BadRequestException(msg);
}
}
/**
* Checks if user requested ownerships are valid.
*
* @param ownership ownerships upon to filter devices using ownership
*/
public static void validateOwnershipType(String ownership) throws BadRequestException {
switch (ownership) {
case "BYOD":
case "COPE":
case "WORK_PROFILE":
case "GOOGLE_ENTERPRISE":
case "COSU":
case "FULLY_MANAGED":
case "DEDICATED_DEVICE":
break;
default:
String msg = "Invalid ownership type received.Valid ownership types are BYOD | COPE | WORK_PROFILE |" +
"GOOGLE_ENTERPRISE | COSU | FULLY_MANAGED | DEDICATED_DEVICE";
log.error(msg);
throw new BadRequestException(msg);
}
}
/**
* Checks if user requested Action status codes are valid.
*
* @param status status codes upon to filter operation logs using status
*/
public static void validateStatusFiltering(String status) throws BadRequestException {
if (Constants.OperationStatus.COMPLETED.toUpperCase().equals(status)
|| Constants.OperationStatus.ERROR.toUpperCase().equals(status)
|| Constants.OperationStatus.NOTNOW.toUpperCase().equals(status)
|| Constants.OperationStatus.REPEATED.toUpperCase().equals(status)
|| Constants.OperationStatus.PENDING.toUpperCase().equals(status)
|| Constants.OperationStatus.IN_PROGRESS.toUpperCase().equals(status)) {
} else {
String msg = "Invalid status type: " + status + ". \nValid status types are COMPLETED | ERROR | " +
"IN_PROGRESS | NOTNOW | PENDING | REPEATED";
log.error(msg);
throw new BadRequestException(msg);
}
}
}

@ -0,0 +1,101 @@
/*
* 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.
*
*
* 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.application.mgt.store.api.util;
/**
* Holds the constants used by DeviceImpl Management Admin web application.
*/
public class Constants {
public static final String USER_CLAIM_EMAIL_ADDRESS = "http://wso2.org/claims/emailaddress";
public static final String USER_CLAIM_FIRST_NAME = "http://wso2.org/claims/givenname";
public static final String USER_CLAIM_LAST_NAME = "http://wso2.org/claims/lastname";
public static final String USER_CLAIM_CREATED = "http://wso2.org/claims/created";
public static final String USER_CLAIM_MODIFIED = "http://wso2.org/claims/modified";
public static final String USER_CLAIM_DEVICES = "http://wso2.org/claims/devices";
public static final String PRIMARY_USER_STORE = "PRIMARY";
public static final String DEFAULT_STREAM_VERSION = "1.0.0";
public static final String SCOPE = "scope";
public static final String JDBC_USERSTOREMANAGER = "org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager";
public static final String DEFAULT_SIMPLE_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss Z";
public static final int DEFAULT_PAGE_LIMIT = 50;
public static final String FORWARD_SLASH = "/";
public static final String ANDROID = "android";
public static final String ANDROID_POLICY_VALIDATOR = "io.entgra.proprietary.platform.android." +
"core.polcy.AndroidPolicyPayloadValidator";
public static final String IOS = "ios";
public static final String WINDOWS = "windows";
public final class OperationStatus {
private OperationStatus () { throw new AssertionError(); }
public static final String COMPLETED = "completed";
public static final String ERROR = "error";
public static final String IN_PROGRESS = "in_progress";
public static final String PENDING = "pending";
public static final String NOTNOW = "notnow";
public static final String REPEATED = "repeated";
}
public static final String DEVICES = "devices";
public static final String ATTRIBUTE_DISPLAY_NAME = "DisplayName";
public static final String ATTRIBUTE_DESCRIPTION = "Description";
public static final String EXTERNAL_DEVICE_CLAIM_DISPLAY_NAME = "Devices";
public static final String EXTERNAL_DEVICE_CLAIM_DESCRIPTION = "Device list";
public final class ErrorMessages {
private ErrorMessages () { throw new AssertionError(); }
public static final String STATUS_BAD_REQUEST_MESSAGE_DEFAULT = "Bad Request";
}
public final class DeviceConstants {
private DeviceConstants () { throw new AssertionError(); }
public static final String APPLICATION_JSON = "application/json";
public static final String HEADER_CONTENT_TYPE = "Content-Type";
}
public final class Permission {
private Permission() { throw new AssertionError(); }
public static final String ADMIN = "/permission/admin";
public static final String LOGIN = "/permission/admin/login";
public static final String DEVICE_MGT = "/permission/admin/device-mgt";
public static final String APP_MGT = "/permission/admin/app-mgt";
}
}

@ -22,13 +22,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>application-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WSO2 Carbon - Application Management Component</name>
<description>WSO2 Carbon - Application Management Component</description>

@ -22,7 +22,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>certificate-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -38,13 +38,13 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>certificate-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.certificate.mgt.core</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Certificate Management Core</name>
<description>WSO2 Carbon - Certificate Management Core</description>

@ -22,14 +22,14 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>carbon-devicemgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>certificate-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WSO2 Carbon - Certificate Management Component</name>
<url>http://wso2.org</url>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt-extensions</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>carbon-devicemgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>device-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -20,7 +20,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -22,7 +22,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -0,0 +1,84 @@
/*
* Copyright (c) 2018-2021, Entgra (Pvt) Ltd. (http://www.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 org.wso2.carbon.device.mgt.common.geo.service.GeoCoordinate;
public class GeoCluster {
private final GeoCoordinate coordinates;
private final GeoCoordinate southWestBound;
private final GeoCoordinate northEastBound;
private final long count;
private final String geohashPrefix;
private final String deviceIdentification;
private final String deviceName;
private final String deviceType;
private final String lastSeen;
public GeoCluster(GeoCoordinate coordinates, GeoCoordinate southWestBound, GeoCoordinate northEastBound,
long count, String geohashPrefix, String deviceIdentification, String deviceName,
String deviceType, String lastSeen) {
this.coordinates = coordinates;
this.southWestBound = southWestBound;
this.northEastBound = northEastBound;
this.count = count;
this.geohashPrefix = geohashPrefix;
this.deviceIdentification = deviceIdentification;
this.deviceName = deviceName;
this.deviceType = deviceType;
this.lastSeen = lastSeen;
}
public String getGeohashPrefix() {
return geohashPrefix;
}
public long getCount() {
return count;
}
public GeoCoordinate getCoordinates() {
return coordinates;
}
public GeoCoordinate getSouthWestBound() {
return southWestBound;
}
public GeoCoordinate getNorthEastBound() {
return northEastBound;
}
public String getDeviceIdentification() {
return deviceIdentification;
}
public String getDeviceName() {
return deviceName;
}
public String getDeviceType() {
return deviceType;
}
public String getLastSeen() {
return lastSeen;
}
}

@ -48,6 +48,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* Activity related REST-API implementation.
@ -460,7 +461,7 @@ public interface ActivityInfoProviderService {
name = "deviceId",
value = "Device Id to filter"
)
@QueryParam("deviceId") String deviceId,
@QueryParam("deviceId") List<String> deviceIds,
@ApiParam(
name = "type",
value = "Operation type to filter"
@ -477,6 +478,16 @@ public interface ActivityInfoProviderService {
"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);
@HeaderParam("If-Modified-Since") String ifModifiedSince,
@ApiParam(
name = "startTimestamp",
value = "Starting unix timestamp value for filtering activities"
)
@QueryParam("startTimestamp") long startTimestamp,
@ApiParam(
name = "endTimestamp",
value = "Ending unix timestamp value for filtering activities"
)
@QueryParam("endTimestamp") long endTimestamp);
}

@ -269,6 +269,12 @@ public interface DeviceManagementService {
@QueryParam("ownership")
@Size(max = 45)
String ownership,
@ApiParam(
name = "serialNumber",
value = "The serial number of the device.",
required = false)
@QueryParam("serialNumber")
String serialNumber,
@ApiParam(
name = "status",
value = "Provide the device status details, such as active or inactive.",

@ -16,7 +16,6 @@
* under the License.
*/
package org.wso2.carbon.device.mgt.jaxrs.service.api;
import io.swagger.annotations.Api;
@ -32,6 +31,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.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.geo.service.Alert;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.GeofenceWrapper;
@ -41,7 +41,6 @@ import javax.validation.Valid;
import javax.validation.constraints.Size;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
@ -51,7 +50,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
@SwaggerDefinition(
info = @Info(
@ -208,6 +207,7 @@ public interface GeoLocationBasedService {
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
@Deprecated
Response getGeoDeviceLocations(
@ApiParam(
name = "deviceType",
@ -244,6 +244,124 @@ public interface GeoLocationBasedService {
defaultValue ="2")
@QueryParam("zoom") int zoom);
@Path("stats/geo-view")
@GET
@Consumes("application/json")
@Produces("application/json")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Getting geo view of devices",
notes = "Get the details of the devices that are within the map. The map area is enclosed with four " +
"coordinates in the shape of a square or rectangle. This is done by defining two points of the " +
"map. The other two points are automatically created using the given points. " +
"You can define the zoom level or scale of the map too.",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:analytics-view")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid parameters found.",
response = Response.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response getGeoDeviceView(
@ApiParam(
name = "minLat",
value = "Define the minimum latitude of the geofence.",
required = true,
defaultValue ="79.85213577747345")
@QueryParam("minLat") double minLat,
@ApiParam(
name = "maxLat",
value = "Define the maximum latitude of the geofence.",
required = true,
defaultValue ="79.85266149044037")
@QueryParam("maxLat") double maxLat,
@ApiParam(
name = "minLong",
value = "Define the minimum longitude of the geofence.",
required = true,
defaultValue ="6.909673257977737")
@QueryParam("minLong") double minLong,
@ApiParam(
name = "maxLong",
value = "Define the maximum longitude of the geofence",
required = true,
defaultValue ="6.909673257977737")
@QueryParam("maxLong") double maxLong,
@ApiParam(
name = "zoom",
value = "Define the level to zoom or scale the map. You can define any value between 1 to 14.",
required = true,
defaultValue ="2")
@QueryParam("zoom") int zoom,
@ApiParam(
name = "deviceType",
value = "Optional Device type name.")
@QueryParam("deviceType") List<String> deviceTypes,
@ApiParam(
name = "deviceIdentifier",
value = "Optional Device Identifier.")
@QueryParam("deviceIdentifier") List<String> deviceIdentifiers,
@ApiParam(
name = "status",
value = "Optional Device status.")
@QueryParam("status") List<EnrolmentInfo.Status> statuses,
@ApiParam(
name = "ownership",
value = "Optional Device ownership.")
@QueryParam("ownership") List<String> ownerships,
@ApiParam(
name = "owner",
value = "Optional Device owner.")
@QueryParam("owner") List<String> owners,
@ApiParam(
name = "noClusters",
value = "Optional include devices only.")
@QueryParam("noClusters") boolean noClusters,
@ApiParam(
name = "createdBefore",
value = "Optional Device created before timestamp.")
@QueryParam("createdBefore") long createdBefore,
@ApiParam(
name = "createdAfter",
value = "Optional Device created after timestamp..")
@QueryParam("createdAfter") long createdAfter,
@ApiParam(
name = "updatedBefore",
value = "Optional Device updated before timestamp.")
@QueryParam("updatedBefore") long updatedBefore,
@ApiParam(
name = "updatedAfter",
value = "Optional Device updated after timestamp.")
@QueryParam("updatedAfter") long updatedAfter);
/**
* Create Geo alerts

@ -15,6 +15,22 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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;
@ -45,6 +61,7 @@ import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
@ -243,6 +260,87 @@ public interface GroupManagementService {
@QueryParam("requireGroupProps")
boolean requireGroupProps);
@GET
@Path("/hierarchy")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "Getting the List of Hierarchical Groups",
notes = "Returns all groups enrolled with the system hierarchically.",
tags = "Device Group Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:groups:groups")
})
}
)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK. \n Successfully fetched the list of device hierarchical groups.",
response = DeviceGroupList.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. \n Empty body because the client has already the latest version of " +
"the requested resource."),
@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 groups list.",
response = ErrorResponse.class)
})
Response getGroupsWithHierarchy(
@ApiParam(
name = "name",
value = "Name of the group.")
@QueryParam("name")
String name,
@ApiParam(
name = "owner",
value = "Owner of the group.")
@QueryParam("owner")
String owner,
@ApiParam(
name = "requireGroupProps",
value = "Request group properties to include in the response",
defaultValue = "false")
@QueryParam("requireGroupProps")
boolean requireGroupProps,
@ApiParam(
name = "depth",
value = "Depth of the group hierarchy.")
@DefaultValue("3")
@QueryParam("depth")
int depth,
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.",
defaultValue = "0")
@DefaultValue("0")
@QueryParam("offset")
int offset,
@ApiParam(
name = "limit",
value = "Provide how many records require from the starting pagination index/offset.",
defaultValue = "5")
@DefaultValue("5")
@QueryParam("limit")
int limit);
@Path("/count")
@GET
@ApiOperation(
@ -412,7 +510,14 @@ public interface GroupManagementService {
value = "Request group properties to include in the response",
defaultValue = "false")
@QueryParam("requireGroupProps")
boolean requireGroupProps);
boolean requireGroupProps,
@ApiParam(
name = "depth",
value = "Depth of the group hierarchy.",
defaultValue = "1")
@DefaultValue("1")
@QueryParam("depth")
int depth);
@Path("/name/{groupName}")
@GET
@ -471,7 +576,14 @@ public interface GroupManagementService {
value = "Request group properties to include in the response",
defaultValue = "false")
@QueryParam("requireGroupProps")
boolean requireGroupProps);
boolean requireGroupProps,
@ApiParam(
name = "depth",
value = "Depth of the group hierarchy.",
defaultValue = "1")
@DefaultValue("1")
@QueryParam("depth")
int depth);
@Path("/id/{groupId}")
@PUT
@ -580,7 +692,12 @@ public interface GroupManagementService {
name = "groupId",
value = "ID of the group to be deleted.",
required = true)
@PathParam("groupId") int groupId);
@PathParam("groupId") int groupId,
@ApiParam(
name = "isDeleteChildren",
value = "Is the children groups needs to be deleted.",
required = true)
@QueryParam("isDeleteChildren") boolean isDeleteChildren);
@Path("/id/{groupId}/share")
@POST

@ -15,6 +15,22 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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;
@ -163,6 +179,90 @@ public interface GroupManagementAdminService {
@QueryParam("requireGroupProps")
boolean requireGroupProps);
@GET
@Path("hierarchy")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "Getting the List of Hierarchical Groups",
notes = "Returns all groups enrolled with the system hierarchically.",
tags = "Device Group Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:admin-groups:view")
})
}
)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK. \n Successfully fetched the list of device groups hierarchically.",
response = DeviceGroupList.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. \n Empty body because the client has already the latest version of " +
"the requested resource."),
@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 groups list.",
response = ErrorResponse.class)
})
Response getGroupsWithHierarchy(@ApiParam(
name = "name",
value = "Name of the group.")
@QueryParam("name")
String name,
@ApiParam(
name = "owner",
value = "Owner of the group.")
@QueryParam("owner")
String owner,
@ApiParam(
name = "status",
value = "status of group to be retrieve.")
@QueryParam("status")
String status,
@ApiParam(
name = "requireGroupProps",
value = "Request group properties to include in the response",
defaultValue = "false")
@QueryParam("requireGroupProps")
boolean requireGroupProps,
@ApiParam(
name = "depth",
value = "Depth of the group hierarchy.")
@DefaultValue("3")
@QueryParam("depth")
int depth,
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.",
defaultValue = "0")
@DefaultValue("0")
@QueryParam("offset")
int offset,
@ApiParam(
name = "limit",
value = "Provide how many records require from the starting pagination index/offset.",
defaultValue = "5")
@DefaultValue("5")
@QueryParam("limit")
int limit);
@Path("/count")
@GET
@ApiOperation(

@ -66,7 +66,7 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
@HeaderParam("If-Modified-Since") String ifModifiedSince) {
Activity activity;
DeviceManagementProviderService dmService;
Response response = validateAdminUser();
Response response = validateAdminPermission();
if (response == null) {
try {
RequestValidationUtil.validateActivityId(id);
@ -103,7 +103,7 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
return Response.status(400).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
Response validationFailedResponse = validateAdminUser();
Response validationFailedResponse = validateAdminPermission();
if (validationFailedResponse == null) {
List<Activity> activities;
ActivityList activityList = new ActivityList();
@ -184,7 +184,7 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
log.debug("getActivities -> Operation Code : " +operationCode+ "offset " + offset + " limit: " + limit );
}
RequestValidationUtil.validatePaginationParameters(offset, limit);
Response response = validateAdminUser();
Response response = validateAdminPermission();
if(response == null){
List<Activity> activities;
ActivityList activityList = new ActivityList();
@ -225,14 +225,17 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
@QueryParam("initiatedBy") String initiatedBy,
@QueryParam("operationCode") String operationCode,
@QueryParam("deviceType") String deviceType,
@QueryParam("deviceId") String deviceId,
@QueryParam("deviceId") List<String> deviceIds,
@QueryParam("type") String type,
@QueryParam("status") String status,
@HeaderParam("If-Modified-Since") String ifModifiedSince) {
@HeaderParam("If-Modified-Since") String ifModifiedSince,
@QueryParam("startTimestamp") long startTimestamp,
@QueryParam("endTimestamp") long endTimestamp) {
long ifModifiedSinceTimestamp;
long sinceTimestamp;
long timestamp = 0;
boolean isTimeDurationProvided = false;
if (log.isDebugEnabled()) {
log.debug("getActivities since: " + since + " , offset: " + offset + " ,limit: " + limit + " ," +
"ifModifiedSince: " + ifModifiedSince);
@ -262,9 +265,12 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
}
sinceTimestamp = sinceDate.getTime();
timestamp = sinceTimestamp / 1000;
} else if (startTimestamp > 0 && endTimestamp > 0) {
RequestValidationUtil.validateTimeDuration(startTimestamp, endTimestamp);
isTimeDurationProvided = true;
}
if (timestamp == 0) {
if (timestamp == 0 && !isTimeDurationProvided) {
//If timestamp is not sent by the user, a default value is set, that is equal to current time-12 hours.
long time = System.currentTimeMillis() / 1000;
timestamp = time - 42300;
@ -272,7 +278,7 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
if (log.isDebugEnabled()) {
log.debug("getActivities final timestamp " + timestamp);
}
Response response = validateAdminUser();
Response response = validateAdminPermission();
if (response == null) {
ActivityList activityList = new ActivityList();
DeviceManagementProviderService dmService;
@ -291,8 +297,8 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
if (deviceType != null && !deviceType.isEmpty()) {
activityPaginationRequest.setDeviceType(deviceType);
}
if (deviceId != null && !deviceId.isEmpty()) {
activityPaginationRequest.setDeviceId(deviceId);
if (deviceIds != null && !deviceIds.isEmpty()) {
activityPaginationRequest.setDeviceIds(deviceIds);
}
if (type != null && !type.isEmpty()) {
activityPaginationRequest.setType(Operation.Type.valueOf(type.toUpperCase()));
@ -300,7 +306,12 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
if (status != null && !status.isEmpty()) {
activityPaginationRequest.setStatus(Operation.Status.valueOf(status.toUpperCase()));
}
activityPaginationRequest.setSince(timestamp);
if (timestamp > 0) {
activityPaginationRequest.setSince(timestamp);
} else {
activityPaginationRequest.setStartTimestamp(startTimestamp);
activityPaginationRequest.setEndTimestamp(endTimestamp);
}
if (log.isDebugEnabled()) {
log.debug("Activity request: " + new Gson().toJson(activityPaginationRequest));
}
@ -330,19 +341,21 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
}
}
private Response validateAdminUser(){
private Response validateAdminPermission() {
//TODO: also check initiated by field to check current user has added the operation, if so allow access.
try {
if (!DeviceMgtAPIUtils.isAdmin()) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Unauthorized operation! Only admin role can perform " +
"this operation.").build();
if (!DeviceMgtAPIUtils.isAdminUser()) {
return Response.status(Response.Status.UNAUTHORIZED)
.entity("Unauthorized operation! Only users with CDM ADMIN PERMISSION " +
"can perform this operation.").build();
}
return null;
} catch (UserStoreException e) {
String msg
= "Error occurred while validating the user have admin role!";
String msg = "Error occurred while validating the user have admin permission!";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
}

@ -136,6 +136,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
@Path("/devices")
public class DeviceManagementServiceImpl implements DeviceManagementService {
@ -172,6 +173,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
@QueryParam("userPattern") String userPattern,
@QueryParam("role") String role,
@QueryParam("ownership") String ownership,
@QueryParam("serialNumber") String serialNumber,
@QueryParam("status") List<String> status,
@QueryParam("groupId") int groupId,
@QueryParam("since") String since,
@ -205,6 +207,9 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
RequestValidationUtil.validateOwnershipType(ownership);
request.setOwnership(ownership);
}
if (StringUtils.isNotBlank(serialNumber)) {
request.setSerialNumber(serialNumber);
}
if (status != null && !status.isEmpty()) {
boolean isStatusEmpty = true;
for (String statusString : status){
@ -911,7 +916,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
if (UUID != null) {
ApplicationInstallResponse response = subscriptionManager
.performBulkAppOperation(UUID, deviceIdentifiers, SubscriptionType.DEVICE.toString(),
"uninstall");
"uninstall", new Properties());
return Response.status(Response.Status.OK).entity(response).build();
//if the applications not installed via entgra store
} else {

@ -38,6 +38,7 @@ import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants.GeoServices;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
@ -47,13 +48,14 @@ import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.geo.service.Alert;
import org.wso2.carbon.device.mgt.common.geo.service.AlertAlreadyExistException;
import org.wso2.carbon.device.mgt.common.geo.service.Event;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCluster;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCoordinate;
import org.wso2.carbon.device.mgt.common.geo.service.GeoFence;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationBasedServiceException;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService;
import org.wso2.carbon.device.mgt.common.geo.service.GeoQuery;
import org.wso2.carbon.device.mgt.common.geo.service.GeofenceData;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.GeoHashLengthStrategy;
import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.ZoomGeoHashLengthStrategy;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
@ -81,7 +83,10 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -91,7 +96,7 @@ import java.util.Map;
*/
public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
private static Log log = LogFactory.getLog(GeoLocationBasedServiceImpl.class);
private static final Log log = LogFactory.getLog(GeoLocationBasedServiceImpl.class);
@Path("stats/{deviceType}/{deviceId}")
@GET
@ -155,6 +160,7 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
@GET
@Consumes("application/json")
@Produces("application/json")
@Deprecated
public Response getGeoDeviceLocations(
@QueryParam("deviceType") String deviceType,
@QueryParam("minLat") double minLat,
@ -162,6 +168,64 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
@QueryParam("minLong") double minLong,
@QueryParam("maxLong") double maxLong,
@QueryParam("zoom") int zoom) {
GeoHashLengthStrategy geoHashLengthStrategy = new ZoomGeoHashLengthStrategy();
GeoCoordinate southWest = new GeoCoordinate(minLat, minLong);
GeoCoordinate northEast = new GeoCoordinate(maxLat, maxLong);
int geohashLength = geoHashLengthStrategy.getGeohashLength(southWest, northEast, zoom);
DeviceManagementProviderService deviceManagementService = DeviceMgtAPIUtils.getDeviceManagementService();
GeoQuery geoQuery = new GeoQuery(southWest, northEast, geohashLength);
if (deviceType != null) {
geoQuery.setDeviceTypes(Collections.singletonList(deviceType));
}
List<org.wso2.carbon.device.mgt.jaxrs.beans.GeoCluster> geoClusters = new ArrayList<>();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
try {
List<GeoCluster> newClusters = deviceManagementService.findGeoClusters(geoQuery);
org.wso2.carbon.device.mgt.jaxrs.beans.GeoCluster geoCluster;
String deviceIdentification = null;
String deviceName = null;
String lastSeen = null;
for (GeoCluster gc : newClusters) {
if (gc.getDevice() != null) {
deviceIdentification = gc.getDevice().getDeviceIdentifier();
deviceName = gc.getDevice().getName();
deviceType = gc.getDevice().getType();
lastSeen = simpleDateFormat.format(new Date(gc.getDevice()
.getEnrolmentInfo().getDateOfLastUpdate()));
}
geoCluster = new org.wso2.carbon.device.mgt.jaxrs.beans.GeoCluster(gc.getCoordinates(),
gc.getSouthWestBound(), gc.getNorthEastBound(), gc.getCount(), gc.getGeohashPrefix(),
deviceIdentification, deviceName, deviceType, lastSeen);
geoClusters.add(geoCluster);
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while retrieving geo clusters query: " + new Gson().toJson(geoQuery);
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
return Response.ok().entity(geoClusters).build();
}
@Path("stats/geo-view")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeoDeviceView(
@QueryParam("minLat") double minLat,
@QueryParam("maxLat") double maxLat,
@QueryParam("minLong") double minLong,
@QueryParam("maxLong") double maxLong,
@QueryParam("zoom") int zoom,
@QueryParam("deviceType") List<String> deviceTypes,
@QueryParam("deviceIdentifier") List<String> deviceIdentifiers,
@QueryParam("status") List<EnrolmentInfo.Status> statuses,
@QueryParam("ownership") List<String> ownerships,
@QueryParam("owner") List<String> owners,
@QueryParam("noClusters") boolean noClusters,
@QueryParam("createdBefore") long createdBefore,
@QueryParam("createdAfter") long createdAfter,
@QueryParam("updatedBefore") long updatedBefore,
@QueryParam("updatedAfter") long updatedAfter) {
GeoHashLengthStrategy geoHashLengthStrategy = new ZoomGeoHashLengthStrategy();
GeoCoordinate southWest = new GeoCoordinate(minLat, minLong);
@ -169,15 +233,25 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
int geohashLength = geoHashLengthStrategy.getGeohashLength(southWest, northEast, zoom);
DeviceManagementProviderService deviceManagementService = DeviceMgtAPIUtils.getDeviceManagementService();
List<GeoCluster> geoClusters;
GeoQuery geoQuery = new GeoQuery(southWest, northEast, geohashLength);
geoQuery.setDeviceTypes(deviceTypes);
geoQuery.setDeviceIdentifiers(deviceIdentifiers);
geoQuery.setStatuses(statuses);
geoQuery.setOwners(owners);
geoQuery.setOwnerships(ownerships);
geoQuery.setNoClusters(noClusters);
geoQuery.setCreatedBefore(createdBefore);
geoQuery.setCreatedAfter(createdAfter);
geoQuery.setUpdatedBefore(updatedBefore);
geoQuery.setUpdatedAfter(updatedAfter);
try {
geoClusters = deviceManagementService.findGeoClusters(deviceType, southWest, northEast, geohashLength);
geoClusters = deviceManagementService.findGeoClusters(geoQuery);
} catch (DeviceManagementException e) {
String msg = "Error occurred while retrieving geo clusters ";
String msg = "Error occurred while retrieving geo clusters for query: " + new Gson().toJson(geoQuery);
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
return Response.ok().entity(geoClusters).build();
}
@Path("alerts/{alertType}/{deviceType}/{deviceId}")

@ -15,6 +15,22 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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;
@ -36,7 +52,6 @@ import org.wso2.carbon.device.mgt.common.group.mgt.GroupAlreadyExistException;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupNotExistException;
import org.wso2.carbon.device.mgt.common.group.mgt.RoleDoesNotExistException;
import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList;
@ -47,10 +62,12 @@ import org.wso2.carbon.device.mgt.jaxrs.service.api.GroupManagementService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.policy.mgt.common.PolicyAdministratorPoint;
import org.wso2.carbon.policy.mgt.common.PolicyEvaluationException;
import org.wso2.carbon.policy.mgt.common.PolicyEvaluationPoint;
import org.wso2.carbon.policy.mgt.common.PolicyManagementException;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
@ -89,11 +106,41 @@ public class GroupManagementServiceImpl implements GroupManagementService {
}
}
@GET
@Path("/hierarchy")
@Override
public Response getGroupsWithHierarchy(
@QueryParam("name") String name,
@QueryParam("owner") String owner,
@QueryParam("requireGroupProps") boolean requireGroupProps,
@DefaultValue("3") @QueryParam("depth") int depth,
@DefaultValue("0") @QueryParam("offset") int offset,
@DefaultValue("5") @QueryParam("limit") int limit) {
try {
RequestValidationUtil.validatePaginationParameters(offset, limit);
String currentUser = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
GroupPaginationRequest request = new GroupPaginationRequest(offset, limit);
request.setGroupName(name);
request.setOwner(owner);
request.setDepth(depth);
PaginationResult deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(currentUser, request, requireGroupProps);
DeviceGroupList deviceGroupList = new DeviceGroupList();
deviceGroupList.setList(deviceGroupsResult.getData());
deviceGroupList.setCount(deviceGroupsResult.getRecordsTotal());
return Response.status(Response.Status.OK).entity(deviceGroupList).build();
} catch (GroupManagementException e) {
String error = "Error occurred while retrieving groups with hierarchy.";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Override
public Response getGroupCount() {
try {
String currentUser = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
int count = DeviceMgtAPIUtils.getGroupManagementProviderService().getGroupCount(currentUser);
int count = DeviceMgtAPIUtils.getGroupManagementProviderService().getGroupCount(currentUser, null);
return Response.status(Response.Status.OK).entity(count).build();
} catch (GroupManagementException e) {
String msg = "Error occurred while retrieving group count.";
@ -125,10 +172,10 @@ public class GroupManagementServiceImpl implements GroupManagementService {
}
@Override
public Response getGroup(int groupId, boolean requireGroupProps) {
public Response getGroup(int groupId, boolean requireGroupProps, int depth) {
try {
GroupManagementProviderService service = DeviceMgtAPIUtils.getGroupManagementProviderService();
DeviceGroup deviceGroup = service.getGroup(groupId, requireGroupProps);
DeviceGroup deviceGroup = service.getGroup(groupId, requireGroupProps, depth);
if (deviceGroup != null) {
return Response.status(Response.Status.OK).entity(deviceGroup).build();
} else {
@ -142,7 +189,7 @@ public class GroupManagementServiceImpl implements GroupManagementService {
}
@Override
public Response getGroup(String groupName, boolean requireGroupProps) {
public Response getGroup(String groupName, boolean requireGroupProps, int depth) {
try {
GroupManagementProviderService service = DeviceMgtAPIUtils.getGroupManagementProviderService();
DeviceGroup deviceGroup = service.getGroup(groupName, requireGroupProps);
@ -178,9 +225,9 @@ public class GroupManagementServiceImpl implements GroupManagementService {
}
@Override
public Response deleteGroup(int groupId) {
public Response deleteGroup(int groupId, boolean isDeleteChildren) {
try {
if (DeviceMgtAPIUtils.getGroupManagementProviderService().deleteGroup(groupId)) {
if (DeviceMgtAPIUtils.getGroupManagementProviderService().deleteGroup(groupId, isDeleteChildren)) {
return Response.status(Response.Status.OK).build();
} else {
return Response.status(Response.Status.NOT_FOUND).entity("Group not found.").build();

@ -15,6 +15,22 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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;
@ -31,6 +47,10 @@ import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.GroupManagementAdminSe
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
@ -74,6 +94,37 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
}
}
@GET
@Path("/hierarchy")
@Override
public Response getGroupsWithHierarchy(
@QueryParam("name") String name,
@QueryParam("owner") String owner,
@QueryParam("status") String status,
@QueryParam("requireGroupProps") boolean requireGroupProps,
@DefaultValue("3") @QueryParam("depth") int depth,
@DefaultValue("0") @QueryParam("offset") int offset,
@DefaultValue("5") @QueryParam("limit") int limit) {
try {
RequestValidationUtil.validatePaginationParameters(offset, limit);
GroupPaginationRequest request = new GroupPaginationRequest(offset, limit);
request.setGroupName(name);
request.setOwner(owner);
request.setStatus(status);
request.setDepth(depth);
PaginationResult deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(null, request, requireGroupProps);
DeviceGroupList deviceGroupList = new DeviceGroupList();
deviceGroupList.setList(deviceGroupsResult.getData());
deviceGroupList.setCount(deviceGroupsResult.getRecordsTotal());
return Response.status(Response.Status.OK).entity(deviceGroupList).build();
} catch (GroupManagementException e) {
String error = "Error occurred while retrieving groups with hierarchy.";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
}
}
@Override
public Response getGroupCount(String status) {
try {

@ -769,4 +769,13 @@ public class RequestValidationUtil {
}
}
}
public static void validateTimeDuration(long startTimestamp, long endTimestamp) {
if (startTimestamp > endTimestamp) {
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l)
.setMessage("Request parameter startTimestamp should not be " +
"a higher value than endTimestamp").build());
}
}
}

@ -45,6 +45,7 @@ import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.analytics.stream.persistence.stub.EventStreamPersistenceAdminServiceStub;
import org.wso2.carbon.apimgt.integration.client.service.IntegrationClientService;
import org.wso2.carbon.base.ServerConfiguration;
@ -84,6 +85,8 @@ import org.wso2.carbon.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
import org.wso2.carbon.device.mgt.core.dto.DeviceTypeVersion;
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionUtils;
import org.wso2.carbon.device.mgt.core.privacy.PrivacyComplianceProvider;
import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
@ -144,6 +147,7 @@ import java.util.Queue;
*/
public class DeviceMgtAPIUtils {
private final static String CDM_ADMIN_PERMISSION = "/device-mgt/devices/any-device/permitted-actions-under-owning-device";
private static final String NOTIFIER_FREQUENCY = "notifierFrequency";
private static final String STREAM_DEFINITION_PREFIX = "iot.per.device.stream.";
private static final String DEFAULT_HTTP_PROTOCOL = "https";
@ -885,6 +889,27 @@ public class DeviceMgtAPIUtils {
return false;
}
public static boolean isAdminUser() throws UserStoreException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
UserRealm userRealm = DeviceMgtAPIUtils.getRealmService().getTenantUserRealm(tenantId);
if (userRealm != null && userRealm.getAuthorizationManager() != null) {
return userRealm.getAuthorizationManager()
.isUserAuthorized(removeTenantDomain(userName),
PermissionUtils.getAbsolutePermissionPath(CDM_ADMIN_PERMISSION),
CarbonConstants.UI_PERMISSION_ACTION);
}
return false;
}
private static String removeTenantDomain(String username) {
String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
if (username.endsWith(tenantDomain)) {
return username.substring(0, username.lastIndexOf("@"));
}
return username;
}
public static DeviceTypeVersion convertDeviceTypeVersionWrapper(String deviceTypeName, int deviceTypeId,
DeviceTypeVersionWrapper deviceTypeVersion) {
DeviceTypeVersion typeVersion = new DeviceTypeVersion();

@ -175,7 +175,8 @@ public class DeviceManagementServiceImplTest {
.toReturn(this.deviceAccessAuthorizationService);
Response response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -194,19 +195,23 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, null, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, true, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, true,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
}
@ -319,7 +324,7 @@ public class DeviceManagementServiceImplTest {
.toReturn(this.deviceManagementProviderService);
Mockito.when(deviceAccessAuthorizationService.isDeviceAdminUser()).thenReturn(true);
deviceManagementService.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null,
DEFAULT_ROLE, DEFAULT_OWNERSHIP, DEFAULT_STATUS_LIST, 1,
DEFAULT_ROLE, DEFAULT_OWNERSHIP, null, DEFAULT_STATUS_LIST, 1,
null, null, false, 10, 5);
}
@ -339,11 +344,11 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP
, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, null, DEFAULT_USERNAME, DEFAULT_ROLE, DEFAULT_OWNERSHIP
, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
}
@ -365,7 +370,8 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 0, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode());
Mockito.reset(this.deviceAccessAuthorizationService);
}
@ -386,15 +392,18 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, false, 10, 5);
null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, true, 10, 5);
null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, true,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, null, "ErrorModifiedSince", false, 10, 5);
null, DEFAULT_STATUS_LIST, 0, null, "ErrorModifiedSince",
false, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -414,15 +423,18 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, since, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 0, since, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, since, null, true, 10, 5);
null, DEFAULT_STATUS_LIST, 0, since, null, true,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 0, "ErrorSince", null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 0, "ErrorSince", null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -444,7 +456,8 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
Mockito.reset(this.deviceManagementProviderService);
}
@ -466,7 +479,8 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
null, DEFAULT_STATUS_LIST, 1, null, null, false,
10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
Mockito.reset(this.deviceAccessAuthorizationService);
}

@ -7,8 +7,9 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCluster;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCoordinate;
import org.wso2.carbon.device.mgt.common.geo.service.GeoQuery;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.jaxrs.service.api.GeoLocationBasedService;
@ -33,8 +34,9 @@ public class GeoLocationBasedServiceImplTest {
@Test(description = "This method tests the behaviour of getGeoDeviceLocations when there are no devices" +
"in the given map boundaries")
public void testGetGeoDeviceLocations1() throws DeviceManagementException {
GeoQuery geoQuery = new GeoQuery(Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
Mockito.doReturn(new ArrayList<GeoCluster>()).when(deviceManagementProviderService)
.findGeoClusters(null, Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
.findGeoClusters(geoQuery);
Response response = geoLocationBasedService.getGeoDeviceLocations(null, 0.4, 15, 75.6,
90.1, 6);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
@ -47,12 +49,14 @@ public class GeoLocationBasedServiceImplTest {
List<GeoCluster> geoClusters = new ArrayList<>();
geoClusters.add(new GeoCluster(new GeoCoordinate(1.5, 80.7),
new GeoCoordinate(1.1, 79.5), new GeoCoordinate(1.9, 82.1), 3,
"tb32", "aegtew234", "test1", "android", "1234"));
"tb32", null));
geoClusters.add(new GeoCluster(new GeoCoordinate(10.2, 86.1),
new GeoCoordinate(9.8, 84.7), new GeoCoordinate(11.1, 88.1), 4,
"t1gd", "swerty12s", "t2test", "android", "1234"));
"t1gd", null));
GeoQuery geoQuery = new GeoQuery(Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
Mockito.doReturn(geoClusters).when(deviceManagementProviderService)
.findGeoClusters(null, Mockito.any(GeoCoordinate.class), Mockito.any(GeoCoordinate.class), Mockito.anyInt());
.findGeoClusters(geoQuery);
Response response = geoLocationBasedService.getGeoDeviceLocations(null, 0.4, 15, 75.6,
90.1, 6);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),

@ -15,11 +15,26 @@
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
@ -130,13 +145,14 @@ public class GroupManagementServiceImplTest {
.toReturn(groupManagementProviderService);
PowerMockito.stub(PowerMockito.method(PrivilegedCarbonContext.class, "getThreadLocalCarbonContext"))
.toReturn(context);
Mockito.doReturn(2).when(groupManagementProviderService).getGroupCount(Mockito.anyString());
Mockito.doReturn(2).when(groupManagementProviderService)
.getGroupCount(Mockito.anyString(), Mockito.anyString());
Response response = groupManagementService.getGroupCount();
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
"GetGroupCount request failed with valid parameters");
Mockito.reset(groupManagementProviderService);
Mockito.doThrow(new GroupManagementException()).when(groupManagementProviderService)
.getGroupCount(Mockito.anyString());
.getGroupCount(Mockito.anyString(), Mockito.anyString());
response = groupManagementService.getGroupCount();
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"GetGroupCount request succeeded with in-valid parameters");
@ -174,16 +190,16 @@ public class GroupManagementServiceImplTest {
public void testGetGroup() throws GroupManagementException {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getGroupManagementProviderService"))
.toReturn(groupManagementProviderService);
Mockito.doReturn(new DeviceGroup()).when(groupManagementProviderService).getGroup(1, false);
Mockito.doReturn(null).when(groupManagementProviderService).getGroup(2, false);
Mockito.doThrow(new GroupManagementException()).when(groupManagementProviderService).getGroup(3, false);
Response response = groupManagementService.getGroup(1, false);
Mockito.doReturn(new DeviceGroup()).when(groupManagementProviderService).getGroup(1, false, 1);
Mockito.doReturn(null).when(groupManagementProviderService).getGroup(2, false, 1);
Mockito.doThrow(new GroupManagementException()).when(groupManagementProviderService).getGroup(3, false, 1);
Response response = groupManagementService.getGroup(1, false, 1);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
"getGroup request failed for a request with valid parameters");
response = groupManagementService.getGroup(2, false);
response = groupManagementService.getGroup(2, false, 1);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode(),
"getGroup request returned a group for a non-existing group");
response = groupManagementService.getGroup(3, false);
response = groupManagementService.getGroup(3, false, 1);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"getGroup request returned a group for a in-valid request");
}
@ -216,16 +232,16 @@ public class GroupManagementServiceImplTest {
public void testDeleteGroup() throws GroupManagementException {
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getGroupManagementProviderService"))
.toReturn(groupManagementProviderService);
Mockito.doReturn(true).when(groupManagementProviderService).deleteGroup(1);
Mockito.doReturn(false).when(groupManagementProviderService).deleteGroup(2);
Mockito.doThrow(new GroupManagementException()).when(groupManagementProviderService).deleteGroup(3);
Response response = groupManagementService.deleteGroup(1);
Mockito.doReturn(true).when(groupManagementProviderService).deleteGroup(1, false);
Mockito.doReturn(false).when(groupManagementProviderService).deleteGroup(2, false);
Mockito.doThrow(new GroupManagementException()).when(groupManagementProviderService).deleteGroup(3, false);
Response response = groupManagementService.deleteGroup(1, false);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
"delete group request failed for a request with valid parameters");
response = groupManagementService.deleteGroup(2);
response = groupManagementService.deleteGroup(2, false);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode(),
"Non-existing group was successfully deleted");
response = groupManagementService.deleteGroup(3);
response = groupManagementService.deleteGroup(3, false);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"Deletion succeeded with an erroneous condition.");
}

@ -21,7 +21,7 @@
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -20,6 +20,8 @@ package org.wso2.carbon.device.mgt.common;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import java.util.List;
/**
* This class holds required parameters for a querying a paginated activity response.
*/
@ -28,12 +30,14 @@ public class ActivityPaginationRequest {
private int offset;
private int limit;
private String deviceType;
private String deviceId;
private List<String> deviceIds;
private String operationCode;
private String initiatedBy;
private long since;
private Operation.Type type;
private Operation.Status status;
private long startTimestamp;
private long endTimestamp;
public ActivityPaginationRequest(int offset, int limit) {
this.offset = offset;
@ -64,12 +68,12 @@ public class ActivityPaginationRequest {
this.deviceType = deviceType;
}
public String getDeviceId() {
return deviceId;
public List<String> getDeviceIds() {
return deviceIds;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
public void setDeviceIds(List<String> deviceIds) {
this.deviceIds = deviceIds;
}
public String getOperationCode() {
@ -113,4 +117,19 @@ public class ActivityPaginationRequest {
this.status = status;
}
public long getStartTimestamp() {
return startTimestamp;
}
public void setStartTimestamp(long startTimestamp) {
this.startTimestamp = startTimestamp;
}
public long getEndTimestamp() {
return endTimestamp;
}
public void setEndTimestamp(long endTimestamp) {
this.endTimestamp = endTimestamp;
}
}

@ -32,7 +32,7 @@ public class EnrolmentInfo implements Serializable {
public enum Status {
CREATED, ACTIVE, INACTIVE, UNREACHABLE, UNCLAIMED, SUSPENDED, BLOCKED, REMOVED, DISENROLLMENT_REQUESTED,
CONFIGURED, READY_TO_CONNECT, RETURN_PENDING, RETURNED, DEFECTIVE, WARRANTY_PENDING, WARRANTY_SENT,
WARRANTY_REPLACED
WARRANTY_REPLACED, ASSIGNED
}
public enum OwnerShip {

@ -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) 2021, 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.common;
@ -28,6 +45,8 @@ public class GroupPaginationRequest {
private String owner;
private String groupName;
private String status;
private String parentPath;
private int depth;
public GroupPaginationRequest(int start, int rowCount) {
this.startIndex = start;
@ -74,6 +93,22 @@ public class GroupPaginationRequest {
this.groupName = groupName;
}
public String getParentPath() {
return parentPath;
}
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
public int getDepth() {
return depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
@Override
public String toString() {
return "Group Name '" + this.groupName + "' num of rows: " + this.rowCount + " start index: " + this.startIndex

@ -45,6 +45,7 @@ public class MDMAppConstants {
private AndroidConstants() {
throw new AssertionError();
}
public static final String IS_BLOCK_UNINSTALL = "isBlockUninstall";
public static final String OPCODE_INSTALL_APPLICATION = "INSTALL_APPLICATION";
public static final String OPCODE_UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION";
public static final String UNMANAGED_APP_UNINSTALL= "UNMANAGED_APP_UNINSTALL";
@ -56,6 +57,7 @@ public class MDMAppConstants {
throw new AssertionError();
}
public static final String INSTALL_ENTERPRISE_APPLICATION = "INSTALL_ENTERPRISE_APPLICATION";
public static final String UNINSTALL_ENTERPRISE_APPLICATION = "UNINSTALL_ENTERPRISE_APPLICATION";
//App type constants related to window device type
public static final String MSI = "MSI";
public static final String APPX = "APPX";

@ -40,6 +40,7 @@ public class PaginationRequest {
private String ownerRole;
private Date since;
private String filter;
private String serialNumber;
private Map<String, Object> property = new HashMap<>();
private List<String> statusList = new ArrayList<>();
private OperationLogFilters operationLogFilters = new OperationLogFilters();
@ -153,6 +154,10 @@ public class PaginationRequest {
return this.property.get(key);
}
public String getSerialNumber() { return serialNumber; }
public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; }
public Map<String, Object> getProperties() {
Map<String, Object> temp = new HashMap<>();
temp.putAll(property);

@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.common.app.mgt.android;
import com.google.gson.Gson;
import java.io.Serializable;
import java.util.Properties;
/**
* This class represents the Appstore AuthenticationImpl information.
@ -29,6 +30,7 @@ public class AppStoreApplication implements Serializable {
private String type;
private String appIdentifier;
private Properties properties;
public String getType() {
return type;
@ -51,4 +53,11 @@ public class AppStoreApplication implements Serializable {
return gson.toJson(this);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.common.app.mgt.android;
import com.google.gson.Gson;
import java.io.Serializable;
import java.util.Properties;
/**
* This class represents the Enterprise AuthenticationImpl information.
@ -30,6 +31,7 @@ public class EnterpriseApplication implements Serializable {
private String type;
private String url;
private String appIdentifier;
private Properties properties;
public String getAppIdentifier() {
return appIdentifier;
@ -60,4 +62,11 @@ public class EnterpriseApplication implements Serializable {
return gson.toJson(this);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.common.app.mgt.android;
import com.google.gson.Gson;
import java.io.Serializable;
import java.util.Properties;
/**
* This class represents the Web AuthenticationImpl information.
@ -30,6 +31,7 @@ public class WebApplication implements Serializable {
private String name;
private String url;
private String type;
private Properties properties;
public String getName() {
return name;
@ -60,4 +62,11 @@ public class WebApplication implements Serializable {
return gson.toJson(this);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2021, Entgra (Pvt) Ltd. (http://www.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.geo.service;
import org.wso2.carbon.device.mgt.common.Device;
public class GeoCluster {
private final GeoCoordinate coordinates;
private final GeoCoordinate southWestBound;
private final GeoCoordinate northEastBound;
private final long count;
private final String geohashPrefix;
private final Device device;
public GeoCluster(GeoCoordinate coordinates, GeoCoordinate southWestBound, GeoCoordinate northEastBound,
long count, String geohashPrefix, Device device) {
this.coordinates = coordinates;
this.southWestBound = southWestBound;
this.northEastBound = northEastBound;
this.count = count;
this.geohashPrefix = geohashPrefix;
this.device = device;
}
public String getGeohashPrefix() {
return geohashPrefix;
}
public long getCount() {
return count;
}
public GeoCoordinate getCoordinates() {
return coordinates;
}
public GeoCoordinate getSouthWestBound() {
return southWestBound;
}
public GeoCoordinate getNorthEastBound() {
return northEastBound;
}
public Device getDevice() {
return device;
}
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2021, Entgra (Pvt) Ltd. (http://www.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.geo.service;
public class GeoCoordinate {
private final double latitude;
private final double longitude;
public GeoCoordinate(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}

@ -0,0 +1,139 @@
/*
* Copyright (c) 2018-2021, Entgra (Pvt) Ltd. (http://www.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.geo.service;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import java.util.List;
public class GeoQuery {
private final GeoCoordinate southWest;
private final GeoCoordinate northEast;
private final int geohashLength;
private List<String> deviceTypes;
private List<String> deviceIdentifiers;
private List<EnrolmentInfo.Status> statuses;
private List<String> ownerships;
private List<String> owners;
private boolean noClusters;
private long createdBefore;
private long createdAfter;
private long updatedBefore;
private long updatedAfter;
public GeoQuery(GeoCoordinate southWest, GeoCoordinate northEast, int geohashLength) {
this.southWest = southWest;
this.northEast = northEast;
this.geohashLength = geohashLength;
}
public GeoCoordinate getSouthWest() {
return southWest;
}
public GeoCoordinate getNorthEast() {
return northEast;
}
public int getGeohashLength() {
return geohashLength;
}
public List<String> getDeviceTypes() {
return deviceTypes;
}
public void setDeviceTypes(List<String> deviceTypes) {
this.deviceTypes = deviceTypes;
}
public List<String> getDeviceIdentifiers() {
return deviceIdentifiers;
}
public void setDeviceIdentifiers(List<String> deviceIdentifiers) {
this.deviceIdentifiers = deviceIdentifiers;
}
public List<EnrolmentInfo.Status> getStatuses() {
return statuses;
}
public void setStatuses(List<EnrolmentInfo.Status> statuses) {
this.statuses = statuses;
}
public List<String> getOwnerships() {
return ownerships;
}
public void setOwnerships(List<String> ownerships) {
this.ownerships = ownerships;
}
public List<String> getOwners() {
return owners;
}
public void setOwners(List<String> owners) {
this.owners = owners;
}
public boolean isNoClusters() {
return noClusters;
}
public void setNoClusters(boolean noClusters) {
this.noClusters = noClusters;
}
public long getCreatedBefore() {
return createdBefore;
}
public void setCreatedBefore(long createdBefore) {
this.createdBefore = createdBefore;
}
public long getCreatedAfter() {
return createdAfter;
}
public void setCreatedAfter(long createdAfter) {
this.createdAfter = createdAfter;
}
public long getUpdatedBefore() {
return updatedBefore;
}
public void setUpdatedBefore(long updatedBefore) {
this.updatedBefore = updatedBefore;
}
public long getUpdatedAfter() {
return updatedAfter;
}
public void setUpdatedAfter(long updatedAfter) {
this.updatedAfter = updatedAfter;
}
}

@ -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) 2021, 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.common.group.mgt;
@ -21,6 +38,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
@ -47,6 +65,15 @@ public class DeviceGroup implements Serializable {
@ApiModelProperty(name = "status", value = "The status of group that needs updating/retrieval.")
private String status;
@ApiModelProperty(name = "parentGroupId", value = "Group ID of parent group")
private int parentGroupId;
@ApiModelProperty(name = "parentPath", value = "Path of parent group")
private String parentPath;
@ApiModelProperty(name = "childrenGroups", value = "Children groups")
private List<DeviceGroup> childrenGroups;
public String getStatus() {
return status;
}
@ -103,4 +130,27 @@ public class DeviceGroup implements Serializable {
this.groupProperties = groupProperties;
}
public int getParentGroupId() {
return parentGroupId;
}
public void setParentGroupId(int parentGroupId) {
this.parentGroupId = parentGroupId;
}
public String getParentPath() {
return parentPath;
}
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
public List<DeviceGroup> getChildrenGroups() {
return childrenGroups;
}
public void setChildrenGroups(List<DeviceGroup> childrenGroups) {
this.childrenGroups = childrenGroups;
}
}

@ -84,4 +84,8 @@ public class DeviceGroupConstants {
public static final String[] DEFAULT_VIEW_EVENTS_PERMISSIONS =
{"/permission/device-mgt/user/groups/device_events"};
}
public static final class HierarchicalGroup {
public static final String SEPERATOR = "/";
}
}

@ -30,7 +30,7 @@ import java.util.List;
public class ActivityStatus {
public enum Status {
IN_PROGRESS, PENDING, COMPLETED, ERROR, REPEATED, INVALID, UNAUTHORIZED
IN_PROGRESS, PENDING, COMPLETED, ERROR, REPEATED, INVALID, UNAUTHORIZED, NOTNOW
}
@ApiModelProperty(

@ -27,6 +27,7 @@ public class Item {
private String label;
private String tooltip;
private String docLink;
private String key;
private String value;
private boolean isRequired;
@ -65,6 +66,16 @@ public class Item {
this.tooltip = tooltip;
}
@XmlElement(name = "DocLink")
public String getDocLink() {
return docLink;
}
public void setDocLink(String docLink) {
this.docLink = docLink;
}
@XmlElement(name = "Key", required = true)
public String getKey() {
return key;

@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>device-mgt</artifactId>
<version>4.1.15</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

@ -31,6 +31,8 @@ public class UIConfiguration {
private AppRegistration appRegistration;
private List<String> scopes;
private boolean isSsoEnable;
private int sessionTimeOut;
private int loginCacheCapacity;
@XmlElement(name = "AppRegistration", required=true)
public AppRegistration getAppRegistration() {
@ -59,4 +61,22 @@ public class UIConfiguration {
public void setSsoEnable(boolean ssoEnable) {
isSsoEnable = ssoEnable;
}
@XmlElement(name = "SessionTimeOut")
public int getSessionTimeOut() {
return sessionTimeOut;
}
public void setSessionTimeOut(int sessionTimeOut) {
this.sessionTimeOut = sessionTimeOut;
}
@XmlElement(name = "LoginCacheCapacity")
public int getLoginCacheCapacity() {
return loginCacheCapacity;
}
public void setLoginCacheCapacity(int loginCacheCapacity) {
this.loginCacheCapacity = loginCacheCapacity;
}
}

@ -46,9 +46,10 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
import org.wso2.carbon.device.mgt.common.geo.service.GeoQuery;
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCluster;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCoordinate;
import java.sql.SQLException;
import java.util.Date;
@ -555,14 +556,11 @@ public interface DeviceDAO {
* This method is used to retrieve the details of geoclusters formed relatively to the zoom level and map
* boundaries.
*
* @param deviceType Optional device type name.
* @param southWest the coordinates of southWest corner of the map.
* @param northEast the coordinates of northEast corner of the map.
* @param tenantId tenant id.
* @param geoQuery the query to determine the geo data.
* @param tenantId tenant id.
* @return returns a list of enrolment info objects.
*/
List<GeoCluster> findGeoClusters(String deviceType, GeoCoordinate southWest, GeoCoordinate northEast,
int geohashLength,int tenantId) throws DeviceManagementDAOException;
List<GeoCluster> findGeoClusters(GeoQuery geoQuery, int tenantId) throws DeviceManagementDAOException;
/**
* This method is used to identify whether given device ids are exist or not.
@ -651,16 +649,14 @@ public interface DeviceDAO {
/**
* This method is used to get the details of subscribed devices.
*
* @param deviceIds device ids of the subscribed devices.
* @param tenantId Id of the current tenant.
* @param offsetValue offset value for get paginated request.
* @param limitValue limit value for get paginated request.
* @param status status of the devices.
* @param deviceIds device ids of the subscribed devices.
* @param tenantId Id of the current tenant.
* @param request paginated request object.
* @return devices - subscribed device details list
* @throws DeviceManagementDAOException if connections establishment fails.
*/
List<Device> getSubscribedDevices(int offsetValue, int limitValue, List<Integer> deviceIds,
int tenantId, List<String> status) throws DeviceManagementDAOException;
List<Device> getSubscribedDevices(PaginationRequest request, List<Integer> deviceIds, int tenantId)
throws DeviceManagementDAOException;
/**
* @param deviceIds device ids of the subscribed devices.
@ -762,4 +758,27 @@ public interface DeviceDAO {
String version) throws DeviceManagementDAOException;
int getFunctioningDevicesInSystem() throws DeviceManagementDAOException;
/**
* This method is used to get the details of devices when give deviceIDs list and group name.
* @param deviceIds device ids of the devices.
* @param tenantId Id of the current tenant.
* @param request paginated request object.
* @param groupName group name.
* @return devices - device details list
* @throws DeviceManagementDAOException if connections establishment fails.
*/
List<Device> getGroupedDevicesDetails(PaginationRequest request, List<Integer> deviceIds, String groupName,
int tenantId) throws DeviceManagementDAOException;
/**
* @param deviceIds device ids of the devices.
* @param tenantId tenant id
* @param request paginated request object.
* @param groupName group name.
* @return number of device count under the group name.
* @throws DeviceManagementDAOException if error occurred while processing the SQL statement.
*/
int getGroupedDevicesCount(PaginationRequest request, List<Integer> deviceIds, String groupName, int tenantId)
throws DeviceManagementDAOException;
}

@ -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) 2021, 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.core.dao;
@ -74,6 +91,15 @@ public interface GroupDAO {
*/
void deleteAllGroupProperties(int groupId, int tenantId) throws GroupManagementDAOException;
/**
* Remove properties of device groups.
*
* @param groupIds to be deleted.
* @param tenantId of the group.
* @throws GroupManagementDAOException on error during deletion of group properties of groups
*/
void deleteAllGroupsProperties(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException;
/**
* Retrives all properties stored against a group.
*
@ -95,6 +121,15 @@ public interface GroupDAO {
void updateGroup(DeviceGroup deviceGroup, int groupId, int tenantId)
throws GroupManagementDAOException;
/**
* Update existing Device Groups.
*
* @param deviceGroups groups to update.
* @param tenantId of the group.
* @throws GroupManagementDAOException on error during updating of groups
*/
void updateGroups(List<DeviceGroup> deviceGroups, int tenantId) throws GroupManagementDAOException;
/**
* Delete an existing Device Group.
*
@ -104,6 +139,24 @@ public interface GroupDAO {
*/
void deleteGroup(int groupId, int tenantId) throws GroupManagementDAOException;
/**
* Delete mappings of Device Groups.
*
* @param groupIds of Device Groups.
* @param tenantId of the group.
* @throws GroupManagementDAOException on error during deletion of mappings of groups
*/
void deleteGroupsMapping(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException;
/**
* Delete existing Device Groups.
*
* @param groupIds of Device Groups.
* @param tenantId of the group.
* @throws GroupManagementDAOException on error during deletion of groups
*/
void deleteGroups(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException;
/**
* Get device group by id.
*
@ -114,6 +167,25 @@ public interface GroupDAO {
*/
DeviceGroup getGroup(int groupId, int tenantId) throws GroupManagementDAOException;
/**
* Get children groups by parent path.
*
* @param parentPath of parent group.
* @param tenantId of the group.
* @return {@link List<DeviceGroup>} list of children device groups
* @throws GroupManagementDAOException on error during retrieval of children groups
*/
List<DeviceGroup> getChildrenGroups(String parentPath, int tenantId) throws GroupManagementDAOException;
/**
* Get root groups.
*
* @param tenantId of the group.
* @return {@link List<DeviceGroup>} list of root device groups
* @throws GroupManagementDAOException on error during retrieval of root groups
*/
List<DeviceGroup> getRootGroups(int tenantId) throws GroupManagementDAOException;
/**
* Get the groups of device with device id provided
* @param deviceId
@ -306,10 +378,11 @@ public interface GroupDAO {
*
* @param roles of the group.
* @param tenantId of user's tenant.
* @param parentPath of the group.
* @return count of device groups.
* @throws GroupManagementDAOException
*/
int getGroupsCount(String[] roles, int tenantId) throws GroupManagementDAOException;
int getGroupsCount(String[] roles, int tenantId, String parentPath) throws GroupManagementDAOException;
/**
* Get all device groups which owned by user.
@ -336,10 +409,11 @@ public interface GroupDAO {
*
* @param username of the owner.
* @param tenantId of user's tenant.
* @param parentPath of the group.
* @return count of device groups.
* @throws GroupManagementDAOException
*/
int getOwnGroupsCount(String username, int tenantId) throws GroupManagementDAOException;
int getOwnGroupsCount(String username, int tenantId, String parentPath) throws GroupManagementDAOException;
/**
* Get device Ids of devices which are assigned to groups.

@ -48,13 +48,14 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
import org.wso2.carbon.device.mgt.common.geo.service.GeoQuery;
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;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCluster;
import org.wso2.carbon.device.mgt.common.geo.service.GeoCoordinate;
import java.sql.Connection;
import java.sql.PreparedStatement;
@ -64,6 +65,7 @@ import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -380,6 +382,9 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
PreparedStatement stmt = null;
ResultSet resultSet = null;
List<Device> devices = new ArrayList<>();
if (deviceProps.isEmpty()) {
return devices;
}
try {
List<List<String>> outputLists = new ArrayList<>();
List<String> deviceList = null;
@ -935,6 +940,9 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
throws DeviceManagementDAOException {
List<Device> devices = new ArrayList<>();
try {
if (deviceStatuses.isEmpty()) {
return devices;
}
Connection conn = this.getConnection();
StringJoiner joiner = new StringJoiner(",","SELECT "
+ "e1.OWNER, "
@ -1222,6 +1230,9 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
Connection conn;
PreparedStatement stmt = null;
try {
if (devices.isEmpty()) {
return false;
}
conn = this.getConnection();
StringBuilder sql = new StringBuilder("UPDATE DM_ENROLMENT SET STATUS = ? WHERE DEVICE_ID IN " +
"(SELECT d.ID FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE d.DEVICE_TYPE_ID = t.ID AND d.DEVICE_IDENTIFICATION IN (");
@ -1841,62 +1852,161 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
return tenants;
}
public List<GeoCluster> findGeoClusters(String deviceType, GeoCoordinate southWest, GeoCoordinate northEast,
int geohashLength, int tenantId) throws DeviceManagementDAOException {
public List<GeoCluster> findGeoClusters(GeoQuery geoQuery, int tenantId) throws DeviceManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
ResultSet rs = null;
List<GeoCluster> geoClusters = new ArrayList<>();
try {
conn = this.getConnection();
String sql = "SELECT AVG(DEVICE_LOCATION.LATITUDE) AS LATITUDE,AVG(DEVICE_LOCATION.LONGITUDE) AS LONGITUDE," +
" MIN(DEVICE_LOCATION.LATITUDE) AS MIN_LATITUDE, MAX(DEVICE_LOCATION.LATITUDE) AS MAX_LATITUDE," +
" MIN(DEVICE_LOCATION.LONGITUDE) AS MIN_LONGITUDE," +
" MAX(DEVICE_LOCATION.LONGITUDE) AS MAX_LONGITUDE," +
" SUBSTRING(DEVICE_LOCATION.GEO_HASH,1,?) AS GEOHASH_PREFIX, COUNT(*) AS COUNT," +
" MIN(DEVICE.DEVICE_IDENTIFICATION) AS DEVICE_IDENTIFICATION," +
" MIN(DEVICE.NAME) AS NAME," +
" MIN(DEVICE_TYPE.NAME) AS TYPE, " +
" MIN(DEVICE.LAST_UPDATED_TIMESTAMP) AS LAST_UPDATED_TIMESTAMP " +
"FROM DM_DEVICE_LOCATION AS DEVICE_LOCATION,DM_DEVICE AS DEVICE, DM_DEVICE_TYPE AS DEVICE_TYPE " +
"WHERE DEVICE_LOCATION.LATITUDE BETWEEN ? AND ? AND " +
"DEVICE_LOCATION.LONGITUDE BETWEEN ? AND ? AND " +
"DEVICE.TENANT_ID=? AND " +
"DEVICE.ID=DEVICE_LOCATION.DEVICE_ID AND DEVICE.DEVICE_TYPE_ID=DEVICE_TYPE.ID";
if (deviceType != null && !deviceType.isEmpty()) {
sql += " AND DEVICE_TYPE.NAME=?";
String sql = "SELECT AVG(DEVICE_LOCATION.LATITUDE) AS LATITUDE, " +
"AVG(DEVICE_LOCATION.LONGITUDE) AS LONGITUDE, " +
"MIN(DEVICE_LOCATION.LATITUDE) AS MIN_LATITUDE, " +
"MAX(DEVICE_LOCATION.LATITUDE) AS MAX_LATITUDE, " +
"MIN(DEVICE_LOCATION.LONGITUDE) AS MIN_LONGITUDE, " +
"MAX(DEVICE_LOCATION.LONGITUDE) AS MAX_LONGITUDE, " +
"SUBSTRING(DEVICE_LOCATION.GEO_HASH,1,?) AS GEOHASH_PREFIX, " +
"COUNT(DEVICE_LOCATION.ID) AS COUNT, " +
"MIN(DEVICE.ID) AS DEVICE_ID, " +
"MIN(DEVICE.NAME) AS DEVICE_NAME, " +
"MIN(DEVICE.DESCRIPTION) AS DESCRIPTION, " +
"MIN(DEVICE_TYPE.NAME) AS DEVICE_TYPE, " +
"MIN(DEVICE.DEVICE_IDENTIFICATION) AS DEVICE_IDENTIFICATION, " +
"MIN(ENROLMENT.ID) AS ENROLMENT_ID, " +
"MIN(ENROLMENT.OWNER) AS OWNER, " +
"MIN(ENROLMENT.OWNERSHIP) AS OWNERSHIP, " +
"MIN(ENROLMENT.IS_TRANSFERRED) AS IS_TRANSFERRED, " +
"MIN(ENROLMENT.DATE_OF_ENROLMENT) AS DATE_OF_ENROLMENT, " +
"MIN(ENROLMENT.DATE_OF_LAST_UPDATE) AS DATE_OF_LAST_UPDATE, " +
"MIN(ENROLMENT.STATUS) AS STATUS " +
"FROM DM_DEVICE_LOCATION AS DEVICE_LOCATION, DM_DEVICE AS DEVICE, " +
"DM_DEVICE_TYPE AS DEVICE_TYPE, DM_ENROLMENT AS ENROLMENT " +
"WHERE DEVICE_LOCATION.LATITUDE BETWEEN ? AND ? " +
"AND DEVICE_LOCATION.LONGITUDE BETWEEN ? AND ? ";
if (geoQuery.getDeviceTypes() != null && !geoQuery.getDeviceTypes().isEmpty()) {
sql += "AND DEVICE_TYPE.NAME IN (";
sql += String.join(", ",
Collections.nCopies(geoQuery.getDeviceTypes().size(), "?"));
sql += ") ";
}
if (geoQuery.getDeviceIdentifiers() != null && !geoQuery.getDeviceIdentifiers().isEmpty()) {
sql += "AND DEVICE.DEVICE_IDENTIFICATION IN (";
sql += String.join(", ",
Collections.nCopies(geoQuery.getDeviceIdentifiers().size(), "?"));
sql += ") ";
}
if (geoQuery.getOwners() != null && !geoQuery.getOwners().isEmpty()) {
sql += "AND ENROLMENT.OWNER IN (";
sql += String.join(", ",
Collections.nCopies(geoQuery.getOwners().size(), "?"));
sql += ") ";
}
if (geoQuery.getOwnerships() != null && !geoQuery.getOwnerships().isEmpty()) {
sql += "AND ENROLMENT.OWNERSHIP IN (";
sql += String.join(", ",
Collections.nCopies(geoQuery.getOwnerships().size(), "?"));
sql += ") ";
}
if (geoQuery.getStatuses() != null && !geoQuery.getStatuses().isEmpty()) {
sql += "AND ENROLMENT.STATUS IN (";
sql += String.join(", ",
Collections.nCopies(geoQuery.getStatuses().size(), "?"));
sql += ") ";
} else {
sql += "AND ENROLMENT.STATUS != 'REMOVED' ";
}
if (geoQuery.getCreatedBefore() != 0 || geoQuery.getCreatedAfter() != 0) {
sql += "AND ENROLMENT.DATE_OF_ENROLMENT BETWEEN ? AND ? ";
}
sql += " GROUP BY GEOHASH_PREFIX";
if (geoQuery.getUpdatedBefore() != 0 || geoQuery.getUpdatedAfter() != 0) {
sql += "AND ENROLMENT.DATE_OF_LAST_UPDATE BETWEEN ? AND ? ";
}
sql += "AND DEVICE.ID = DEVICE_LOCATION.DEVICE_ID AND DEVICE.DEVICE_TYPE_ID = DEVICE_TYPE.ID " +
"AND DEVICE.ID = ENROLMENT.DEVICE_ID " +
"AND DEVICE.TENANT_ID = ? AND DEVICE.TENANT_ID = ENROLMENT.TENANT_ID GROUP BY GEOHASH_PREFIX";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, geohashLength);
stmt.setDouble(2, southWest.getLatitude());
stmt.setDouble(3, northEast.getLatitude());
stmt.setDouble(4, southWest.getLongitude());
stmt.setDouble(5, northEast.getLongitude());
stmt.setDouble(6, tenantId);
if (deviceType != null && !deviceType.isEmpty()) {
stmt.setString(7, deviceType);
int index = 1;
stmt.setInt(index++, geoQuery.getGeohashLength());
stmt.setDouble(index++, geoQuery.getSouthWest().getLatitude());
stmt.setDouble(index++, geoQuery.getNorthEast().getLatitude());
stmt.setDouble(index++, geoQuery.getSouthWest().getLongitude());
stmt.setDouble(index++, geoQuery.getNorthEast().getLongitude());
if (geoQuery.getDeviceTypes() != null) {
for (String s: geoQuery.getDeviceTypes()) {
stmt.setString(index++, s);
}
}
if (geoQuery.getDeviceIdentifiers() != null) {
for (String s: geoQuery.getDeviceIdentifiers()) {
stmt.setString(index++, s);
}
}
if (geoQuery.getOwners() != null) {
for (String s: geoQuery.getOwners()) {
stmt.setString(index++, s);
}
}
if (geoQuery.getOwnerships() != null) {
for (String s: geoQuery.getOwnerships()) {
stmt.setString(index++, s);
}
}
if (geoQuery.getStatuses() != null) {
for (Status s: geoQuery.getStatuses()) {
stmt.setString(index++, s.toString());
}
}
if (geoQuery.getCreatedBefore() != 0 || geoQuery.getCreatedAfter() != 0) {
stmt.setTimestamp(index++, new Timestamp(geoQuery.getCreatedAfter()));
if (geoQuery.getCreatedBefore() == 0) {
stmt.setTimestamp(index++, new Timestamp(System.currentTimeMillis()));
} else {
stmt.setTimestamp(index++, new Timestamp(geoQuery.getCreatedBefore()));
}
}
if (geoQuery.getUpdatedBefore() != 0 || geoQuery.getUpdatedAfter() != 0) {
stmt.setTimestamp(index++, new Timestamp(geoQuery.getUpdatedAfter()));
if (geoQuery.getUpdatedBefore() == 0) {
stmt.setTimestamp(index++, new Timestamp(System.currentTimeMillis()));
} else {
stmt.setTimestamp(index++, new Timestamp(geoQuery.getUpdatedBefore()));
}
}
stmt.setInt(index, tenantId);
rs = stmt.executeQuery();
double latitude;
double longitude;
double minLatitude;
double maxLatitude;
double minLongitude;
double maxLongitude;
long count;
String geohashPrefix;
Device device;
while (rs.next()) {
double latitude = rs.getDouble("LATITUDE");
double longitude = rs.getDouble("LONGITUDE");
double min_latitude = rs.getDouble("MIN_LATITUDE");
double max_latitude = rs.getDouble("MAX_LATITUDE");
double min_longitude = rs.getDouble("MIN_LONGITUDE");
double max_longitude = rs.getDouble("MAX_LONGITUDE");
String device_identification = rs.getString("DEVICE_IDENTIFICATION");
String device_name = rs.getString("NAME");
String device_type = rs.getString("TYPE");
String last_seen = rs.getString("LAST_UPDATED_TIMESTAMP");
long count = rs.getLong("COUNT");
String geohashPrefix = rs.getString("GEOHASH_PREFIX");
latitude = rs.getDouble("LATITUDE");
longitude = rs.getDouble("LONGITUDE");
minLatitude = rs.getDouble("MIN_LATITUDE");
maxLatitude = rs.getDouble("MAX_LATITUDE");
minLongitude = rs.getDouble("MIN_LONGITUDE");
maxLongitude = rs.getDouble("MAX_LONGITUDE");
count = rs.getLong("COUNT");
geohashPrefix = rs.getString("GEOHASH_PREFIX");
if (count == 1) {
device = DeviceManagementDAOUtil.loadDevice(rs);
} else {
device = null;
}
geoClusters.add(new GeoCluster(new GeoCoordinate(latitude, longitude),
new GeoCoordinate(min_latitude, min_longitude), new GeoCoordinate(max_latitude, max_longitude),
count, geohashPrefix, device_identification, device_name, device_type, last_seen));
new GeoCoordinate(minLatitude, minLongitude), new GeoCoordinate(maxLatitude, maxLongitude),
count, geohashPrefix, device));
}
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving information of " +
throw new DeviceManagementDAOException("Error occurred while retrieving information of " +
"Geo Clusters", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, rs);
@ -1913,6 +2023,10 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
int counter = 0;
List<Device> devices = new ArrayList<>();
if (deviceIdentifiers.isEmpty()) {
return devices;
}
StringJoiner joiner = new StringJoiner(",",
"SELECT "
+ "d1.ID AS DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, "
@ -1961,6 +2075,10 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
int counter = 0;
List<Device> devices = new ArrayList<>();
if (deviceIdentifiers.isEmpty() || statuses.isEmpty()) {
return devices;
}
StringJoiner statusJoiner = new StringJoiner(",", "e.STATUS IN (", ") ");
while (counter < statuses.size()) {
statusJoiner.add("?");
@ -2904,4 +3022,154 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public List<Device> getGroupedDevicesDetails(PaginationRequest request, List<Integer> deviceIds, String groupName,
int tenantId) throws DeviceManagementDAOException {
int limitValue = request.getRowCount();
int offsetValue = request.getStartIndex();
List<String> status = request.getStatusList();
String name = request.getDeviceName();
String user = request.getOwner();
String ownership = request.getOwnership();
try {
List<Device> devices = new ArrayList<>();
if (deviceIds.isEmpty()) {
return devices;
}
Connection conn = this.getConnection();
int index = 1;
StringJoiner joiner = new StringJoiner(",",
"SELECT "
+ "DM_DEVICE.ID AS DEVICE_ID, "
+ "DM_DEVICE.NAME AS DEVICE_NAME, "
+ "DM_DEVICE.DESCRIPTION AS DESCRIPTION, "
+ "DM_DEVICE.DEVICE_TYPE_ID, "
+ "DM_DEVICE.DEVICE_IDENTIFICATION AS DEVICE_IDENTIFICATION, "
+ "e.ID AS ENROLMENT_ID, "
+ "e.OWNER, "
+ "e.OWNERSHIP, "
+ "e.DATE_OF_ENROLMENT, "
+ "e.DATE_OF_LAST_UPDATE, "
+ "e.STATUS, "
+ "e.IS_TRANSFERRED, "
+ "device_types.NAME AS DEVICE_TYPE "
+ "FROM DM_DEVICE_GROUP_MAP "
+ "INNER JOIN DM_DEVICE ON "
+ "DM_DEVICE_GROUP_MAP.DEVICE_ID = DM_DEVICE.ID "
+ "INNER JOIN DM_GROUP ON "
+ "DM_DEVICE_GROUP_MAP.GROUP_ID = DM_GROUP.ID "
+ "INNER JOIN DM_ENROLMENT e ON "
+ "DM_DEVICE.ID = e.DEVICE_ID AND "
+ "DM_DEVICE.TENANT_ID = e.TENANT_ID "
+ "INNER JOIN (SELECT ID, NAME FROM DM_DEVICE_TYPE) AS device_types ON "
+ "device_types.ID = DM_DEVICE.DEVICE_TYPE_ID "
+ "WHERE DM_DEVICE.ID IN (",
") AND DM_DEVICE.TENANT_ID = ?");
deviceIds.stream().map(ignored -> "?").forEach(joiner::add);
String query = joiner.toString();
if (StringUtils.isNotBlank(groupName)) {
query += " AND DM_GROUP.GROUP_NAME = ?";
}
if (StringUtils.isNotBlank(name)) {
query += " AND DM_DEVICE.NAME LIKE ?";
}
if (StringUtils.isNotBlank(user)) {
query += " AND e.OWNER = ?";
}
if (StringUtils.isNotBlank(ownership)) {
query += " AND e.OWNERSHIP = ?";
}
if (status != null && !status.isEmpty()) {
query += buildStatusQuery(status);
}
query += "LIMIT ? OFFSET ?";
try (PreparedStatement ps = conn.prepareStatement(query)) {
for (Integer deviceId : deviceIds) {
ps.setInt(index++, deviceId);
}
ps.setInt(index++, tenantId);
if (StringUtils.isNotBlank(groupName)) {
ps.setString(index++, groupName);
}
if (StringUtils.isNotBlank(name)) {
ps.setString(index++, name);
}
if (StringUtils.isNotBlank(user)) {
ps.setString(index++, user);
}
if (StringUtils.isNotBlank(ownership)) {
ps.setString(index++, ownership);
}
if (status != null && !status.isEmpty()) {
for (String deviceStatus : status) {
ps.setString(index++, deviceStatus);
}
}
ps.setInt(index++, limitValue);
ps.setInt(index, offsetValue);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
devices.add(DeviceManagementDAOUtil.loadDevice(rs));
}
return devices;
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving information of all registered devices " +
"according to device ids and the limit area.";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public int getGroupedDevicesCount(PaginationRequest request, List<Integer> deviceIds, String groupName,
int tenantId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
if (deviceIds.isEmpty()) {
return 0;
}
int index = 1;
StringJoiner joiner = new StringJoiner(",",
"SELECT "
+ "COUNT(DM_DEVICE_GROUP_MAP.DEVICE_ID) AS DEVICE_COUNT "
+ "FROM DM_DEVICE_GROUP_MAP "
+ "INNER JOIN DM_GROUP ON "
+ "DM_DEVICE_GROUP_MAP.GROUP_ID = DM_GROUP.ID "
+ "WHERE DM_DEVICE_GROUP_MAP.DEVICE_ID IN (",
") AND DM_GROUP.TENANT_ID = ?");
deviceIds.stream().map(ignored -> "?").forEach(joiner::add);
String query = joiner.toString();
if (StringUtils.isNotBlank(groupName)) {
query += " AND DM_GROUP.GROUP_NAME = ?";
}
try (PreparedStatement ps = conn.prepareStatement(query)) {
for (Integer deviceId : deviceIds) {
ps.setInt(index++, deviceId);
}
ps.setInt(index++, tenantId);
if (StringUtils.isNotBlank(groupName)) {
ps.setString(index, groupName);
}
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt("DEVICE_COUNT");
}
return 0;
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving information of all registered devices " +
"according to device ids and the limit area.";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
}

@ -68,6 +68,9 @@ public abstract class AbstractEventConfigDAO implements EventConfigDAO {
public List<EventConfig> getEventsOfGroups(List<Integer> groupIds, int tenantId) throws EventManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
if (groupIds.isEmpty()) {
return eventList;
}
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
@ -145,6 +148,9 @@ public abstract class AbstractEventConfigDAO implements EventConfigDAO {
@Override
public void deleteEventGroupMappingRecordsByEventIds(List<Integer> eventsIdsToDelete) throws EventManagementDAOException {
try {
if (eventsIdsToDelete.isEmpty()) {
return;
}
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_DEVICE_EVENT_GROUP_MAPPING WHERE EVENT_ID IN (%s)";
String inClause = String.join(", ", Collections.nCopies(eventsIdsToDelete.size(), "?"));
@ -166,6 +172,9 @@ public abstract class AbstractEventConfigDAO implements EventConfigDAO {
@Override
public void deleteEventGroupMappingRecordsByGroupIds(List<Integer> groupIdsToDelete) throws EventManagementDAOException {
try {
if (groupIdsToDelete.isEmpty()) {
return;
}
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_DEVICE_EVENT_GROUP_MAPPING WHERE GROUP_ID IN (%s)";
String inClause = String.join(", ", Collections.nCopies(groupIdsToDelete.size(), "?"));
@ -230,6 +239,9 @@ public abstract class AbstractEventConfigDAO implements EventConfigDAO {
public List<EventConfig> getEventsById(List<Integer> eventIdList) throws EventManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
if (eventIdList.isEmpty()) {
return eventList;
}
Connection conn = this.getConnection();
String sql = "SELECT " +
"ID AS EVENT_ID, " +
@ -269,6 +281,9 @@ public abstract class AbstractEventConfigDAO implements EventConfigDAO {
public List<Integer> getGroupsOfEvents(List<Integer> eventIdList) throws EventManagementDAOException {
try {
List<Integer> groupIdList = new ArrayList<>();
if (eventIdList.isEmpty()) {
return groupIdList;
}
Connection conn = this.getConnection();
String sql = "SELECT " +
"GROUP_ID " +

@ -14,18 +14,34 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*
* Copyright (c) 2021, 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.core.dao.impl;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.solr.common.StringUtils;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.GroupPaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.GroupDAO;
import org.wso2.carbon.device.mgt.core.dao.GroupManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.GroupManagementDAOFactory;
@ -49,6 +65,127 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
private static final Log log = LogFactory.getLog(AbstractGroupDAOImpl.class);
@Override
public List<DeviceGroup> getGroups(GroupPaginationRequest request, int tenantId)
throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE TENANT_ID = ?";
if (StringUtils.isNotBlank(request.getGroupName())) {
sql += " AND GROUP_NAME LIKE ?";
}
if (StringUtils.isNotBlank(request.getOwner())) {
sql += " AND OWNER LIKE ?";
}
if (StringUtils.isNotBlank(request.getStatus())) {
sql += " AND STATUS = ?";
}
if (StringUtils.isNotBlank(request.getParentPath())) {
sql += " AND PARENT_PATH LIKE ?";
}
if (request.getRowCount() != 0) {
sql += " LIMIT ? OFFSET ?";
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIndex = 1;
stmt.setInt(paramIndex++, tenantId);
if (StringUtils.isNotBlank(request.getGroupName())) {
stmt.setString(paramIndex++, request.getGroupName() + "%");
}
if (StringUtils.isNotBlank(request.getOwner())) {
stmt.setString(paramIndex++, request.getOwner() + "%");
}
if (StringUtils.isNotBlank(request.getStatus())) {
stmt.setString(paramIndex++, request.getStatus().toUpperCase());
}
if (StringUtils.isNotBlank(request.getParentPath())) {
stmt.setString(paramIndex++, request.getParentPath());
}
if (request.getRowCount() != 0) {
stmt.setInt(paramIndex++, request.getRowCount());
stmt.setInt(paramIndex, request.getStartIndex());
}
List<DeviceGroup> deviceGroupList = new ArrayList<>();
try (ResultSet resultSet = stmt.executeQuery()) {
while (resultSet.next()) {
deviceGroupList.add(GroupManagementDAOUtil.loadGroup(resultSet));
}
}
return deviceGroupList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving groups in tenant: " + tenantId;
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public List<DeviceGroup> getGroups(GroupPaginationRequest request, List<Integer> deviceGroupIds,
int tenantId) throws GroupManagementDAOException {
int deviceGroupIdsCount = deviceGroupIds.size();
if (deviceGroupIdsCount == 0) {
return new ArrayList<>();
}
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP WHERE TENANT_ID = ?";
if (StringUtils.isNotBlank(request.getGroupName())) {
sql += " AND GROUP_NAME LIKE ?";
}
if (StringUtils.isNotBlank(request.getOwner())) {
sql += " AND OWNER LIKE ?";
}
if (StringUtils.isNotBlank(request.getParentPath())) {
sql += " AND PARENT_PATH LIKE ?";
}
sql += " AND ID IN (";
for (int i = 0; i < deviceGroupIdsCount; i++) {
sql += (deviceGroupIdsCount - 1 != i) ? "?," : "?";
}
sql += ")";
if (request.getRowCount() != 0) {
sql += " LIMIT ? OFFSET ?";
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIndex = 1;
stmt.setInt(paramIndex++, tenantId);
if (StringUtils.isNotBlank(request.getGroupName())) {
stmt.setString(paramIndex++, request.getGroupName() + "%");
}
if (StringUtils.isNotBlank(request.getOwner())) {
stmt.setString(paramIndex++, request.getOwner() + "%");
}
if (StringUtils.isNotBlank(request.getParentPath())) {
stmt.setString(paramIndex++, request.getParentPath());
}
for (Integer deviceGroupId : deviceGroupIds) {
stmt.setInt(paramIndex++, deviceGroupId);
}
if (request.getRowCount() != 0) {
stmt.setInt(paramIndex++, request.getRowCount());
stmt.setInt(paramIndex, request.getStartIndex());
}
List<DeviceGroup> deviceGroupList = new ArrayList<>();
try (ResultSet resultSet = stmt.executeQuery()) {
while (resultSet.next()) {
deviceGroupList.add(GroupManagementDAOUtil.loadGroup(resultSet));
}
}
return deviceGroupList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving groups of groups IDs " + deviceGroupIds.toString()
+ " in tenant: " + tenantId;
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public int addGroup(DeviceGroup deviceGroup, int tenantId) throws GroupManagementDAOException {
PreparedStatement stmt = null;
@ -59,9 +196,11 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql;
if (deviceGroup.getStatus() == null || deviceGroup.getStatus().isEmpty()) {
sql = "INSERT INTO DM_GROUP(DESCRIPTION, GROUP_NAME, OWNER, TENANT_ID) VALUES (?, ?, ?, ?)";
sql = "INSERT INTO DM_GROUP(DESCRIPTION, GROUP_NAME, OWNER, TENANT_ID, PARENT_PATH) "
+ "VALUES (?, ?, ?, ?, ?)";
} else {
sql = "INSERT INTO DM_GROUP(DESCRIPTION, GROUP_NAME, OWNER, TENANT_ID, STATUS) VALUES (?, ?, ?, ?, ?)";
sql = "INSERT INTO DM_GROUP(DESCRIPTION, GROUP_NAME, OWNER, TENANT_ID, PARENT_PATH, STATUS) "
+ "VALUES (?, ?, ?, ?, ?, ?)";
hasStatus = true;
}
stmt = conn.prepareStatement(sql, new String[]{"ID"});
@ -69,8 +208,9 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
stmt.setString(2, deviceGroup.getName());
stmt.setString(3, deviceGroup.getOwner());
stmt.setInt(4, tenantId);
stmt.setString(5, deviceGroup.getParentPath());
if (hasStatus) {
stmt.setString(5, deviceGroup.getStatus());
stmt.setString(6, deviceGroup.getStatus());
}
stmt.executeUpdate();
@ -151,10 +291,12 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql =
"UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ? WHERE ID = ? AND TENANT_ID = ?";
"UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ?, PARENT_PATH = ? WHERE ID = ? "
+ "AND TENANT_ID = ?";
if (deviceGroup.getStatus() != null && !deviceGroup.getStatus().isEmpty()) {
sql = "UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ?, STATUS = ? WHERE ID = ? AND TENANT_ID = ?";
sql = "UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ?, PARENT_PATH = ?, STATUS = ? "
+ "WHERE ID = ? AND TENANT_ID = ?";
hasStatus = true;
}
stmt = conn.prepareStatement(sql);
@ -162,11 +304,12 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
stmt.setString(paramIndex++, deviceGroup.getDescription());
stmt.setString(paramIndex++, deviceGroup.getName());
stmt.setString(paramIndex++, deviceGroup.getOwner());
stmt.setString(paramIndex++, deviceGroup.getParentPath());
if (hasStatus) {
stmt.setString(paramIndex++, deviceGroup.getStatus());
}
stmt.setInt(paramIndex++, groupId);
stmt.setInt(paramIndex++, tenantId);
stmt.setInt(paramIndex, tenantId);
stmt.executeUpdate();
} catch (SQLException e) {
throw new GroupManagementDAOException("Error occurred while updating deviceGroup '" +
@ -176,6 +319,32 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
}
@Override
public void updateGroups(List<DeviceGroup> deviceGroups, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ?, STATUS = ?, "
+ "PARENT_PATH = ? WHERE ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)){
for (DeviceGroup deviceGroup : deviceGroups) {
stmt.setString(1, deviceGroup.getDescription());
stmt.setString(2, deviceGroup.getName());
stmt.setString(3, deviceGroup.getOwner());
stmt.setString(4, deviceGroup.getStatus());
stmt.setString(5, deviceGroup.getParentPath());
stmt.setInt(6, deviceGroup.getGroupId());
stmt.setInt(7, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while updating groups as batch";
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public void deleteGroup(int groupId, int tenantId) throws GroupManagementDAOException {
Connection conn;
@ -217,6 +386,64 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
}
@Override
public void deleteGroupsMapping(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "DELETE FROM DM_ROLE_GROUP_MAP WHERE GROUP_ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int groupId : groupIds) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
}
sql = "DELETE FROM DM_DEVICE_GROUP_MAP WHERE GROUP_ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int groupId : groupIds) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
}
sql = "DELETE FROM DM_DEVICE_GROUP_POLICY WHERE DEVICE_GROUP_ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int groupId : groupIds) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while removing mappings of groups as batches";
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public void deleteGroups(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "DELETE FROM DM_GROUP WHERE ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int groupId : groupIds) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting groups as batches";
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
public void deleteAllGroupProperties(int groupId, int tenantId)
throws GroupManagementDAOException {
PreparedStatement stmt = null;
@ -235,6 +462,25 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
}
public void deleteAllGroupsProperties(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "DELETE FROM GROUP_PROPERTIES WHERE GROUP_ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer groupId : groupIds) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
stmt.addBatch();
}
stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting properties of groups as batches";
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
public Map<String, String> getAllGroupProperties(int groupId, int tenantId)
throws GroupManagementDAOException {
PreparedStatement stmt = null;
@ -266,7 +512,8 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
ResultSet resultSet = null;
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS FROM DM_GROUP WHERE ID = ? AND TENANT_ID = ?";
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP WHERE ID = ? "
+ "AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
@ -284,6 +531,56 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
}
@Override
public List<DeviceGroup> getChildrenGroups(String parentPath, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE PARENT_PATH LIKE ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, parentPath + "%");
stmt.setInt(2, tenantId);
List<DeviceGroup> deviceGroupList = new ArrayList<>();
try (ResultSet resultSet = stmt.executeQuery()) {
while (resultSet.next()) {
deviceGroupList.add(GroupManagementDAOUtil.loadGroup(resultSet));
}
}
return deviceGroupList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving children group having parent path '" + parentPath
+ "' in tenant: " + tenantId;
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public List<DeviceGroup> getRootGroups(int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE PARENT_PATH LIKE ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "/");
stmt.setInt(2, tenantId);
List<DeviceGroup> deviceGroupList = new ArrayList<>();
try (ResultSet resultSet = stmt.executeQuery()) {
deviceGroupList = new ArrayList<>();
while (resultSet.next()) {
deviceGroupList.add(GroupManagementDAOUtil.loadGroup(resultSet));
}
}
return deviceGroupList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving root groups in tenant: " + tenantId;
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public List<DeviceGroup> getGroups(int deviceId, int tenantId) throws GroupManagementDAOException {
PreparedStatement stmt = null;
@ -291,7 +588,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
List<DeviceGroup> deviceGroupBuilders = new ArrayList<>();
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT G.ID, G.GROUP_NAME, G.DESCRIPTION, G.OWNER, G.STATUS FROM DM_GROUP G " +
String sql = "SELECT G.ID, G.GROUP_NAME, G.DESCRIPTION, G.OWNER, G.STATUS, G.PARENT_PATH FROM DM_GROUP G " +
"INNER JOIN DM_DEVICE_GROUP_MAP GM ON G.ID = GM.GROUP_ID " +
"WHERE GM.DEVICE_ID = ? AND GM.TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
@ -316,7 +613,8 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
List<DeviceGroup> deviceGroupList = null;
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS FROM DM_GROUP WHERE TENANT_ID = ?";
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, tenantId);
resultSet = stmt.executeQuery();
@ -389,6 +687,9 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
sql += " AND STATUS = ?";
hasStatus = true;
}
if (StringUtils.isNotBlank(request.getParentPath())) {
sql += " AND PARENT_PATH = ?";
}
int paramIndex = 1;
stmt = conn.prepareStatement(sql);
@ -397,10 +698,13 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
stmt.setString(paramIndex++, groupName + "%");
}
if (hasOwner) {
stmt.setString(paramIndex, owner + "%");
stmt.setString(paramIndex++, owner + "%");
}
if (hasStatus) {
stmt.setString(paramIndex, request.getStatus());
stmt.setString(paramIndex++, request.getStatus());
}
if (StringUtils.isNotBlank(request.getParentPath())) {
stmt.setString(paramIndex, request.getParentPath());
}
resultSet = stmt.executeQuery();
if (resultSet.next()) {
@ -422,7 +726,8 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql =
"SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS FROM DM_GROUP WHERE GROUP_NAME = ? AND TENANT_ID = ?";
"SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE GROUP_NAME = ? AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, groupName);
stmt.setInt(2, tenantId);
@ -592,7 +897,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
List<DeviceGroup> deviceGroupList = null;
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS FROM DM_GROUP g, " +
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP g, " +
"(SELECT GROUP_ID FROM DM_ROLE_GROUP_MAP WHERE ROLE IN (";
int index = 0;
@ -658,7 +963,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
@Override
public int getGroupsCount(String[] roles, int tenantId) throws GroupManagementDAOException {
public int getGroupsCount(String[] roles, int tenantId, String parentPath) throws GroupManagementDAOException {
int rolesCount = roles.length;
if (rolesCount == 0) {
return 0;
@ -672,14 +977,20 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
for (int i = 0; i < rolesCount; i++) {
sql += (rolesCount - 1 != i) ? "?," : "?";
}
sql += ")) gr WHERE g.ID = gr.GROUP_ID AND TENANT_ID = ? GROUP BY g.ID";
sql += ")) gr WHERE g.ID = gr.GROUP_ID AND TENANT_ID = ? ";
if (StringUtils.isNotBlank(parentPath)) {
sql += " AND g.PARENT_PATH = ? ";
}
sql += "GROUP BY g.ID";
stmt = conn.prepareStatement(sql);
int index = 0;
while (index++ < rolesCount) {
stmt.setString(index, roles[index - 1]);
}
stmt.setInt(index, tenantId);
stmt.setInt(index++, tenantId);
if (StringUtils.isNotBlank(parentPath)) {
stmt.setString(index, parentPath);
}
resultSet = stmt.executeQuery();
if (resultSet.next()) {
return resultSet.getInt("GROUP_COUNT");
@ -700,7 +1011,8 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
List<DeviceGroup> deviceGroupList = null;
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS FROM DM_GROUP WHERE OWNER = ? AND TENANT_ID = ?";
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH FROM DM_GROUP "
+ "WHERE OWNER = ? AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setInt(2, tenantId);
@ -744,15 +1056,21 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
@Override
public int getOwnGroupsCount(String username, int tenantId) throws GroupManagementDAOException {
public int getOwnGroupsCount(String username, int tenantId, String parentPath) throws GroupManagementDAOException {
PreparedStatement stmt = null;
ResultSet resultSet = null;
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT COUNT(ID) AS GROUP_COUNT FROM DM_GROUP WHERE OWNER = ? AND TENANT_ID = ?";
if (StringUtils.isNotBlank(parentPath)) {
sql += " AND PARENT_PATH = ?";
}
stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setInt(2, tenantId);
if (StringUtils.isNotBlank(parentPath)) {
stmt.setString(3, parentPath);
}
resultSet = stmt.executeQuery();
if (resultSet.next()) {
return resultSet.getInt("GROUP_COUNT");
@ -772,6 +1090,9 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
throws GroupManagementDAOException {
List<Device> devices = new ArrayList<>();
try {
if (deviceStatuses.isEmpty()) {
return devices;
}
Connection conn = GroupManagementDAOFactory.getConnection();
StringJoiner joiner = new StringJoiner(",","SELECT "
+ "d1.DEVICE_ID, "
@ -794,7 +1115,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
+ "FROM DM_DEVICE d, "
+ "(SELECT dgm.DEVICE_ID "
+ "FROM DM_DEVICE_GROUP_MAP dgm "
+ "WHERE dgm.GROUP_ID = (SELECT ID FROM DM_GROUP WHERE GROUP_NAME = ? )) dgm1 "
+ "WHERE dgm.GROUP_ID = (SELECT ID FROM DM_GROUP WHERE GROUP_NAME = ? AND TENANT_ID = ?)) dgm1 "
+ "WHERE d.ID = dgm1.DEVICE_ID AND d.TENANT_ID = ?) gd, DM_DEVICE_TYPE t "
+ "WHERE gd.DEVICE_TYPE_ID = t.ID) d1 "
+ "WHERE d1.DEVICE_ID = e.DEVICE_ID AND TENANT_ID = ? AND e.STATUS IN (",
@ -808,6 +1129,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
stmt.setString(index++, groupName);
stmt.setInt(index++, tenantId);
stmt.setInt(index++, tenantId);
stmt.setInt(index++, tenantId);
for (String deviceId : deviceStatuses) {
stmt.setObject(index++, deviceId);
}

@ -421,6 +421,9 @@ public class GeofenceDAOImpl implements GeofenceDAO {
public Map<Integer, List<EventConfig>> getEventsOfGeoFences(List<Integer> geofenceIds) throws DeviceManagementDAOException {
try {
Map<Integer, List<EventConfig>> geoFenceEventMap = new HashMap<>();
if (geofenceIds.isEmpty()) {
return geoFenceEventMap;
}
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
@ -490,6 +493,9 @@ public class GeofenceDAOImpl implements GeofenceDAO {
public Set<GeoFenceGroupMap> getGroupIdsOfGeoFences(List<Integer> fenceIds) throws DeviceManagementDAOException {
try {
Set<GeoFenceGroupMap> geoFenceGroupSet = new HashSet<>();
if (fenceIds.isEmpty()) {
return geoFenceGroupSet;
}
Connection conn = this.getConnection();
String sql = "SELECT " +
"FENCE_ID, " +

@ -67,6 +67,9 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
boolean isStatusProvided = false;
Date since = request.getSince();
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
try {
Connection conn = getConnection();
@ -87,10 +90,19 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
"d.DESCRIPTION, " +
"d.NAME, " +
"d.DEVICE_IDENTIFICATION, " +
"t.NAME AS DEVICE_TYPE " +
"FROM DM_DEVICE d, DM_DEVICE_TYPE t ";
sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
"t.NAME AS DEVICE_TYPE ";
if (serial != null) {
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_INFO i " +
"WHERE DEVICE_TYPE_ID = t.ID " +
"AND d.ID= i.DEVICE_ID " +
"AND i.KEY_FIELD = 'serial' " +
"AND i.VALUE_FIELD = ? " +
"AND d.TENANT_ID = ? ";
isSerialProvided = true;
} else {
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
}
//Add query for last updated timestamp
if (since != null) {
sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
@ -128,6 +140,9 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIdx = 1;
if (isSerialProvided) {
stmt.setString(paramIdx++, serial);
}
stmt.setInt(paramIdx++, tenantId);
if (isSinceProvided) {
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
@ -877,16 +892,28 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
}
@Override
public List<Device> getSubscribedDevices(int offsetValue, int limitValue,
List<Integer> deviceIds, int tenantId, List<String> status)
public List<Device> getSubscribedDevices(PaginationRequest request, List<Integer> deviceIds, int tenantId)
throws DeviceManagementDAOException {
Connection conn;
int limitValue = request.getRowCount();
int offsetValue = request.getStartIndex();
List<String> status = request.getStatusList();
String name = request.getDeviceName();
String user = request.getOwner();
String ownership = request.getOwnership();
try {
List<Device> devices = new ArrayList<>();
if (deviceIds.isEmpty()) {
return devices;
}
conn = this.getConnection();
int index = 1;
boolean isStatusProvided = false;
boolean isDeviceNameProvided = false;
boolean isOwnerProvided = false;
boolean isOwnershipProvided = false;
StringJoiner joiner = new StringJoiner(",",
"SELECT "
+ "DM_DEVICE.ID AS DEVICE_ID, "
@ -914,6 +941,18 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
deviceIds.stream().map(ignored -> "?").forEach(joiner::add);
String query = joiner.toString();
if (name != null && !name.isEmpty()) {
query += " AND DM_DEVICE.NAME LIKE ?";
isDeviceNameProvided = true;
}
if (ownership != null && !ownership.isEmpty()) {
query += " AND e.OWNERSHIP = ?";
isOwnershipProvided = true;
}
if (user != null && !user.isEmpty()) {
query += " AND e.OWNER = ?";
isOwnerProvided = true;
}
if (status != null && !status.isEmpty()) {
query += buildStatusQuery(status);
isStatusProvided = true;
@ -926,8 +965,16 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
for (Integer deviceId : deviceIds) {
ps.setObject(index++, deviceId);
}
ps.setInt(index++, tenantId);
if (isDeviceNameProvided) {
ps.setString(index++, name + "%");
}
if (isOwnershipProvided) {
ps.setString(index++, ownership);
}
if (isOwnerProvided) {
ps.setString(index++, user);
}
if (isStatusProvided) {
for (String deviceStatus : status) {
ps.setString(index++, deviceStatus);
@ -937,7 +984,6 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
ps.setInt(index, limitValue);
try (ResultSet rs = ps.executeQuery()) {
List<Device> devices = new ArrayList<>();
while (rs.next()) {
devices.add(DeviceManagementDAOUtil.loadDevice(rs));
}
@ -956,6 +1002,9 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
public int getSubscribedDeviceCount(List<Integer> deviceIds, int tenantId, List<String> status)
throws DeviceManagementDAOException {
try {
if (deviceIds.isEmpty()) {
return 0;
}
Connection conn = this.getConnection();
int index = 1;
StringJoiner joiner = new StringJoiner(",",

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save