merging with upstream

revert-70ac1926
Ace 4 years ago
commit bac6e3ba67

@ -17,5 +17,5 @@
package org.wso2.carbon.device.application.mgt.common; package org.wso2.carbon.device.application.mgt.common;
public enum DeviceTypes { public enum DeviceTypes {
ANDROID, IOS ANDROID, IOS, WINDOWS
} }

@ -31,6 +31,10 @@ public class Application {
required = true) required = true)
private String name; private String name;
@ApiModelProperty(name = "installerName",
value = "Application Installer Name")
private String installerName;
@ApiModelProperty(name = "description", @ApiModelProperty(name = "description",
value = "Description of the application", value = "Description of the application",
required = true) required = true)
@ -173,4 +177,8 @@ public class Application {
public boolean isAndroidEnterpriseApp() { return isAndroidEnterpriseApp; } public boolean isAndroidEnterpriseApp() { return isAndroidEnterpriseApp; }
public void setAndroidEnterpriseApp(boolean androidEnterpriseApp) { isAndroidEnterpriseApp = androidEnterpriseApp; } public void setAndroidEnterpriseApp(boolean androidEnterpriseApp) { isAndroidEnterpriseApp = androidEnterpriseApp; }
public String getInstallerName() { return installerName; }
public void setInstallerName(String installerName) { this.installerName = installerName; }
} }

@ -87,6 +87,10 @@ public class ApplicationRelease {
value = "Application Rating") value = "Application Rating")
private double rating; private double rating;
@ApiModelProperty(name = "packageName",
value = "package name of the application")
private String packageName;
public String getReleaseType() { public String getReleaseType() {
return releaseType; return releaseType;
} }
@ -162,4 +166,8 @@ public class ApplicationRelease {
public List<String> getScreenshots() { return screenshots; } public List<String> getScreenshots() { return screenshots; }
public void setScreenshots(List<String> screenshots) { this.screenshots = screenshots; } public void setScreenshots(List<String> screenshots) { this.screenshots = screenshots; }
public String getPackageName() { return packageName; }
public void setPackageName(String packageName) { this.packageName = packageName; }
} }

@ -281,6 +281,16 @@ public interface ApplicationManager {
String getInstallableLifecycleState() throws ApplicationManagementException; String getInstallableLifecycleState() throws ApplicationManagementException;
/**
* Check if there are subscription devices for operations
*
* @param operationId Id of the operation
* @param deviceId deviceId of the relevant device
* @return boolean value either true or false according to the situation
* @throws ApplicationManagementException
*/
boolean checkSubDeviceIdsForOperations(int operationId, int deviceId) throws ApplicationManagementException;
void updateSubsStatus (int deviceId, int operationId, String status) throws ApplicationManagementException; void updateSubsStatus (int deviceId, int operationId, String status) throws ApplicationManagementException;

@ -60,6 +60,14 @@ public class EntAppReleaseWrapper {
@NotNull @NotNull
private String supportedOsVersions; private String supportedOsVersions;
@ApiModelProperty(name = "version",
value = "Version number of the applications installer specifically for windows")
private String version;
@ApiModelProperty(name = "packageName",
value = "PackageName of the application installer specifically for windows")
private String packageName;
public String getReleaseType() { public String getReleaseType() {
return releaseType; return releaseType;
} }
@ -99,4 +107,20 @@ public class EntAppReleaseWrapper {
public String getSupportedOsVersions() { return supportedOsVersions; } public String getSupportedOsVersions() { return supportedOsVersions; }
public void setSupportedOsVersions(String supportedOsVersions) { this.supportedOsVersions = supportedOsVersions; } public void setSupportedOsVersions(String supportedOsVersions) { this.supportedOsVersions = supportedOsVersions; }
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
} }

@ -173,14 +173,14 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
if (deviceTypeId != -1) { if (deviceTypeId != -1) {
sql += "AND AP_APP.DEVICE_TYPE_ID = ? "; sql += "AND AP_APP.DEVICE_TYPE_ID = ? ";
} }
sql += "GROUP BY AP_APP.ID "; sql += "GROUP BY AP_APP.ID ORDER BY AP_APP.ID ";
if (StringUtils.isNotEmpty(filter.getSortBy())) { if (StringUtils.isNotEmpty(filter.getSortBy())) {
sql += "ORDER BY ID " + filter.getSortBy() +" "; sql += filter.getSortBy() +" ";
} }
if (filter.getLimit() != -1) { if (filter.getLimit() != -1) {
sql += "LIMIT ? OFFSET ? "; sql += "LIMIT ? OFFSET ? ";
} }
sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ?"; sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
try { try {
Connection conn = this.getDBConnection(); Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {

@ -118,15 +118,14 @@ public class OracleApplicationDAOImpl extends GenericApplicationDAOImpl {
if (deviceTypeId != -1) { if (deviceTypeId != -1) {
sql += "AND AP_APP.DEVICE_TYPE_ID = ? "; sql += "AND AP_APP.DEVICE_TYPE_ID = ? ";
} }
sql += "GROUP BY AP_APP.ID "; sql += "GROUP BY AP_APP.ID ORDER BY AP_APP.ID ";
if (StringUtils.isNotEmpty(filter.getSortBy())) { if (StringUtils.isNotEmpty(filter.getSortBy())) {
sql += "ORDER BY ID " + filter.getSortBy() + " "; sql += filter.getSortBy() +" ";
} }
if (filter.getLimit() != -1) { if (filter.getLimit() != -1) {
sql += "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY "; sql += "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";
} }
sql += ") AS app_data ON app_data.ID = AP_APP.ID " + sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
"WHERE AP_APP.TENANT_ID = ?";
try { try {
Connection conn = this.getDBConnection(); Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {

@ -117,15 +117,14 @@ public class SQLServerApplicationDAOImpl extends GenericApplicationDAOImpl {
if (deviceTypeId != -1) { if (deviceTypeId != -1) {
sql += "AND AP_APP.DEVICE_TYPE_ID = ? "; sql += "AND AP_APP.DEVICE_TYPE_ID = ? ";
} }
sql += "GROUP BY AP_APP.ID "; sql += "GROUP BY AP_APP.ID ORDER BY AP_APP.ID ";
if (StringUtils.isNotEmpty(filter.getSortBy())) { if (StringUtils.isNotEmpty(filter.getSortBy())) {
sql += "ORDER BY ID " + filter.getSortBy() + " "; sql += filter.getSortBy() +" ";
} }
if (filter.getLimit() != -1) { if (filter.getLimit() != -1) {
sql += "ORDER BY ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY "; sql += "ORDER BY ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";
} }
sql += ") AS app_data ON app_data.ID = AP_APP.ID " + sql += ") AS app_data ON app_data.ID = AP_APP.ID WHERE AP_APP.TENANT_ID = ? ORDER BY AP_APP.ID";
"WHERE AP_APP.TENANT_ID = ?";
try { try {
Connection conn = this.getDBConnection(); Connection conn = this.getDBConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) { try (PreparedStatement stmt = conn.prepareStatement(sql)) {

@ -141,6 +141,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(applicationWrapper); ApplicationDTO applicationDTO = APIUtil.convertToAppDTO(applicationWrapper);
//uploading application artifacts //uploading application artifacts
ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts( ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts(
applicationDTO.getApplicationReleaseDTOs().get(0), applicationArtifact, applicationDTO.getApplicationReleaseDTOs().get(0), applicationArtifact,
@ -338,24 +339,36 @@ public class ApplicationManagerImpl implements ApplicationManager {
byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream()); byte[] content = IOUtils.toByteArray(applicationArtifact.getInstallerStream());
applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName()); applicationReleaseDTO.setInstallerName(applicationArtifact.getInstallerName());
try (ByteArrayInputStream binary = new ByteArrayInputStream(content)) { try (ByteArrayInputStream binary = new ByteArrayInputStream(content)) {
ApplicationInstaller applicationInstaller = applicationStorageManager if (!DeviceTypes.WINDOWS.toString().equalsIgnoreCase(deviceType)) {
.getAppInstallerData(binary, deviceType); ApplicationInstaller applicationInstaller = applicationStorageManager
String packagename = applicationInstaller.getPackageName(); .getAppInstallerData(binary, deviceType);
applicationReleaseDTO.setVersion(applicationInstaller.getVersion());
applicationReleaseDTO.setPackageName(applicationInstaller.getPackageName());
} else {
String windowsInstallerName = applicationArtifact.getInstallerName();
String extension = windowsInstallerName.substring(windowsInstallerName.lastIndexOf(".") + 1);
if (!extension.equalsIgnoreCase(Constants.MSI) &&
!extension.equalsIgnoreCase(Constants.APPX)) {
String msg = "Application Type doesn't match with supporting application types of " +
deviceType + "platform which are APPX and MSI";
log.error(msg);
throw new BadRequestException(msg);
}
}
String packageName = applicationReleaseDTO.getPackageName();
try { try {
ConnectionManagerUtil.openDBConnection(); ConnectionManagerUtil.openDBConnection();
if (!isNewRelease && applicationReleaseDAO if (!isNewRelease && applicationReleaseDAO
.isActiveReleaseExisitForPackageName(packagename, tenantId, .isActiveReleaseExisitForPackageName(packageName, tenantId,
lifecycleStateManager.getEndState())) { lifecycleStateManager.getEndState())) {
String msg = "Application release is already exist for the package name: " + packagename String msg = "Application release is already exist for the package name: " + packageName
+ ". Either you can delete all application releases for package " + packagename + " or " + ". Either you can delete all application releases for package " + packageName + " or "
+ "you can add this app release as an new application release, under the existing " + "you can add this app release as an new application release, under the existing "
+ "application."; + "application.";
log.error(msg); log.error(msg);
throw new ApplicationManagementException(msg); throw new ApplicationManagementException(msg);
} }
applicationReleaseDTO.setVersion(applicationInstaller.getVersion());
applicationReleaseDTO.setPackageName(packagename);
String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content)); String md5OfApp = StorageManagementUtil.getMD5(new ByteArrayInputStream(content));
if (md5OfApp == null) { if (md5OfApp == null) {
String msg = "Error occurred while md5sum value retrieving process: application UUID " String msg = "Error occurred while md5sum value retrieving process: application UUID "
@ -1012,6 +1025,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts( ApplicationReleaseDTO applicationReleaseDTO = uploadEntAppReleaseArtifacts(
APIUtil.releaseWrapperToReleaseDTO(entAppReleaseWrapper), applicationArtifact, deviceType.getName(), APIUtil.releaseWrapperToReleaseDTO(entAppReleaseWrapper), applicationArtifact, deviceType.getName(),
tenantId, true); tenantId, true);
@ -1909,13 +1923,13 @@ public class ApplicationManagerImpl implements ApplicationManager {
int deviceTypeId; int deviceTypeId;
if (!deviceTypeName.equals(Constants.ALL)) { if (!deviceTypeName.equals(Constants.ALL)) {
DeviceType deviceType = deviceManagementProviderService.getDeviceType(deviceTypeName); DeviceType deviceType = deviceManagementProviderService.getDeviceType(deviceTypeName);
deviceTypeId = deviceType.getId();
if (deviceType == null) { if (deviceType == null) {
String msg = "Device type doesn't exist. Hence check the application name existence with valid " String msg = "Device type doesn't exist. Hence check the application name existence with valid "
+ "device type name."; + "device type name.";
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
deviceTypeId = deviceType.getId();
} else { } else {
//For web-clips device type = 'ALL' //For web-clips device type = 'ALL'
deviceTypeId = 0; deviceTypeId = 0;
@ -2662,6 +2676,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
try { try {
ConnectionManagerUtil.beginDBTransaction(); ConnectionManagerUtil.beginDBTransaction();
ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(releaseUuid, tenantId); ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(releaseUuid, tenantId);
DeviceType deviceTypeObj = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId());
AtomicReference<ApplicationReleaseDTO> applicationReleaseDTO = new AtomicReference<>( AtomicReference<ApplicationReleaseDTO> applicationReleaseDTO = new AtomicReference<>(
applicationDTO.getApplicationReleaseDTOs().get(0)); applicationDTO.getApplicationReleaseDTOs().get(0));
validateAppReleaseUpdating(entAppReleaseWrapper, applicationDTO, applicationArtifact, validateAppReleaseUpdating(entAppReleaseWrapper, applicationDTO, applicationArtifact,
@ -2681,9 +2696,18 @@ public class ApplicationManagerImpl implements ApplicationManager {
applicationReleaseDTO.get().setMetaData(entAppReleaseWrapper.getMetaData()); applicationReleaseDTO.get().setMetaData(entAppReleaseWrapper.getMetaData());
} }
//If the application device type is WINDOWS, it is allowed to modify version number and package name.
if (DeviceTypes.WINDOWS.toString().equalsIgnoreCase(deviceTypeObj.getName())) {
if (!StringUtils.isEmpty(entAppReleaseWrapper.getVersion())) {
applicationReleaseDTO.get().setVersion(entAppReleaseWrapper.getVersion());
}
if (!StringUtils.isEmpty(entAppReleaseWrapper.getPackageName())) {
applicationReleaseDTO.get().setPackageName(entAppReleaseWrapper.getPackageName());
}
}
if (!StringUtils.isEmpty(applicationArtifact.getInstallerName()) if (!StringUtils.isEmpty(applicationArtifact.getInstallerName())
&& applicationArtifact.getInstallerStream() != null) { && applicationArtifact.getInstallerStream() != null) {
DeviceType deviceTypeObj = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId());
applicationReleaseDTO applicationReleaseDTO
.set(updateEntAppReleaseArtifact(deviceTypeObj.getName(), applicationReleaseDTO.get(), .set(updateEntAppReleaseArtifact(deviceTypeObj.getName(), applicationReleaseDTO.get(),
applicationArtifact)); applicationArtifact));
@ -3326,6 +3350,15 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
//Validating the version number and the packageName of the Windows new applications releases
if (DeviceTypes.WINDOWS.toString().equalsIgnoreCase(deviceType)) {
if (entAppReleaseWrapper.get().getVersion() == null || entAppReleaseWrapper.get().getPackageName() == null) {
String msg = "Application Version number or/and PackageName..both are required only when the app type is " +
deviceType + " platform type";
log.error(msg);
throw new BadRequestException(msg);
}
}
} else if (param instanceof WebAppReleaseWrapper) { } else if (param instanceof WebAppReleaseWrapper) {
WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param; WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param;
UrlValidator urlValidator = new UrlValidator(); UrlValidator urlValidator = new UrlValidator();
@ -3414,18 +3447,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
} }
@Override
public boolean checkSubDeviceIdsForOperations(int operationId, int deviceId) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
ConnectionManagerUtil.openDBConnection();
List<Integer> deviceSubIds = subscriptionDAO.getDeviceSubIdsForOperation(operationId, deviceId, tenantId);
if (deviceSubIds.isEmpty()) {
return false;
}
} catch (ApplicationManagementDAOException e) {
String msg = "Error occurred while getting the device sub ids for the operations";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
return true;
}
@Override @Override
public void updateSubsStatus (int deviceId, int operationId, String status) throws ApplicationManagementException { public void updateSubsStatus (int deviceId, int operationId, String status) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
try { try {
ConnectionManagerUtil.beginDBTransaction(); ConnectionManagerUtil.beginDBTransaction();
List<Integer> deviceSubIds = subscriptionDAO.getDeviceSubIdsForOperation(operationId, deviceId, tenantId); List<Integer> deviceSubIds = subscriptionDAO.getDeviceSubIdsForOperation(operationId, deviceId, tenantId);
if (deviceSubIds.isEmpty()){
ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Couldn't find device subscription for operation id " + operationId;
log.error(msg);
throw new ApplicationManagementException(msg);
}
if (!subscriptionDAO.updateDeviceSubStatus(deviceId, deviceSubIds, status, tenantId)){ if (!subscriptionDAO.updateDeviceSubStatus(deviceId, deviceSubIds, status, tenantId)){
ConnectionManagerUtil.rollbackDBTransaction(); ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Didn't update an any app subscription of device for operation Id: " + operationId; String msg = "Didn't update an any app subscription of device for operation Id: " + operationId;

@ -82,6 +82,7 @@ import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil; import org.wso2.carbon.device.mgt.core.util.MDMAndroidOperationUtil;
import org.wso2.carbon.device.mgt.core.util.MDMIOSOperationUtil; 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.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.device.mgt.common.PaginationResult;
@ -108,7 +109,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
private LifecycleStateManager lifecycleStateManager; private LifecycleStateManager lifecycleStateManager;
public SubscriptionManagerImpl() { public SubscriptionManagerImpl() {
lifecycleStateManager = DataHolder.getInstance().getLifecycleStateManager(); this.lifecycleStateManager = DataHolder.getInstance().getLifecycleStateManager();
this.subscriptionDAO = ApplicationManagementDAOFactory.getSubscriptionDAO(); this.subscriptionDAO = ApplicationManagementDAOFactory.getSubscriptionDAO();
this.applicationDAO = ApplicationManagementDAOFactory.getApplicationDAO(); this.applicationDAO = ApplicationManagementDAOFactory.getApplicationDAO();
} }
@ -549,7 +550,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
boolean isValidSubType = Arrays.stream(SubscriptionType.values()) boolean isValidSubType = Arrays.stream(SubscriptionType.values())
.anyMatch(sub -> sub.name().equalsIgnoreCase(subType)); .anyMatch(sub -> sub.name().equalsIgnoreCase(subType));
if (!isValidSubType) { if (!isValidSubType) {
String msg = "Found invalid subscription type " + subType+ " to install application release" ; String msg = "Found invalid subscription type " + subType+ " to subscribe application release" ;
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
@ -579,8 +580,10 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
ApplicationDTO applicationDTO, String subType, List<String> subscribers, String action) ApplicationDTO applicationDTO, String subType, List<String> subscribers, String action)
throws ApplicationManagementException { throws ApplicationManagementException {
//Get app subscribing info of each device
SubscribingDeviceIdHolder subscribingDeviceIdHolder = getSubscribingDeviceIdHolder(devices, SubscribingDeviceIdHolder subscribingDeviceIdHolder = getSubscribingDeviceIdHolder(devices,
applicationDTO.getApplicationReleaseDTOs().get(0).getId()); applicationDTO.getApplicationReleaseDTOs().get(0).getId());
List<Activity> activityList = new ArrayList<>(); List<Activity> activityList = new ArrayList<>();
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>(); List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
List<DeviceIdentifier> ignoredDeviceIdentifiers = new ArrayList<>(); List<DeviceIdentifier> ignoredDeviceIdentifiers = new ArrayList<>();
@ -1020,6 +1023,18 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
log.error(msg); log.error(msg);
throw new ApplicationManagementException(msg); throw new ApplicationManagementException(msg);
} }
} else if (DeviceTypes.WINDOWS.toString().equalsIgnoreCase(deviceType)) {
app.setType(mobileAppType);
app.setIdentifier(application.getPackageName());
app.setMetaData(application.getApplicationReleases().get(0).getMetaData());
app.setName(application.getInstallerName());
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);
}
} else { } else {
String msg = "Invalid device type is found. Device Type: " + deviceType; String msg = "Invalid device type is found. Device Type: " + deviceType;
log.error(msg); log.error(msg);

@ -304,6 +304,10 @@ public class APIUtil {
applicationReleaseDTO.setIsSharedWithAllTenants(entAppReleaseWrapper.getIsSharedWithAllTenants()); applicationReleaseDTO.setIsSharedWithAllTenants(entAppReleaseWrapper.getIsSharedWithAllTenants());
applicationReleaseDTO.setMetaData(entAppReleaseWrapper.getMetaData()); applicationReleaseDTO.setMetaData(entAppReleaseWrapper.getMetaData());
applicationReleaseDTO.setSupportedOsVersions(entAppReleaseWrapper.getSupportedOsVersions()); applicationReleaseDTO.setSupportedOsVersions(entAppReleaseWrapper.getSupportedOsVersions());
//Setting version number value specifically for windows type and in an instance of android and ios it will be null
applicationReleaseDTO.setVersion(entAppReleaseWrapper.getVersion());
//Setting package name value specifically for windows type and in an instance of android and ios it will be null
applicationReleaseDTO.setPackageName(entAppReleaseWrapper.getPackageName());
} else if (param instanceof WebAppReleaseWrapper){ } else if (param instanceof WebAppReleaseWrapper){
WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param; WebAppReleaseWrapper webAppReleaseWrapper = (WebAppReleaseWrapper) param;
applicationReleaseDTO.setDescription(webAppReleaseWrapper.getDescription()); applicationReleaseDTO.setDescription(webAppReleaseWrapper.getDescription());
@ -358,6 +362,7 @@ public class APIUtil {
application.setTags(applicationDTO.getTags()); application.setTags(applicationDTO.getTags());
application.setUnrestrictedRoles(applicationDTO.getUnrestrictedRoles()); application.setUnrestrictedRoles(applicationDTO.getUnrestrictedRoles());
application.setRating(applicationDTO.getAppRating()); application.setRating(applicationDTO.getAppRating());
application.setInstallerName(applicationDTO.getApplicationReleaseDTOs().get(0).getInstallerName());
List<ApplicationRelease> applicationReleases = new ArrayList<>(); List<ApplicationRelease> applicationReleases = new ArrayList<>();
if (ApplicationType.PUBLIC.toString().equals(applicationDTO.getType()) && application.getCategories() if (ApplicationType.PUBLIC.toString().equals(applicationDTO.getType()) && application.getCategories()
.contains("GooglePlaySyncedApp")) { .contains("GooglePlaySyncedApp")) {
@ -384,6 +389,7 @@ public class APIUtil {
applicationRelease.setDescription(applicationReleaseDTO.getDescription()); applicationRelease.setDescription(applicationReleaseDTO.getDescription());
applicationRelease.setVersion(applicationReleaseDTO.getVersion()); applicationRelease.setVersion(applicationReleaseDTO.getVersion());
applicationRelease.setPackageName(applicationReleaseDTO.getPackageName());
applicationRelease.setUuid(applicationReleaseDTO.getUuid()); applicationRelease.setUuid(applicationReleaseDTO.getUuid());
applicationRelease.setReleaseType(applicationReleaseDTO.getReleaseType()); applicationRelease.setReleaseType(applicationReleaseDTO.getReleaseType());
applicationRelease.setPrice(applicationReleaseDTO.getPrice()); applicationRelease.setPrice(applicationReleaseDTO.getPrice());

@ -65,6 +65,10 @@ public class Constants {
public static final String SUBSCRIBED = "SUBSCRIBED"; public static final String SUBSCRIBED = "SUBSCRIBED";
public static final String UNSUBSCRIBED = "UNSUBSCRIBED"; public static final String UNSUBSCRIBED = "UNSUBSCRIBED";
//App type constants related to window device type
public static final String MSI = "MSI";
public static final String APPX = "APPX";
private static final Map<String, String> AGENT_DATA = new HashMap<>(); private static final Map<String, String> AGENT_DATA = new HashMap<>();
static { static {
AGENT_DATA.put("android", "android-agent.apk"); AGENT_DATA.put("android", "android-agent.apk");

@ -334,7 +334,7 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (ApplicationManagementException e) { } catch (ApplicationManagementException e) {
String msg = "Error occurred while creating a costom application"; String msg = "Error occurred while creating a custom application";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (RequestValidatingException e) { } catch (RequestValidatingException e) {
@ -373,6 +373,10 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
log.error("ApplicationDTO Creation Failed"); log.error("ApplicationDTO Creation Failed");
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} }
} catch (BadRequestException e) {
String msg = "Found incompatible payload with enterprise app release creating request.";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (ApplicationManagementException e) { } catch (ApplicationManagementException e) {
String msg = "Error occurred while creating the application"; String msg = "Error occurred while creating the application";
log.error(msg, e); log.error(msg, e);
@ -716,7 +720,7 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
.changeLifecycleState(applicationUuid, lifecycleChanger); .changeLifecycleState(applicationUuid, lifecycleChanger);
return Response.status(Response.Status.CREATED).entity(applicationRelease).build(); return Response.status(Response.Status.CREATED).entity(applicationRelease).build();
} catch (BadRequestException e) { } catch (BadRequestException e) {
String msg = "Request payload contains invalid data, hence veryfy the request payload."; String msg = "Request payload contains invalid data, hence verify the request payload.";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).build(); return Response.status(Response.Status.BAD_REQUEST).build();
} catch (ForbiddenException e) { } catch (ForbiddenException e) {
@ -1005,10 +1009,10 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
} }
if (attachmentList != null && !attachmentList.isEmpty()) { if (attachmentList != null && !attachmentList.isEmpty()) {
Map<String, InputStream> scrrenshotData = new TreeMap<>(); Map<String, InputStream> screenshotData = new TreeMap<>();
for (Attachment sc : attachmentList) { for (Attachment sc : attachmentList) {
dataHandler = sc.getDataHandler(); dataHandler = sc.getDataHandler();
String screenshotrFileName = dataHandler.getName(); String screenshotFileName = dataHandler.getName();
InputStream screenshotStream = dataHandler.getInputStream(); InputStream screenshotStream = dataHandler.getInputStream();
if (screenshotStream == null) { if (screenshotStream == null) {
String msg = String msg =
@ -1017,16 +1021,16 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
if (screenshotrFileName == null) { if (screenshotFileName == null) {
String msg = String msg =
"Screenshot file name retrieving is failed for one screenshot. Hence can't proceed. " "Screenshot file name retrieving is failed for one screenshot. Hence can't proceed. "
+ "Please verify the screenshots."; + "Please verify the screenshots.";
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
scrrenshotData.put(screenshotrFileName, screenshotStream); screenshotData.put(screenshotFileName, screenshotStream);
} }
applicationArtifact.setScreenshots(scrrenshotData); applicationArtifact.setScreenshots(screenshotData);
} }
return applicationArtifact; return applicationArtifact;
} catch (IOException e) { } catch (IOException e) {

@ -85,6 +85,12 @@
} }
}, },
"deviceTypes": { "deviceTypes": {
"mobileTypes": ["android", "ios"] "mobileTypes": ["android", "ios", "windows"]
},
"windowsDeviceType": {
"appType": ["msi", "appx"]
},
"windowsAppxMsiKeyValueForMetaData": {
"metaKeyArray": ["Package_Url", "Dependency_Package_Url", "Certificate_Hash", "Encoded_Cert_Content", "Package_Family_Name", "Product_Id", "Content_Uri", "File_Hash"]
} }
} }

@ -46,6 +46,7 @@ class NewAppDetailsForm extends React.Component {
categories: [], categories: [],
tags: [], tags: [],
deviceTypes: [], deviceTypes: [],
selectedValue: null,
fetching: false, fetching: false,
roleSearchValue: [], roleSearchValue: [],
unrestrictedRoles: [], unrestrictedRoles: [],
@ -312,12 +313,33 @@ class NewAppDetailsForm extends React.Component {
}); });
}; };
// Event handler for selecting the device type
handleSelect = event => {
this.setState({
selectedValue: event,
});
if (this.props.selectedValueHandler) {
this.props.selectedValueHandler(event);
}
};
// Event handler for selecting the windows app type
handleSelectForAppType = event => {
if (this.props.selectedAppTypeHandler) {
this.props.selectedAppTypeHandler(event);
}
};
render() { render() {
const config = this.props.context;
// Windows installation app types
const appTypes = config.windowsDeviceType.appType;
const { formConfig } = this.props; const { formConfig } = this.props;
const { const {
categories, categories,
tags, tags,
deviceTypes, deviceTypes,
selectedValue,
fetching, fetching,
unrestrictedRoles, unrestrictedRoles,
} = this.state; } = this.state;
@ -358,6 +380,7 @@ class NewAppDetailsForm extends React.Component {
<Select <Select
style={{ width: '100%' }} style={{ width: '100%' }}
placeholder="select device type" placeholder="select device type"
onSelect={this.handleSelect.bind(this)}
> >
{deviceTypes.map(deviceType => { {deviceTypes.map(deviceType => {
return ( return (
@ -396,6 +419,31 @@ class NewAppDetailsForm extends React.Component {
})(<Input placeholder="ex: Lorem App" />)} })(<Input placeholder="ex: Lorem App" />)}
</Form.Item> </Form.Item>
{/* App Type only shown for windows device types for enterprise apps */}
{selectedValue === 'windows' &&
this.props.formConfig.installationType === 'ENTERPRISE' && (
<Form.Item {...formItemLayout} label="App Type">
{getFieldDecorator('appType', {
rules: [
{
required: true,
message: 'Please select app type',
},
],
})(
<Select
style={{ width: '100%' }}
placeholder="select application type"
onSelect={this.handleSelectForAppType}
>
{appTypes.map(appType => {
return <Option key={appType}>{appType}</Option>;
})}
</Select>,
)}
</Form.Item>
)}
{/* description*/} {/* description*/}
<Form.Item {...formItemLayout} label="Description"> <Form.Item {...formItemLayout} label="Description">
{getFieldDecorator('description', { {getFieldDecorator('description', {

@ -33,6 +33,7 @@ import {
} from 'antd'; } from 'antd';
import '@babel/polyfill'; import '@babel/polyfill';
import Authorized from '../../../../../../../../components/Authorized/Authorized'; import Authorized from '../../../../../../../../components/Authorized/Authorized';
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
const { Text } = Typography; const { Text } = Typography;
@ -59,6 +60,12 @@ function getBase64(file) {
}); });
} }
// function for access the full name of the binary file using the installation path
function extractBinaryFileName(installationPath) {
let UploadedBinaryName = installationPath.split('/');
return UploadedBinaryName[UploadedBinaryName.length - 1];
}
class NewAppUploadForm extends React.Component { class NewAppUploadForm extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -77,6 +84,7 @@ class NewAppUploadForm extends React.Component {
osVersionsHelperText: '', osVersionsHelperText: '',
osVersionsValidateStatus: 'validating', osVersionsValidateStatus: 'validating',
metaData: [], metaData: [],
appType: null,
}; };
this.lowerOsVersion = null; this.lowerOsVersion = null;
this.upperOsVersion = null; this.upperOsVersion = null;
@ -93,6 +101,8 @@ class NewAppUploadForm extends React.Component {
e.preventDefault(); e.preventDefault();
const { formConfig } = this.props; const { formConfig } = this.props;
const { specificElements } = formConfig; const { specificElements } = formConfig;
let windowsAppTypeMetaArray = [];
let metaValue = [];
this.props.form.validateFields((err, values) => { this.props.form.validateFields((err, values) => {
if (!err) { if (!err) {
@ -107,6 +117,19 @@ class NewAppUploadForm extends React.Component {
releaseType, releaseType,
} = values; } = values;
/**
* To save the metaData value that receive from
* metaData UI In an windows app type creation
*/
if (
((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows') ||
this.props.deviceType === 'windows') &&
this.state.metaData.length !== 0
) {
metaValue = [...this.state.metaData];
}
// add release data // add release data
const release = { const release = {
description: releaseDescription, description: releaseDescription,
@ -116,6 +139,90 @@ class NewAppUploadForm extends React.Component {
releaseType: releaseType, releaseType: releaseType,
}; };
const data = new FormData();
const config = this.props.context;
// Accessing the Meta Key value for windows device type from the config.json file
const metaKeyValues =
config.windowsAppxMsiKeyValueForMetaData.metaKeyArray;
/*
Setting up the app type specific values to the
metaData state field and Setting up the version
and the packageName for windows type
*/
if (
(this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows') ||
this.props.deviceType === 'windows'
) {
// Setting up the version and packageName
release.version = values.version;
release.packageName = values.packageName;
// setting the metaData value for appx type
if (
this.props.selectedAppType === 'appx' ||
this.state.appType === 'appx'
) {
windowsAppTypeMetaArray = [
{
key: metaKeyValues[0],
value: values.packageUrl,
},
{
key: metaKeyValues[1],
value: values.dependencyPackageUrl,
},
{
key: metaKeyValues[2],
value: values.certificateHash,
},
{
key: metaKeyValues[3],
value: values.encodedCertContent,
},
{
key: metaKeyValues[4],
value: values.packageName,
},
];
windowsAppTypeMetaArray = [
...windowsAppTypeMetaArray,
...metaValue,
];
} else if (
this.props.selectedAppType === 'msi' ||
this.state.appType === 'msi'
) {
windowsAppTypeMetaArray = [
{
key: metaKeyValues[5],
value: values.productId,
},
{
key: metaKeyValues[6],
value: values.contentUri,
},
{
key: metaKeyValues[7],
value: values.fileHash,
},
];
windowsAppTypeMetaArray = [
...windowsAppTypeMetaArray,
...metaValue,
];
}
this.setState(
{
metaData: windowsAppTypeMetaArray,
},
() => {
release.metaData = JSON.stringify(this.state.metaData);
this.props.onSuccessReleaseData({ data, release });
},
);
}
if (specificElements.hasOwnProperty('version')) { if (specificElements.hasOwnProperty('version')) {
release.version = values.version; release.version = values.version;
} }
@ -126,7 +233,6 @@ class NewAppUploadForm extends React.Component {
release.packageName = values.packageName; release.packageName = values.packageName;
} }
const data = new FormData();
let isFormValid = true; // flag to check if this form is valid let isFormValid = true; // flag to check if this form is valid
if ( if (
@ -187,7 +293,16 @@ class NewAppUploadForm extends React.Component {
if (specificElements.hasOwnProperty('binaryFile')) { if (specificElements.hasOwnProperty('binaryFile')) {
data.append('binaryFile', binaryFile[0].originFileObj); data.append('binaryFile', binaryFile[0].originFileObj);
} }
this.props.onSuccessReleaseData({ data, release }); // Condition to check is it not an Enterprise windows app creation or release
if (
!(
this.props.selectedValue === 'windows' &&
this.props.formConfig.installationType === 'ENTERPRISE'
) &&
this.props.deviceType !== 'windows'
) {
this.props.onSuccessReleaseData({ data, release });
}
} }
} }
}); });
@ -203,13 +318,44 @@ class NewAppUploadForm extends React.Component {
icons: fileList, icons: fileList,
}); });
}; };
handleBinaryFileChange = ({ fileList }) => { handleBinaryFileChange = ({ fileList }) => {
let validity = true;
// To set the app type of windows by using the binary file in an new app release
if (this.props.formConfig.isNewRelease && fileList.length !== 0) {
let firstUploadedBinaryFileName = extractBinaryFileName(
this.props.uploadedInstalltionAppType,
);
let FirstFileExtension = firstUploadedBinaryFileName.substr(
firstUploadedBinaryFileName.lastIndexOf('.') + 1,
);
let LastFileExtension = fileList[0].name.substr(
fileList[0].name.lastIndexOf('.') + 1,
);
if (FirstFileExtension !== LastFileExtension) {
validity = false;
} else if (LastFileExtension === 'msi' || LastFileExtension === 'appx') {
this.setState({
appType: LastFileExtension,
});
}
}
if (fileList.length === 1) { if (fileList.length === 1) {
this.setState({ this.setState({
binaryFileHelperText: '', binaryFileHelperText: '',
}); });
} }
this.setState({ binaryFiles: fileList });
if (validity) {
this.setState({
binaryFiles: fileList,
});
} else {
this.setState({
binaryFileHelperText: 'Upload Correct Binary File extension',
});
}
}; };
handleScreenshotChange = ({ fileList }) => { handleScreenshotChange = ({ fileList }) => {
@ -266,6 +412,7 @@ class NewAppUploadForm extends React.Component {
render() { render() {
const { formConfig, supportedOsVersions } = this.props; const { formConfig, supportedOsVersions } = this.props;
const { getFieldDecorator } = this.props.form; const { getFieldDecorator } = this.props.form;
const config = this.props.context;
const { const {
icons, icons,
screenshots, screenshots,
@ -399,7 +546,12 @@ class NewAppUploadForm extends React.Component {
</Text> </Text>
</Col> </Col>
</Row> </Row>
{formConfig.specificElements.hasOwnProperty('packageName') && (
{/* Package Name field for windows device type and other specific scene using it */}
{(formConfig.specificElements.hasOwnProperty('packageName') ||
(this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows') ||
this.props.deviceType === 'windows') && (
<Form.Item {...formItemLayout} label="Package Name"> <Form.Item {...formItemLayout} label="Package Name">
{getFieldDecorator('packageName', { {getFieldDecorator('packageName', {
rules: [ rules: [
@ -425,7 +577,11 @@ class NewAppUploadForm extends React.Component {
</Form.Item> </Form.Item>
)} )}
{formConfig.specificElements.hasOwnProperty('version') && ( {/* Version field for windows device type and other specific scene using it */}
{(formConfig.specificElements.hasOwnProperty('version') ||
(this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows') ||
this.props.deviceType === 'windows') && (
<Form.Item {...formItemLayout} label="Version"> <Form.Item {...formItemLayout} label="Version">
{getFieldDecorator('version', { {getFieldDecorator('version', {
rules: [ rules: [
@ -438,6 +594,127 @@ class NewAppUploadForm extends React.Component {
</Form.Item> </Form.Item>
)} )}
{/* Windows Appx App Type Fields */}
{/* For Windows appx app type only -> Package Url */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'appx') ||
this.state.appType === 'appx') && (
<Form.Item {...formItemLayout} label="Package Url">
{getFieldDecorator('packageUrl', {
rules: [
{
required: true,
message: 'Please input the package url',
},
],
})(<Input placeholder="Package Url" />)}
</Form.Item>
)}
{/* For Windows appx app type only -> Dependency Package Url */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'appx') ||
this.state.appType === 'appx') && (
<Form.Item {...formItemLayout} label="Dependency Package Url">
{getFieldDecorator('dependencyPackageUrl', {})(
<Input placeholder="Dependency Package Url" />,
)}
</Form.Item>
)}
{/* For Windows appx app type only -> Certificate Hash */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'appx') ||
this.state.appType === 'appx') && (
<Form.Item {...formItemLayout} label="Certificate Hash">
{getFieldDecorator('certificateHash', {
rules: [
{
required: true,
message: 'Please input the certificate hash',
},
],
})(<Input placeholder="Certificate Hash" />)}
</Form.Item>
)}
{/* For Windows appx app type only -> Encoded Certificate Content */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'appx') ||
this.state.appType === 'appx') && (
<Form.Item {...formItemLayout} label="Encoded Cert Content">
{getFieldDecorator('encodedCertContent', {
rules: [
{
required: true,
message: 'Give the encoded cert content',
},
],
})(
<TextArea
placeholder="Enter a encoded certificate content"
rows={5}
/>,
)}
</Form.Item>
)}
{/* Windows MSI App Type Fields */}
{/* For Windows msi app type only -> Product Id */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'msi') ||
this.state.appType === 'msi') && (
<Form.Item {...formItemLayout} label="Product Id">
{getFieldDecorator('productId', {
rules: [
{
required: true,
message: 'Please input the product id',
},
],
})(<Input placeholder="Product Id" />)}
</Form.Item>
)}
{/* For Windows msi app type only -> Content URI */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'msi') ||
this.state.appType === 'msi') && (
<Form.Item {...formItemLayout} label="Content URI">
{getFieldDecorator('contentUri', {
rules: [
{
required: true,
message: 'Please input the content uri',
},
],
})(<Input placeholder="Content Uri" />)}
</Form.Item>
)}
{/* For Windows msi app type only -> File Hash */}
{((this.props.formConfig.installationType === 'ENTERPRISE' &&
this.props.selectedValue === 'windows' &&
this.props.selectedAppType === 'msi') ||
this.state.appType === 'msi') && (
<Form.Item {...formItemLayout} label="File Hash">
{getFieldDecorator('fileHash', {
rules: [
{
required: true,
message: 'Please input the file hash',
},
],
})(<Input placeholder="File Hash" />)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Release Type"> <Form.Item {...formItemLayout} label="Release Type">
{getFieldDecorator('releaseType', { {getFieldDecorator('releaseType', {
rules: [ rules: [
@ -547,49 +824,60 @@ class NewAppUploadForm extends React.Component {
{getFieldDecorator('meta', {})( {getFieldDecorator('meta', {})(
<div> <div>
{metaData.map((data, index) => { {metaData.map((data, index) => {
return ( /*
<InputGroup key={index}> Exclude showing the values related to
<Row gutter={8}> windows app type variables in meta Data UI
<Col span={5}> */
<Input if (
placeholder="key" !config.windowsAppxMsiKeyValueForMetaData.metaKeyArray.includes(
value={data.key} data.key,
onChange={e => { )
metaData[index].key = e.currentTarget.value; ) {
this.setState({ return (
metaData, <InputGroup key={index}>
}); <Row gutter={8}>
}} <Col span={5}>
/> <Input
</Col> placeholder="key"
<Col span={8}> value={data.key}
<Input onChange={e => {
placeholder="value" metaData[index].key = e.currentTarget.value;
value={data.value} this.setState({
onChange={e => { metaData,
metaData[index].value = e.currentTarget.value; });
this.setState({ }}
metaData, />
}); </Col>
}} <Col span={8}>
/> <Input
</Col> placeholder="value"
<Col span={3}> value={data.value}
<Button onChange={e => {
type="dashed" metaData[index].value =
shape="circle" e.currentTarget.value;
icon={<MinusOutlined />} this.setState({
onClick={() => { metaData,
metaData.splice(index, 1); });
this.setState({ }}
metaData, />
}); </Col>
}} <Col span={3}>
/> <Button
</Col> type="dashed"
</Row> shape="circle"
</InputGroup> icon={<MinusOutlined />}
); onClick={() => {
metaData.splice(index, 1);
this.setState({
metaData,
});
}}
/>
</Col>
</Row>
</InputGroup>
);
}
})} })}
<Button <Button
type="dashed" type="dashed"
@ -633,4 +921,6 @@ class NewAppUploadForm extends React.Component {
} }
} }
export default Form.create({ name: 'app-upload-form' })(NewAppUploadForm); export default withConfigContext(
Form.create({ name: 'app-upload-form' })(NewAppUploadForm),
);

@ -44,6 +44,8 @@ class AddNewAppFormComponent extends React.Component {
release: null, release: null,
isError: false, isError: false,
deviceType: null, deviceType: null,
selectedValue: null,
selectedAppType: null,
supportedOsVersions: [], supportedOsVersions: [],
errorText: '', errorText: '',
forbiddenErrors: { forbiddenErrors: {
@ -157,6 +159,20 @@ class AddNewAppFormComponent extends React.Component {
}); });
}; };
// For passing the device type as the prop for other component
selectedValueHandler = selectedValue => {
this.setState({
selectedValue,
});
};
// For passing the app type as the prop for other component
selectedAppTypeHandler = selectedAppType => {
this.setState({
selectedAppType,
});
};
render() { render() {
const { const {
loading, loading,
@ -164,6 +180,8 @@ class AddNewAppFormComponent extends React.Component {
isError, isError,
supportedOsVersions, supportedOsVersions,
errorText, errorText,
selectedValue,
selectedAppType,
} = this.state; } = this.state;
const { formConfig } = this.props; const { formConfig } = this.props;
return ( return (
@ -180,18 +198,21 @@ class AddNewAppFormComponent extends React.Component {
<div style={{ display: current === 0 ? 'unset' : 'none' }}> <div style={{ display: current === 0 ? 'unset' : 'none' }}>
<NewAppDetailsForm <NewAppDetailsForm
formConfig={formConfig} formConfig={formConfig}
selectedValueHandler={this.selectedValueHandler}
selectedAppTypeHandler={this.selectedAppTypeHandler}
onSuccessApplicationData={this.onSuccessApplicationData} onSuccessApplicationData={this.onSuccessApplicationData}
/> />
</div> </div>
<div style={{ display: current === 1 ? 'unset' : 'none' }}> <div style={{ display: current === 1 ? 'unset' : 'none' }}>
<NewAppUploadForm <NewAppUploadForm
formConfig={formConfig} formConfig={formConfig}
selectedValue={selectedValue}
selectedAppType={selectedAppType}
supportedOsVersions={supportedOsVersions} supportedOsVersions={supportedOsVersions}
onSuccessReleaseData={this.onSuccessReleaseData} onSuccessReleaseData={this.onSuccessReleaseData}
onClickBackButton={this.onClickBackButton} onClickBackButton={this.onClickBackButton}
/> />
</div> </div>
<div style={{ display: current === 2 ? 'unset' : 'none' }}> <div style={{ display: current === 2 ? 'unset' : 'none' }}>
{!isError && ( {!isError && (
<Result <Result

@ -27,6 +27,7 @@ import { handleApiError } from '../../../../../../services/utils/errorHandler';
import NewAppUploadForm from '../../../AddNewApp/components/AddNewAppForm/components/NewAppUploadForm'; import NewAppUploadForm from '../../../AddNewApp/components/AddNewAppForm/components/NewAppUploadForm';
const formConfig = { const formConfig = {
isNewRelease: true,
specificElements: { specificElements: {
binaryFile: { binaryFile: {
required: true, required: true,
@ -127,7 +128,10 @@ class AddNewReleaseFormComponent extends React.Component {
description: 'New release was added successfully', description: 'New release was added successfully',
}); });
const uuid = res.data.data.uuid; const uuid = res.data.data.uuid;
this.props.history.push('/publisher/apps/releases/' + uuid); this.props.history.push({
pathname: '/publisher/apps/releases/' + uuid,
state: { fullAppDetails: this.props.location.state.fullAppDetails },
});
} else { } else {
this.setState({ this.setState({
loading: false, loading: false,
@ -160,6 +164,11 @@ class AddNewReleaseFormComponent extends React.Component {
<NewAppUploadForm <NewAppUploadForm
forbiddenErrors={forbiddenErrors} forbiddenErrors={forbiddenErrors}
formConfig={formConfig} formConfig={formConfig}
deviceType={this.props.deviceType}
// Takes the first upload app type installation path
uploadedInstalltionAppType={
this.props.location.state.appDetails.installerPath
}
supportedOsVersions={supportedOsVersions} supportedOsVersions={supportedOsVersions}
onSuccessReleaseData={this.onSuccessReleaseData} onSuccessReleaseData={this.onSuccessReleaseData}
onClickBackButton={this.onClickBackButton} onClickBackButton={this.onClickBackButton}

@ -702,7 +702,14 @@ class AppDetailsDrawer extends React.Component {
title="Click to view full details" title="Click to view full details"
placement="topRight" placement="topRight"
> >
<Link to={'apps/releases/' + release.uuid}> <Link
to={{
pathname: `apps/releases/${release.uuid}`,
state: {
fullAppDetails: app.applicationReleases,
},
}}
>
<Card className="release-card"> <Card className="release-card">
<Meta <Meta
avatar={ avatar={
@ -773,7 +780,13 @@ class AppDetailsDrawer extends React.Component {
<Text>Add new release for the application</Text> <Text>Add new release for the application</Text>
</div> </div>
<Link <Link
to={`/publisher/apps/${app.deviceType}/${app.id}/add-release`} to={{
pathname: `/publisher/apps/${app.deviceType}/${app.id}/add-release`,
state: {
appDetails: app.applicationReleases[0],
fullAppDetails: app.applicationReleases,
},
}}
> >
<Button htmlType="button" type="primary" size="small"> <Button htmlType="button" type="primary" size="small">
Add Add

@ -27,6 +27,7 @@ import {
Steps, Steps,
Alert, Alert,
Tabs, Tabs,
Tooltip,
} from 'antd'; } from 'antd';
import axios from 'axios'; import axios from 'axios';
import ReactQuill from 'react-quill'; import ReactQuill from 'react-quill';
@ -76,6 +77,7 @@ class LifeCycle extends React.Component {
current: 0, current: 0,
lifecycleSteps: [], lifecycleSteps: [],
lifeCycleStates: [], lifeCycleStates: [],
isPublished: false,
}; };
} }
@ -85,9 +87,11 @@ class LifeCycle extends React.Component {
const lifecycleSteps = Object.keys(lifeCycleConfig).map(config => { const lifecycleSteps = Object.keys(lifeCycleConfig).map(config => {
return lifeCycleConfig[config]; return lifeCycleConfig[config];
}); });
let isPublished = this.checkReleaseLifeCycleStatus();
this.setState({ this.setState({
current: lifeCycleConfig[this.props.currentStatus].step, current: lifeCycleConfig[this.props.currentStatus].step,
lifecycleSteps, lifecycleSteps,
isPublished,
}); });
this.getLifeCycleHistory(); this.getLifeCycleHistory();
} }
@ -198,6 +202,27 @@ class LifeCycle extends React.Component {
this.setState({ current }); this.setState({ current });
}; };
/*
Function to check if the same app releases are in published
state or not and assigned a boolean value to disable
the publish button if an app release is already published
*/
checkReleaseLifeCycleStatus = () => {
if (typeof this.props.appReleases !== 'undefined') {
let appReleases = this.props.appReleases.fullAppDetails;
for (let i = 0; i < appReleases.length; i++) {
if (
this.props.uuid !== appReleases[i].uuid &&
appReleases[i].currentStatus === 'PUBLISHED'
) {
return true;
}
}
return false;
}
return false;
};
render() { render() {
const { const {
currentStatus, currentStatus,
@ -207,6 +232,7 @@ class LifeCycle extends React.Component {
lifeCycleStates, lifeCycleStates,
} = this.state; } = this.state;
const { lifecycle } = this.props; const { lifecycle } = this.props;
const text = <span>Already an app is in publish state</span>;
let proceedingStates = []; let proceedingStates = [];
if ( if (
lifecycle !== null && lifecycle !== null &&
@ -247,17 +273,31 @@ class LifeCycle extends React.Component {
<p>{step.text}</p> <p>{step.text}</p>
{proceedingStates.map(lifecycleState => { {proceedingStates.map(lifecycleState => {
return ( return (
<Button <Tooltip
size={'small'}
style={{ marginRight: 3 }}
onClick={() =>
this.showReasonModal(lifecycleState)
}
key={lifecycleState} key={lifecycleState}
type={'primary'} title={
lifecycleState === 'PUBLISHED' &&
this.state.isPublished
? text
: ''
}
> >
{lifecycleState} <Button
</Button> size={'small'}
style={{ marginRight: 3 }}
disabled={
lifecycleState === 'PUBLISHED' &&
this.state.isPublished
}
onClick={() =>
this.showReasonModal(lifecycleState)
}
key={lifecycleState}
type={'primary'}
>
{lifecycleState}
</Button>
</Tooltip>
); );
})} })}
</div> </div>

@ -65,6 +65,12 @@ function getBase64(file) {
reader.onerror = error => reject(error); reader.onerror = error => reject(error);
}); });
} }
// function for access the name of the binary file using the installation path
function extractBinaryFileName(installationPath) {
let UploadedBinaryName = installationPath.split('/');
let binaryFileName = UploadedBinaryName[UploadedBinaryName.length - 1];
return binaryFileName.substr(binaryFileName.lastIndexOf('.') + 1);
}
class EditReleaseModal extends React.Component { class EditReleaseModal extends React.Component {
// To add subscription type & tenancy sharing, refer https://gitlab.com/entgra/carbon-device-mgt/merge_requests/331 // To add subscription type & tenancy sharing, refer https://gitlab.com/entgra/carbon-device-mgt/merge_requests/331
@ -156,7 +162,6 @@ class EditReleaseModal extends React.Component {
const { formConfig } = this.state; const { formConfig } = this.state;
const { specificElements } = formConfig; const { specificElements } = formConfig;
let metaData = []; let metaData = [];
try { try {
metaData = JSON.parse(release.metaData); metaData = JSON.parse(release.metaData);
} catch (e) { } catch (e) {
@ -185,26 +190,34 @@ class EditReleaseModal extends React.Component {
}, },
}); });
} }
if (specificElements.hasOwnProperty('version')) { // Showing the packageName value in the edit form UI
if (
formConfig.specificElements.hasOwnProperty('packageName') ||
(this.props.type === 'ENTERPRISE' && this.props.deviceType === 'windows')
) {
this.props.form.setFields({ this.props.form.setFields({
version: { packageName: {
value: release.version, value: release.packageName,
}, },
}); });
} }
if (specificElements.hasOwnProperty('url')) { // Showing the version value in the edit form UI
if (
formConfig.specificElements.hasOwnProperty('version') ||
(this.props.type === 'ENTERPRISE' && this.props.deviceType === 'windows')
) {
this.props.form.setFields({ this.props.form.setFields({
url: { version: {
value: release.url, value: release.version,
}, },
}); });
} }
if (specificElements.hasOwnProperty('packageName')) { if (specificElements.hasOwnProperty('url')) {
this.props.form.setFields({ this.props.form.setFields({
packageName: { url: {
value: release.packageName, value: release.url,
}, },
}); });
} }
@ -248,6 +261,10 @@ class EditReleaseModal extends React.Component {
const { formConfig } = this.state; const { formConfig } = this.state;
const { specificElements } = formConfig; const { specificElements } = formConfig;
// Accessing the extension type of the current uploaded binary file
const appTypeExtension = extractBinaryFileName(
this.props.release.installerPath,
);
this.props.form.validateFields((err, values) => { this.props.form.validateFields((err, values) => {
if (!err) { if (!err) {
@ -280,10 +297,38 @@ class EditReleaseModal extends React.Component {
data.append('binaryFile', binaryFiles[0].originFileObj); data.append('binaryFile', binaryFiles[0].originFileObj);
} }
if (specificElements.hasOwnProperty('version')) { if (
specificElements.hasOwnProperty('version') ||
(this.props.type === 'ENTERPRISE' &&
this.props.deviceType === 'windows')
) {
release.version = values.version; release.version = values.version;
} }
// Accessing the Meta Key value for windows device type from the config.json file
const metaKeyValues =
config.windowsAppxMsiKeyValueForMetaData.metaKeyArray;
if (
specificElements.hasOwnProperty('packageName') ||
(this.props.type === 'ENTERPRISE' &&
this.props.deviceType === 'windows')
) {
release.packageName = values.packageName;
// Setting up the packageName to the package_Family_Name key in an appx app type instance
if (appTypeExtension === config.windowsDeviceType.appType[1]) {
let metaDataArray = this.state.metaData;
let filterMetaArray = metaDataArray.filter(
obj => obj.key !== metaKeyValues[4],
);
filterMetaArray.push({
key: metaKeyValues[4],
value: values.packageName,
});
release.metaData = JSON.stringify(filterMetaArray);
}
}
if (specificElements.hasOwnProperty('url')) { if (specificElements.hasOwnProperty('url')) {
release.url = values.url; release.url = values.url;
} }
@ -335,7 +380,6 @@ class EditReleaseModal extends React.Component {
message: 'Done!', message: 'Done!',
description: 'Saved!', description: 'Saved!',
}); });
// console.log(updatedRelease);
this.props.updateRelease(updatedRelease); this.props.updateRelease(updatedRelease);
} }
}) })
@ -463,7 +507,6 @@ class EditReleaseModal extends React.Component {
)} )}
</Form.Item> </Form.Item>
)} )}
{formConfig.specificElements.hasOwnProperty('url') && ( {formConfig.specificElements.hasOwnProperty('url') && (
<Form.Item {...formItemLayout} label="URL"> <Form.Item {...formItemLayout} label="URL">
{getFieldDecorator('url', { {getFieldDecorator('url', {
@ -477,19 +520,6 @@ class EditReleaseModal extends React.Component {
</Form.Item> </Form.Item>
)} )}
{formConfig.specificElements.hasOwnProperty('version') && (
<Form.Item {...formItemLayout} label="Version">
{getFieldDecorator('version', {
rules: [
{
required: true,
message: 'Please input the version',
},
],
})(<Input placeholder="Version" />)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Icon"> <Form.Item {...formItemLayout} label="Icon">
{getFieldDecorator('icon', { {getFieldDecorator('icon', {
valuePropName: 'icon', valuePropName: 'icon',
@ -528,6 +558,38 @@ class EditReleaseModal extends React.Component {
)} )}
</Form.Item> </Form.Item>
{/* Package Name field for windows device type and other specific scene using it */}
{(formConfig.specificElements.hasOwnProperty('packageName') ||
(this.props.type === 'ENTERPRISE' &&
this.props.deviceType === 'windows')) && (
<Form.Item {...formItemLayout} label="Package Name">
{getFieldDecorator('packageName', {
rules: [
{
required: true,
message: 'Please input the package name',
},
],
})(<Input placeholder="Package Name" />)}
</Form.Item>
)}
{/* Version field for windows device type and other specific scene using it */}
{(formConfig.specificElements.hasOwnProperty('version') ||
(this.props.type === 'ENTERPRISE' &&
this.props.deviceType === 'windows')) && (
<Form.Item {...formItemLayout} label="Version">
{getFieldDecorator('version', {
rules: [
{
required: true,
message: 'Please input the version',
},
],
})(<Input placeholder="Version" />)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Release Type"> <Form.Item {...formItemLayout} label="Release Type">
{getFieldDecorator('releaseType', { {getFieldDecorator('releaseType', {
rules: [ rules: [
@ -650,50 +712,59 @@ class EditReleaseModal extends React.Component {
})( })(
<div> <div>
{metaData.map((data, index) => { {metaData.map((data, index) => {
return ( if (
<InputGroup key={index}> !(
<Row gutter={8}> data.key ===
<Col span={10}> config.windowsAppxMsiKeyValueForMetaData
<Input .metaKeyArray[4]
placeholder="key" )
value={data.key} ) {
onChange={e => { return (
metaData[index].key = e.currentTarget.value; <InputGroup key={index}>
this.setState({ <Row gutter={8}>
metaData, <Col span={10}>
}); <Input
}} placeholder="key"
/> value={data.key}
</Col> onChange={e => {
<Col span={10}> metaData[index].key =
<Input e.currentTarget.value;
placeholder="value" this.setState({
value={data.value} metaData,
onChange={e => { });
metaData[index].value = }}
e.currentTarget.value; />
this.setState({ </Col>
metaData, <Col span={10}>
}); <Input
}} placeholder="value"
/> value={data.value}
</Col> onChange={e => {
<Col span={3}> metaData[index].value =
<Button e.currentTarget.value;
type="dashed" this.setState({
shape="circle" metaData,
icon={<MinusOutlined />} });
onClick={() => { }}
metaData.splice(index, 1); />
this.setState({ </Col>
metaData, <Col span={3}>
}); <Button
}} type="dashed"
/> shape="circle"
</Col> icon={<MinusOutlined />}
</Row> onClick={() => {
</InputGroup> metaData.splice(index, 1);
); this.setState({
metaData,
});
}}
/>
</Col>
</Row>
</InputGroup>
);
}
})} })}
<Button <Button
type="dashed" type="dashed"

@ -41,6 +41,8 @@ class ReleaseView extends React.Component {
const { app, release } = this.props; const { app, release } = this.props;
const config = this.props.context; const config = this.props.context;
const { lifecycle, currentLifecycleStatus } = this.props; const { lifecycle, currentLifecycleStatus } = this.props;
let isKeyInclude = false;
let metaArrayWithOutWindowsKey = [];
if (release == null) { if (release == null) {
return null; return null;
} }
@ -169,21 +171,31 @@ class ReleaseView extends React.Component {
<Text>META DATA</Text> <Text>META DATA</Text>
<Row> <Row>
{metaData.map((data, index) => { {metaData.map((data, index) => {
return ( // Exclude showing the values related to windows app type variables in the metaData UI
<Col if (
key={index} !config.windowsAppxMsiKeyValueForMetaData.metaKeyArray.includes(
lg={8} data.key,
md={6} )
xs={24} ) {
style={{ marginTop: 15 }} isKeyInclude = false;
> metaArrayWithOutWindowsKey.push(data);
<Text>{data.key}</Text> return (
<br /> <Col
<Text type="secondary">{data.value}</Text> key={index}
</Col> lg={8}
); md={6}
xs={24}
style={{ marginTop: 15 }}
>
<Text>{data.key}</Text>
<br />
<Text type="secondary">{data.value}</Text>
</Col>
);
}
})} })}
{metaData.length === 0 && ( {(metaData.length === 0 ||
(!isKeyInclude && metaArrayWithOutWindowsKey.length === 0)) && (
<Text type="secondary">No meta data available.</Text> <Text type="secondary">No meta data available.</Text>
)} )}
</Row> </Row>

@ -232,6 +232,7 @@ class Release extends React.Component {
this.changeCurrentLifecycleStatus this.changeCurrentLifecycleStatus
} }
lifecycle={lifecycle} lifecycle={lifecycle}
appReleases={this.props.location.state}
/> />
)} )}
</Skeleton> </Skeleton>

@ -27,14 +27,12 @@ import io.swagger.annotations.ExtensionProperty;
import io.swagger.annotations.Info; import io.swagger.annotations.Info;
import io.swagger.annotations.SwaggerDefinition; import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag; 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.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.application.mgt.common.ErrorResponse; import org.wso2.carbon.device.application.mgt.common.ErrorResponse;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@ -64,7 +62,7 @@ import java.util.List;
) )
@Scopes( @Scopes(
scopes = { scopes = {
@org.wso2.carbon.apimgt.annotations.api.Scope( @Scope(
name = "View Application Subscriptions", name = "View Application Subscriptions",
description = "View Application Subscriptions.", description = "View Application Subscriptions.",
key = "perm:admin:app:subscription:view", key = "perm:admin:app:subscription:view",

@ -40,5 +40,8 @@
"color": "#008cc4", "color": "#008cc4",
"theme": "filled" "theme": "filled"
} }
},
"windowsAppxMsiKeyValueForMetaData": {
"metaKeyArray": ["Package_Url", "Dependency_Package_Url", "Certificate_Hash", "Encoded_Cert_Content", "Package_Family_Name", "Product_Id", "Content_Uri", "File_Hash"]
} }
} }

@ -148,12 +148,14 @@ class ReleaseView extends React.Component {
const config = this.props.context; const config = this.props.context;
const release = app.applicationReleases[0]; const release = app.applicationReleases[0];
let isKeyInclude = false;
let metaArrayWithOutWindowsKey = [];
let metaData = []; let metaData = [];
try { try {
metaData = JSON.parse(release.metaData); metaData = JSON.parse(release.metaData);
// eslint-disable-next-line no-empty // eslint-disable-next-line no-empty
} catch (e) {} } catch (e) {}
if (app.hasOwnProperty('packageName')) { if (app.type !== 'WEB_CLIP' && app.hasOwnProperty('packageName')) {
metaData.push({ metaData.push({
key: 'Package Name', key: 'Package Name',
value: app.packageName, value: app.packageName,
@ -270,38 +272,42 @@ class ReleaseView extends React.Component {
</div> </div>
<Divider /> <Divider />
<Text>META DATA</Text> <Text>META DATA</Text>
<Row> <Row>
{metaData.map((data, index) => { {metaData.map((data, index) => {
return ( if (
<Col !config.windowsAppxMsiKeyValueForMetaData.metaKeyArray.includes(
key={index} data.key,
lg={8} )
md={6} ) {
xs={24} isKeyInclude = false;
style={{ marginTop: 15 }} metaArrayWithOutWindowsKey.push(data);
> return (
<Text>{data.key}</Text> <Col
<br /> key={index}
<Text type="secondary">{data.value}</Text> lg={8}
</Col> md={6}
); xs={24}
style={{ marginTop: 15 }}
>
<Text>{data.key}</Text>
<br />
<Text type="secondary">{data.value}</Text>
</Col>
);
}
})} })}
{metaData.length === 0 && ( {(metaData.length === 0 ||
(!isKeyInclude &&
metaArrayWithOutWindowsKey.length === 0)) && (
<Text type="secondary">No meta data available.</Text> <Text type="secondary">No meta data available.</Text>
)} )}
</Row> </Row>
<Divider /> <Divider />
<ReviewContainer uuid={release.uuid} /> <ReviewContainer uuid={release.uuid} />
</TabPane> </TabPane>
<Authorized <TabPane tab="Subscription Details" key="2">
permission="/permission/admin/app-mgt/store/admin/subscription/view" <SubscriptionDetails uuid={release.uuid} />
yes={ </TabPane>
<TabPane tab="Subscription Details" key="2">
<SubscriptionDetails uuid={release.uuid} />
</TabPane>
}
/>
</Tabs> </Tabs>
</div> </div>
</div> </div>

@ -96,10 +96,10 @@ class Login extends React.Component {
const config = this.props.context; const config = this.props.context;
return ( return (
<div className="login"> <div className="login">
<div className="background"></div> <div className="background" />
<div className="content"> <div className="content">
<Row> <Row>
<Col xs={3} sm={3} md={10}></Col> <Col xs={3} sm={3} md={10} />
<Col xs={18} sm={18} md={4}> <Col xs={18} sm={18} md={4}>
<Row style={{ marginBottom: 20 }}> <Row style={{ marginBottom: 20 }}>
<Col <Col
@ -174,7 +174,7 @@ class Login extends React.Component {
</Col> </Col>
</Row> </Row>
<Row> <Row>
<Col span={4} offset={10}></Col> <Col span={4} offset={10} />
</Row> </Row>
</div> </div>
</div> </div>

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, 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 io.swagger.annotations.ApiModelProperty;
public class EventAction {
@ApiModelProperty(
name = "actionType",
value = "Type of the event action to be triggered in the device level",
required = true)
private String actionType;
@ApiModelProperty(
name = "payload",
value = "Payload of the event action",
required = true)
private Object payload;
public String getActionType() {
return actionType;
}
public void setActionType(String actionType) {
this.actionType = actionType;
}
public Object getPayload() {
return payload;
}
public void setPayload(Object payload) {
this.payload = payload;
}
}

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020, 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 io.swagger.annotations.ApiModelProperty;
import java.util.List;
public class EventConfig {
@ApiModelProperty(
name = "id",
value = "id of the event entry")
private int id;
@ApiModelProperty(
name = "eventLogic",
value = "Logic of the event should be handled at the device level",
required = true)
private String eventLogic;
@ApiModelProperty(
name = "actions",
value = "List of actions to be triggered according to the logic",
required = true)
private List<EventAction> actions;
public String getEventLogic() {
return eventLogic;
}
public void setEventLogic(String eventLogic) {
this.eventLogic = eventLogic;
}
public List<EventAction> getActions() {
return actions;
}
public void setActions(List<EventAction> actions) {
this.actions = actions;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020, 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 com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.List;
public class GeofenceList extends BasePaginatedResult {
private List<GeofenceWrapper> geofenceList = new ArrayList<>();
@ApiModelProperty(value = "List of geofences returned")
@JsonProperty("geofences")
public List<GeofenceWrapper> getGeofenceList() {
return geofenceList;
}
public void setGeofenceList(List<GeofenceWrapper> geofenceList) {
this.geofenceList = geofenceList;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{\n");
sb.append(" count: ").append(getCount()).append(",\n");
sb.append(" geofences: [").append(geofenceList).append("\n");
sb.append("]}\n");
return sb.toString();
}
}

@ -0,0 +1,171 @@
/*
* Copyright (c) 2020, 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 io.swagger.annotations.ApiModelProperty;
import java.util.List;
import java.util.Map;
public class GeofenceWrapper {
@ApiModelProperty(
name = "id",
value = "Id of the geo fence")
private int id;
@ApiModelProperty(
name = "fenceName",
value = "Name of the geo fence",
required = true)
private String fenceName;
@ApiModelProperty(
name = "description",
value = "Description of the geo fence")
private String description;
@ApiModelProperty(
name = "latitude",
value = "Latitude of center of the geo fence")
private double latitude;
@ApiModelProperty(
name = "longitude",
value = "Longitude of center of the geo fence")
private double longitude;
@ApiModelProperty(
name = "radius",
value = "Radius from the center")
private float radius;
@ApiModelProperty(
name = "geoJson",
value = "JSON data set of the polygon fence")
private String geoJson;
@ApiModelProperty(
name = "fenceShape",
value = "Shape of the fence",
required = true)
private String fenceShape;
@ApiModelProperty(
name = "eventConfig",
value = "Event configuration of the geofence",
required = true)
private List<EventConfig> eventConfig;
@ApiModelProperty(
name = "groupIds",
value = "Group ids mapped with geo fences",
required = true)
private List<Integer> groupIds;
private Map<Integer, String> groupNames;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFenceName() {
return fenceName;
}
public void setFenceName(String fenceName) {
this.fenceName = fenceName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public String getGeoJson() {
return geoJson;
}
public void setGeoJson(String geoJson) {
this.geoJson = geoJson;
}
public String getFenceShape() {
return fenceShape;
}
public void setFenceShape(String fenceShape) {
this.fenceShape = fenceShape;
}
public List<EventConfig> getEventConfig() {
return eventConfig;
}
public void setEventConfig(List<EventConfig> eventConfig) {
this.eventConfig = eventConfig;
}
public List<Integer> getGroupIds() {
return groupIds;
}
public void setGroupIds(List<Integer> groupIds) {
this.groupIds = groupIds;
}
public Map<Integer, String> getGroupNames() {
return groupNames;
}
public void setGroupNames(Map<Integer, String> groupNames) {
this.groupNames = groupNames;
}
}

@ -49,6 +49,12 @@ import java.util.List;
+ "Wrappers") + "Wrappers")
public class PolicyWrapper { public class PolicyWrapper {
@ApiModelProperty(
name = "payloadVersion",
value = "Payload version of the Policy")
@Size(max = 45)
private String payloadVersion;
@ApiModelProperty( @ApiModelProperty(
name = "policyName", name = "policyName",
value = "The name of the policy", value = "The name of the policy",
@ -126,12 +132,18 @@ public class PolicyWrapper {
@NotNull @NotNull
private String policyType; private String policyType;
@ApiModelProperty( @ApiModelProperty(name = "correctiveActions",
name = "correctiveActions", value = "List of corrective actions to be applied when the policy is violated")
value = "List of corrective actions to be applied when the policy is violated"
)
private List<CorrectiveAction> correctiveActions; private List<CorrectiveAction> correctiveActions;
public String getPayloadVersion() {
return payloadVersion;
}
public void setPayloadVersion(String payloadVersion) {
this.payloadVersion = payloadVersion;
}
public String getPolicyType() { public String getPolicyType() {
return policyType; return policyType;
} }

@ -21,8 +21,10 @@ package org.wso2.carbon.device.mgt.jaxrs.beans;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.policy.mgt.CorrectiveAction;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
@ApiModel(value = "ProfileFeature", description = "This class carries all information related to profile " @ApiModel(value = "ProfileFeature", description = "This class carries all information related to profile "
+ "features") + "features")
@ -57,6 +59,9 @@ public class ProfileFeature implements Serializable {
value = "The payload which is submitted to each feature", value = "The payload which is submitted to each feature",
required = true) required = true)
private String payLoad; private String payLoad;
@ApiModelProperty(name = "correctiveActions",
value = "List of corrective actions to be applied when the policy is violated")
private List<CorrectiveAction> correctiveActions;
public int getId() { public int getId() {
return id; return id;
@ -109,4 +114,12 @@ public class ProfileFeature implements Serializable {
public void setContent(Object content) { public void setContent(Object content) {
this.content = content; this.content = content;
} }
public List<CorrectiveAction> getCorrectiveActions() {
return correctiveActions;
}
public void setCorrectiveActions(List<CorrectiveAction> correctiveActions) {
this.correctiveActions = correctiveActions;
}
} }

@ -393,6 +393,96 @@ public interface DeviceManagementService {
@QueryParam("limit") @QueryParam("limit")
int limit); int limit);
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{groupId}/location-history")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Getting the Location Details of Devices in the group",
notes = "Get the location details of devices in the group during a define time period.",
response = Response.class,
tags = "Device Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the details of the device.",
response = Device.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 304,
message = "Not Modified. Empty body because the client already has the latest version" +
" of the requested resource.\n"),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 404,
message = "Not Found. \n Location history details for the devices with the specified group id was not found.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n " +
"Server error occurred while retrieving the devices location history details.",
response = ErrorResponse.class)
})
Response getDevicesGroupLocationInfo(
@ApiParam(
name = "groupId",
value = "The group ID.",
required = true)
@PathParam("groupId") int groupId,
@ApiParam(
name = "from",
value = "Define the time to start getting the geo location history of the device in " +
"milliseconds.",
required = true)
@QueryParam("from") long from,
@ApiParam(
name = "to",
value = "Define the time to finish getting the geo location history of the device in " +
"milliseconds.",
required = true)
@QueryParam("to") long to,
@ApiParam(
name = "type",
value = "Defines how the output should be.",
required = true)
@QueryParam("type") String type,
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.",
required = false,
defaultValue = "0")
@QueryParam("offset") int offset,
@ApiParam(
name = "limit",
value = "Provide how many device details you require from the starting pagination index/offset.",
required = false,
defaultValue = "100")
@QueryParam("limit") int limit
);
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/{type}/{id}") @Path("/{type}/{id}")
@ -551,7 +641,12 @@ public interface DeviceManagementService {
value = "Define the time to finish getting the geo location history of the device in " + value = "Define the time to finish getting the geo location history of the device in " +
"milliseconds.", "milliseconds.",
required = true) required = true)
@QueryParam("to") long to); @QueryParam("to") long to,
@ApiParam(
name = "type",
value = "Defines how the output should be.",
required = true)
@QueryParam("type") String type);
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -1493,8 +1588,38 @@ public interface DeviceManagementService {
@ApiParam( @ApiParam(
name = "ownership", name = "ownership",
value = "Provides the ownership of the required device.") value = "Provides the ownership of the required device.")
@QueryParam("owner") @QueryParam("ownership")
String ownership); String ownership,
@ApiParam(
name = "createdFrom",
value = "Since when user wants to filter operation logs using the created data and time")
@QueryParam("createdFrom")
Long createdFrom,
@ApiParam(
name = "createdTo",
value = "Till when user wants to filter operation logs using the created data and time")
@QueryParam("createdTo")
Long createdTo,
@ApiParam(
name = "updatedFrom",
value = "Since when user wants to filter operation logs using the received date and time")
@QueryParam("updatedFrom")
Long updatedFrom,
@ApiParam(
name = "updatedTo",
value = "Till when user wants to filter operation logs using the received date and time")
@QueryParam("updatedTo")
Long updatedTo,
@ApiParam(
name = "operationCode",
value = "Provides the operation codes to filter the operation logs via operation codes")
@QueryParam("operationCode")
List<String> operationCode,
@ApiParam(
name = "operationStatus",
value = "Provides the status codes to filter operation logs via status")
@QueryParam("operationStatus")
List<String> status);
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)

@ -33,12 +33,15 @@ import io.swagger.annotations.Tag;
import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes; import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.mgt.common.geo.service.Alert; 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;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
@ -46,7 +49,9 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList;
@SwaggerDefinition( @SwaggerDefinition(
info = @Info( info = @Info(
@ -76,6 +81,12 @@ import javax.ws.rs.core.Response;
description = "", description = "",
key = "perm:geo-service:alerts-manage", key = "perm:geo-service:alerts-manage",
permissions = {"/device-mgt/devices/owning-device/manage-alerts"} permissions = {"/device-mgt/devices/owning-device/manage-alerts"}
),
@Scope(
name = "Manage Geo Fences",
description = "",
key = "perm:geo-service:geo-fence",
permissions = {"/device-mgt/devices/owning-device/manage-geo-fence"}
) )
} }
) )
@ -833,5 +844,247 @@ public interface GeoLocationBasedService {
value = "The query name.", value = "The query name.",
required = true) required = true)
@QueryParam("queryName") String queryName); @QueryParam("queryName") String queryName);
@POST
@Path("/geo-fence")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "POST",
value = "Create Geo fence",
notes = "Create a new geo fence",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:geo-fence")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Geofence data found.",
response = ErrorResponse.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = ErrorResponse.class)
})
Response createGeofence(@ApiParam(name = "fence", value = "Geo fence data")GeofenceWrapper geofenceWrapper);
@GET
@Path("/geo-fence/{fenceId}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Get Geo fence",
notes = "Get existing geo fence",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:geo-fence")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 404,
message = "Not found. \n No Geofence found for the Id",
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 getGeofence(
@ApiParam(
name = "fenceId",
value = "Id of the fence",
required = true)
@PathParam("fenceId") int fenceId,
@ApiParam(
name = "requireEventData",
value = "Require geofence event data")
@QueryParam("requireEventData") boolean requireEventData);
@GET
@Path("/geo-fence")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "GET",
value = "Get Geo fences",
notes = "Get all geo fence",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:geo-fence")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Unauthorized request."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error on retrieving stats",
response = Response.class)
})
Response getGeofence(
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.")
@QueryParam("offset") int offset,
@ApiParam(
name = "limit",
value = "Provide how many device details you require from the starting pagination index/offset.")
@QueryParam("limit") int limit,
@ApiParam(
name = "name",
value = "Geo Fence name")
@QueryParam("name") String name,
@ApiParam(
name = "requireEventData",
value = "Require geofence event data")
@QueryParam("requireEventData") boolean requireEventData);
@DELETE
@Path("/geo-fence/{fenceId}")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
httpMethod = "DELETE",
value = "Delete Geo fence",
notes = "Delete an existing geo fence",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:geo-fence")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 404,
message = "Not found. \n No geofences found for the Id",
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 deleteGeofence(
@ApiParam(
name = "fenceId",
value = "Id of the fence",
required = true)
@PathParam("fenceId") int fenceId);
@PUT
@Path("/geo-fence/{fenceId}")
@ApiOperation(
consumes = "application/json",
produces = "application/json",
httpMethod = "PUT",
value = "Update Geo fence",
notes = "Update an existing geo fence",
response = Response.class,
tags = "Geo Service Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:geo-service:geo-fence")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK.",
response = Response.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid Geofence data found.",
response = Response.class),
@ApiResponse(
code = 404,
message = "Not found. \n No Geofence found for the Id",
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 updateGeofence(
@ApiParam(name = "fence", value = "Geo fence data")
GeofenceWrapper geofenceWrapper,
@ApiParam(
name = "fenceId",
value = "Id of the fence",
required = true)
@PathParam("fenceId") int fenceId,
@ApiParam(name = "eventIds", value = "Event id list to be removed") @QueryParam("eventIds") int[] eventIds);
} }

@ -57,8 +57,10 @@ import javax.validation.constraints.Size;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -359,4 +361,63 @@ public interface DeviceManagementAdminService {
required = true) required = true)
List<String> deviceIdentifiers); List<String> deviceIdentifiers);
@POST
@Path("/{deviceId}/{featureCode}")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Trigger the given corrective action",
notes = "When violation happens it is possible to trigger a corrective action.",
tags = "Device Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:android:enroll")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully triggered the action."),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 404,
message = "Not Found. \n The specified resource does not exist.",
response = ErrorResponse.class),
@ApiResponse(
code = 415,
message = "Unsupported media type. \n The format of the requested entity was not " +
"supported.\n "
+ "supported format."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n " +
"Server error occurred while triggering the corrective action.",
response = ErrorResponse.class)
})
Response triggerCorrectiveActions(
@ApiParam(
name = "deviceId",
value = "Device Identifier.",
required = true)
@PathParam("deviceId")
String deviceId,
@ApiParam(
name = "featureCode",
value = "Policy Feature Code.",
required = true)
@PathParam("featureCode")
String featureCode,
@ApiParam(
name = "actions",
value = "The list of actions to trigger when violation happens.",
required = true)
List<String> actions
);
} }

@ -36,25 +36,21 @@
package org.wso2.carbon.device.mgt.jaxrs.service.impl; package org.wso2.carbon.device.mgt.jaxrs.service.impl;
import java.util.LinkedList;
import java.util.Queue;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.OperationLogFilters;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.DeviceFilters; import org.wso2.carbon.device.mgt.common.DeviceFilters;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.MonitoringOperation;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.app.mgt.Application; import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException; import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
@ -62,14 +58,13 @@ import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorization
import org.wso2.carbon.device.mgt.common.device.details.DeviceData; import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshotWrapper;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.InvalidConfigurationException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidConfigurationException;
import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException; import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import org.wso2.carbon.device.mgt.common.exceptions.UnAuthorizedException;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
@ -91,15 +86,16 @@ import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation;
import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService; import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService;
import org.wso2.carbon.device.mgt.core.search.mgt.SearchMgtException; import org.wso2.carbon.device.mgt.core.search.mgt.SearchMgtException;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceCompliance; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceCompliance;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest;
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList; import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean;
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService; import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
@ -111,7 +107,6 @@ import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerSer
import org.wso2.carbon.policy.mgt.common.PolicyManagementException; import org.wso2.carbon.policy.mgt.common.PolicyManagementException;
import org.wso2.carbon.policy.mgt.core.PolicyManagerService; import org.wso2.carbon.policy.mgt.core.PolicyManagerService;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.validation.Valid; import javax.validation.Valid;
@ -128,9 +123,9 @@ import javax.ws.rs.DefaultValue;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.ArrayList;
@Path("/devices") @Path("/devices")
public class DeviceManagementServiceImpl implements DeviceManagementService { public class DeviceManagementServiceImpl implements DeviceManagementService {
@ -218,29 +213,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
if (groupId != 0) { if (groupId != 0) {
try { try {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); boolean isPermitted = DeviceMgtAPIUtils.checkPermission(groupId, authorizedUser);
UserStoreManager userStoreManager = DeviceMgtAPIUtils.getRealmService()
.getTenantUserRealm(tenantId).getUserStoreManager();
String[] userRoles = userStoreManager.getRoleListOfUser(authorizedUser);
boolean isPermitted = false;
if (deviceAccessAuthorizationService.isDeviceAdminUser()) {
isPermitted = true;
} else {
List<String> roles = DeviceMgtAPIUtils.getGroupManagementProviderService().getRoles(groupId);
for (String userRole : userRoles) {
if (roles.contains(userRole)) {
isPermitted = true;
break;
}
}
if (!isPermitted) {
DeviceGroup deviceGroup = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroup(groupId, false);
if (deviceGroup != null && authorizedUser.equals(deviceGroup.getOwner())) {
isPermitted = true;
}
}
}
if (isPermitted) { if (isPermitted) {
request.setGroupId(groupId); request.setGroupId(groupId);
} else { } else {
@ -383,6 +356,103 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
} }
} }
/**
* Validate group Id and group Id greater than 0 and exist.
*
* @param groupId Group ID of the group
* @param from time to start getting DeviceLocationHistorySnapshotWrapper in milliseconds
* @param to time to end getting DeviceLocationHistorySnapshotWrapper in milliseconds
*/
private static void validateGroupId(int groupId, long from, long to) throws GroupManagementException, BadRequestException {
if (from == 0 || to == 0) {
String msg = "Invalid values for from/to";
log.error(msg);
throw new BadRequestException(msg);
}
if (groupId <= 0) {
String msg = "Invalid group ID '" + groupId + "'";
log.error(msg);
throw new BadRequestException(msg);
}
GroupManagementProviderService service = DeviceMgtAPIUtils.getGroupManagementProviderService();
if (service.getGroup(groupId, false) == null) {
String msg = "Invalid group ID '" + groupId + "'";
log.error(msg);
throw new BadRequestException(msg);
}
}
@GET
@Override
@Path("/{groupId}/location-history")
public Response getDevicesGroupLocationInfo(@PathParam("groupId") int groupId,
@QueryParam("from") long from,
@QueryParam("to") long to,
@QueryParam("type") String type,
@DefaultValue("0") @QueryParam("offset") int offset,
@DefaultValue("100") @QueryParam("limit") int limit){
try {
RequestValidationUtil.validatePaginationParameters(offset, limit);
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
PaginationRequest request = new PaginationRequest(offset, limit);
DeviceList devices = new DeviceList();
// this is the user who initiates the request
String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername();
try {
validateGroupId(groupId, from, to);
boolean isPermitted = DeviceMgtAPIUtils.checkPermission(groupId, authorizedUser);
if (isPermitted) {
request.setGroupId(groupId);
} else {
String msg = "Current user '" + authorizedUser
+ "' doesn't have enough privileges to list devices of group '"
+ groupId + "'";
log.error(msg);
return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
}
} catch (GroupManagementException e) {
String msg = "Error occurred while getting the data using '" + groupId + "'";
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (UserStoreException e){
String msg = "Error occurred while retrieving role list of user '" + authorizedUser + "'";
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
PaginationResult result = dms.getAllDevices(request, false);
if(!result.getData().isEmpty()){
devices.setList((List<Device>) result.getData());
for (Device device : devices.getList()) {
DeviceLocationHistorySnapshotWrapper snapshotWrapper = DeviceMgtAPIUtils.getDeviceHistorySnapshots(
device.getType(), device.getDeviceIdentifier(), authorizedUser, from, to, type,
dms);
device.setHistorySnapshot(snapshotWrapper);
}
}
return Response.status(Response.Status.OK).entity(devices).build();
} catch (BadRequestException e) {
String msg = "Invalid type, use either 'path' or 'full'";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (UnAuthorizedException e) {
String msg = "Current user doesn't have enough privileges to list devices of group '" + groupId + "'";
log.error(msg, e);
return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while fetching the device information.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (DeviceAccessAuthorizationException e) {
String msg = "Error occurred while checking device access authorization";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@DELETE @DELETE
@Override @Override
@Path("/type/{deviceType}/id/{deviceId}") @Path("/type/{deviceType}/id/{deviceId}")
@ -504,97 +574,43 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
return Response.status(Response.Status.OK).entity(device).build(); return Response.status(Response.Status.OK).entity(device).build();
} }
@Path("/{deviceType}/{deviceId}/location-history")
@GET @GET
public Response getDeviceLocationInfo(@PathParam("deviceType") String deviceType, @Path("/{deviceType}/{deviceId}/location-history")
@PathParam("deviceId") String deviceId, public Response getDeviceLocationInfo(
@QueryParam("from") long from, @QueryParam("to") long to) { @PathParam("deviceType") String deviceType,
@PathParam("deviceId") String deviceId,
String errorMessage; @QueryParam("from") long from,
DeviceLocationHistory deviceLocationHistory = new DeviceLocationHistory(); @QueryParam("to") long to,
@QueryParam("type") String type) {
try { try {
RequestValidationUtil.validateDeviceIdentifier(deviceType, deviceId);
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
DeviceMgtAPIUtils.getDeviceAccessAuthorizationService();
String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername(); String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername();
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); DeviceLocationHistorySnapshotWrapper snapshotWrapper = DeviceMgtAPIUtils.getDeviceHistorySnapshots(
deviceIdentifier.setId(deviceId); deviceType, deviceId, authorizedUser, from, to, type,
deviceIdentifier.setType(deviceType); dms);
return Response.status(Response.Status.OK).entity(snapshotWrapper).build();
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser)) { } catch (BadRequestException e) {
String msg = "User '" + authorizedUser + "' is not authorized to retrieve the given device id '" + String msg = "Invalid type, use either 'path' or 'full'";
deviceId + "'"; log.error(msg, e);
log.error(msg); return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
return Response.status(Response.Status.UNAUTHORIZED).entity( } catch (UnAuthorizedException e) {
new ErrorResponse.ErrorResponseBuilder().setCode(401l).setMessage(msg).build()).build(); String msg = "Current user doesn't have enough privileges to retrieve the given device id '"
} + deviceId + "'";
if (from == 0 || to == 0) { log.error(msg, e);
errorMessage = "Invalid values for from/to"; return Response.status(Response.Status.FORBIDDEN).entity(msg).build();
log.error(errorMessage);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage)).build();
}
List<List<DeviceLocationHistorySnapshot>> locationHistorySnapshotList = new ArrayList<>();
// Get the location history snapshots for the given period
List<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshots = dms.getDeviceLocationInfo(deviceIdentifier, from, to);
OperationMonitoringTaskConfig operationMonitoringTaskConfig = dms.getDeviceMonitoringConfig(deviceType);
int taskFrequency = operationMonitoringTaskConfig.getFrequency();
int operationRecurrentTimes = 0;
List<MonitoringOperation> monitoringOperations = operationMonitoringTaskConfig.getMonitoringOperation();
for (MonitoringOperation monitoringOperation :
monitoringOperations) {
if (monitoringOperation.getTaskName().equals("DEVICE_LOCATION")) {
operationRecurrentTimes = monitoringOperation.getRecurrentTimes();
break;
}
}
// Device Location operation frequency in milliseconds. Adding 100000 ms as an error
long operationFrequency = taskFrequency * operationRecurrentTimes + 100000;
Queue<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshotsQueue = new LinkedList<>(deviceLocationHistorySnapshots);
while (deviceLocationHistorySnapshotsQueue.size() > 0) {
List<DeviceLocationHistorySnapshot> snapshots = new ArrayList<>();
// Make a copy of remaining snapshots
List<DeviceLocationHistorySnapshot> cachedSnapshots = new ArrayList<>(deviceLocationHistorySnapshotsQueue);
for (int i = 0; i < cachedSnapshots.size(); i++) {
DeviceLocationHistorySnapshot currentSnapshot = deviceLocationHistorySnapshotsQueue.poll();
snapshots.add(currentSnapshot);
if (deviceLocationHistorySnapshotsQueue.size() > 0) {
DeviceLocationHistorySnapshot nextSnapshot = deviceLocationHistorySnapshotsQueue.peek();
if (nextSnapshot.getUpdatedTime().getTime() - currentSnapshot.getUpdatedTime().getTime() > operationFrequency) {
break;
}
}
}
locationHistorySnapshotList.add(snapshots);
}
deviceLocationHistory.setLocationHistorySnapshots(locationHistorySnapshotList);
} catch (DeviceManagementException e) { } catch (DeviceManagementException e) {
errorMessage = "Error occurred while fetching the device information."; String msg = "Error occurred while fetching the device information.";
log.error(errorMessage, e); log.error(msg, e);
return Response.serverError().entity( return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build()).build(); } catch (InputValidationException e) {
String msg = "Invalid device Id or device type";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (DeviceAccessAuthorizationException e) { } catch (DeviceAccessAuthorizationException e) {
errorMessage = "Error occurred while checking the device authorization."; String msg = "Error occurred while checking device access authorization";
log.error(errorMessage, e); log.error(msg, e);
return Response.serverError().entity( return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build()).build();
} catch (InputValidationException e){
errorMessage = "Invalid device Id or device type";
log.error(errorMessage, e);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage)).build();
} }
return Response.status(Response.Status.OK).entity(deviceLocationHistory).build();
} }
@GET @GET
@ -871,21 +887,30 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
@QueryParam("offset") int offset, @QueryParam("offset") int offset,
@QueryParam("limit") int limit, @QueryParam("limit") int limit,
@QueryParam("owner") String owner, @QueryParam("owner") String owner,
@QueryParam("ownership") String ownership) { @QueryParam("ownership") String ownership,
@QueryParam("createdFrom") Long createdFrom,
@QueryParam("createdTo") Long createdTo,
@QueryParam("updatedFrom") Long updatedFrom,
@QueryParam("updatedTo") Long updatedTo,
@QueryParam("operationCode") List<String> operationCode,
@QueryParam("operationStatus") List<String> status) {
OperationList operationsList = new OperationList(); OperationList operationsList = new OperationList();
RequestValidationUtil requestValidationUtil = new RequestValidationUtil();
RequestValidationUtil.validateOwnerParameter(owner); RequestValidationUtil.validateOwnerParameter(owner);
RequestValidationUtil.validatePaginationParameters(offset, limit); RequestValidationUtil.validatePaginationParameters(offset, limit);
PaginationRequest request = new PaginationRequest(offset, limit); PaginationRequest request = new PaginationRequest(offset, limit);
request.setOwner(owner); request.setOwner(owner);
PaginationResult result;
DeviceManagementProviderService dms;
try { try {
//validating the operation log filters
OperationLogFilters olf = requestValidationUtil.validateOperationLogFilters(operationCode, createdFrom,
createdTo, updatedFrom, updatedTo, status, type);
request.setOperationLogFilters(olf);
RequestValidationUtil.validateDeviceIdentifier(type, id); RequestValidationUtil.validateDeviceIdentifier(type, id);
dms = DeviceMgtAPIUtils.getDeviceManagementService(); DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
if (!StringUtils.isBlank(ownership)) { if (!StringUtils.isBlank(ownership)) {
request.setOwnership(ownership); request.setOwnership(ownership);
} }
result = dms.getOperations(new DeviceIdentifier(id, type), request); PaginationResult result = dms.getOperations(new DeviceIdentifier(id, type), request);
operationsList.setList((List<? extends Operation>) result.getData()); operationsList.setList((List<? extends Operation>) result.getData());
operationsList.setCount(result.getRecordsTotal()); operationsList.setCount(result.getRecordsTotal());
return Response.status(Response.Status.OK).entity(operationsList).build(); return Response.status(Response.Status.OK).entity(operationsList).build();
@ -895,6 +920,20 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
log.error(msg, e); log.error(msg, e);
return Response.serverError().entity( return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (InputValidationException e) {
String msg = "Error occurred while fetching the operations for the '" + type + "' device, which " +
"carries the id '" + id + "'";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while retrieving the list of [" + type + "] features with params " +
"{featureType: operation, hidden: true}";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (DeviceTypeNotFoundException e) {
String msg = "No device type found with name '" + type + "'";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} }
} }

@ -18,8 +18,13 @@
package org.wso2.carbon.device.mgt.jaxrs.service.impl; package org.wso2.carbon.device.mgt.jaxrs.service.impl;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.gson.Gson;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus;
import org.wso2.carbon.analytics.api.AnalyticsDataAPI; import org.wso2.carbon.analytics.api.AnalyticsDataAPI;
import org.wso2.carbon.analytics.api.AnalyticsDataAPIUtil; import org.wso2.carbon.analytics.api.AnalyticsDataAPIUtil;
import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse; import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse;
@ -31,10 +36,21 @@ import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException
import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; 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.DeviceManagementConstants.GeoServices;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException; import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.common.geo.service.*; import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.event.config.EventConfigurationException;
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.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.GeofenceData;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants; 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.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
@ -42,15 +58,29 @@ import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.GeoHashLength
import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.ZoomGeoHashLengthStrategy; import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.ZoomGeoHashLengthStrategy;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.EventAction;
import org.wso2.carbon.device.mgt.jaxrs.beans.GeofenceWrapper;
import org.wso2.carbon.device.mgt.jaxrs.service.api.GeoLocationBasedService; import org.wso2.carbon.device.mgt.jaxrs.service.api.GeoLocationBasedService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtUtil;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.ws.rs.*; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -577,4 +607,271 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService {
eventBean.setValues(record.getValues()); eventBean.setValues(record.getValues());
return eventBean; return eventBean;
} }
@Path("/geo-fence")
@POST
@Consumes("application/json")
@Produces("application/json")
public Response createGeofence(GeofenceWrapper geofenceWrapper) {
RequestValidationUtil.validateGeofenceData(geofenceWrapper);
RequestValidationUtil.validateEventConfigurationData(geofenceWrapper.getEventConfig());
try {
GeofenceData geofenceData = mapRequestGeofenceData(geofenceWrapper);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
if (!geoService.createGeofence(geofenceData)) {
String msg = "Failed to create geofence";
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
return Response.status(Response.Status.CREATED).entity("Geo Fence record created successfully").build();
} catch (GeoLocationBasedServiceException e) {
String msg = "Failed to create geofence";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (EventConfigurationException e) {
String msg = "Failed to create event configuration for Geo Fence";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
/**
* Extract request event data from the payload and attach it to the DTO
* @param eventConfig request event payload
* @return generated event beans list according to the payload data
*/
private List<EventConfig> mapRequestEvent(List<org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig> eventConfig) {
List<EventConfig> savingEventList = new ArrayList<>();
for (org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig event : eventConfig) {
EventConfig savingConfig = new EventConfig();
if (event.getId() > 0) {
savingConfig.setEventId(event.getId());
} else {
savingConfig.setEventId(-1);
}
savingConfig.setEventLogic(event.getEventLogic());
String eventJson = new Gson().toJson(event.getActions());
savingConfig.setActions(eventJson);
savingEventList.add(savingConfig);
}
return savingEventList;
}
@Path("/geo-fence/{fenceId}")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeofence(@PathParam("fenceId") int fenceId,
@QueryParam("requireEventData") boolean requireEventData) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
GeofenceData geofenceData = geoService.getGeoFences(fenceId);
if (geofenceData == null) {
String msg = "No valid Geofence found for ID " + fenceId;
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
if (requireEventData) {
List<EventConfig> eventsOfGeoFence = geoService.getEventsOfGeoFence(geofenceData.getId());
geofenceData.setEventConfig(eventsOfGeoFence);
}
return Response.status(Response.Status.OK).entity(getMappedResponseBean(geofenceData)).build();
} catch (GeoLocationBasedServiceException e) {
String msg = "Server error occurred while retrieving Geofence for Id " + fenceId;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
/**
* Wrap geofence data retrieved from DB into Response Bean
* @param geofenceData retrieved data fromDB
* @return Response bean with geofence data
*/
private GeofenceWrapper getMappedResponseBean(GeofenceData geofenceData) {
GeofenceWrapper geofenceWrapper = new GeofenceWrapper();
geofenceWrapper.setId(geofenceData.getId());
geofenceWrapper.setFenceName(geofenceData.getFenceName());
geofenceWrapper.setDescription(geofenceData.getDescription());
geofenceWrapper.setLatitude(geofenceData.getLatitude());
geofenceWrapper.setLongitude(geofenceData.getLongitude());
geofenceWrapper.setRadius(geofenceData.getRadius());
geofenceWrapper.setGeoJson(geofenceData.getGeoJson());
geofenceWrapper.setFenceShape(geofenceData.getFenceShape());
if (geofenceData.getGroupIds() != null && !geofenceData.getGroupIds().isEmpty()) {
geofenceWrapper.setGroupIds(geofenceData.getGroupIds());
}
if (geofenceData.getGroupData() != null && !geofenceData.getGroupData().isEmpty()) {
geofenceWrapper.setGroupNames(geofenceData.getGroupData());
}
if (geofenceData.getEventConfig() != null) {
geofenceWrapper.setEventConfig(getEventConfigBean(geofenceData.getEventConfig()));
}
return geofenceWrapper;
}
/**
* Get event list to send with the response
* @param eventConfig event list retrieved
* @return list of response event beans
*/
private List<org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig> getEventConfigBean(List<EventConfig> eventConfig) {
List<org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig> eventList = new ArrayList<>();
org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig eventData;
for (EventConfig event : eventConfig) {
eventData = new org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig();
eventData.setId(event.getEventId());
eventData.setEventLogic(event.getEventLogic());
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
try {
List<EventAction> eventActions = mapper.readValue(event.getActions(), mapper.getTypeFactory().
constructCollectionType(List.class, EventAction.class));
eventData.setActions(eventActions);
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.warn("Error occurred while parsing event actions of the event with ID " + event.getEventId());
}
continue;
}
eventList.add(eventData);
}
return eventList;
}
@Path("/geo-fence")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getGeofence(@QueryParam("offset") int offset,
@QueryParam("limit") int limit,
@QueryParam("name") String name,
@QueryParam("requireEventData") boolean requireEventData) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
if (offset >= 0 && limit != 0) {
PaginationRequest request = new PaginationRequest(offset, limit);
if (name != null && !name.isEmpty()) {
request.setProperty(DeviceManagementConstants.GeoServices.FENCE_NAME, name);
}
List<GeofenceData> geoFences = geoService.getGeoFences(request);
if (!geoFences.isEmpty() && requireEventData) {
geoFences = geoService.attachEventObjects(geoFences);
}
return buildResponse(geoFences);
}
if (name != null && !name.isEmpty()) {
List<GeofenceData> geoFences = geoService.getGeoFences(name);
if (requireEventData) {
geoFences = geoService.attachEventObjects(geoFences);
}
return buildResponse(geoFences);
}
return buildResponse(geoService.getGeoFences());
} catch (GeoLocationBasedServiceException e) {
String msg = "Failed to retrieve geofence data";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
/**
* Build the response payload from the data retrieved from the database
* @param fencesList retrieved geofence data to send in response
* @return HttpResponse object
*/
private Response buildResponse(List<GeofenceData> fencesList) {
List<GeofenceWrapper> geofenceList = new ArrayList<>();
for (GeofenceData geofenceData : fencesList) {
geofenceList.add(getMappedResponseBean(geofenceData));
}
PaginationResult paginationResult = new PaginationResult();
paginationResult.setData(geofenceList);
paginationResult.setRecordsTotal(geofenceList.size());
return Response.status(Response.Status.OK).entity(paginationResult).build();
}
@DELETE
@Override
@Path("/geo-fence/{fenceId}")
public Response deleteGeofence(@PathParam("fenceId") int fenceId) {
try {
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
if (!geoService.deleteGeofenceData(fenceId)) {
String msg = "No valid Geofence found for ID " + fenceId;
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
return Response.status(Response.Status.OK).build();
} catch (GeoLocationBasedServiceException e) {
String msg = "Failed to delete geofence data";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@Path("/geo-fence/{fenceId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Response updateGeofence(GeofenceWrapper geofenceWrapper,
@PathParam("fenceId") int fenceId,
@QueryParam("eventIds") int[] eventIds) {
RequestValidationUtil.validateGeofenceData(geofenceWrapper);
RequestValidationUtil.validateEventConfigurationData(geofenceWrapper.getEventConfig());
try {
GeofenceData geofenceData = mapRequestGeofenceData(geofenceWrapper);
GeoLocationProviderService geoService = DeviceMgtAPIUtils.getGeoService();
if (!geoService.updateGeofence(geofenceData, fenceId)) {
String msg = "No valid Geofence found for ID " + fenceId;
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
List<Integer> eventsToRemove = new ArrayList<>();
for (int eventId : eventIds) {
eventsToRemove.add(eventId);
}
geoService.updateGeoEventConfigurations(geofenceData, eventsToRemove,
geofenceData.getGroupIds(), fenceId);
return Response.status(Response.Status.CREATED).entity("Geo Fence update successfully").build();
} catch (GeoLocationBasedServiceException e) {
String msg = "Failed to update geofence";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (EventConfigurationException e) {
String msg = "Failed to update geofence events";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
/**
* Parse geofence data from the request payload to the GeofenceData DTO
* @param geofenceWrapper request payload data
* @return GeofenceData object built from the request data
*/
private GeofenceData mapRequestGeofenceData(GeofenceWrapper geofenceWrapper) {
GeofenceData geofenceData = new GeofenceData();
geofenceData.setFenceName(geofenceWrapper.getFenceName());
geofenceData.setDescription(geofenceWrapper.getDescription());
geofenceData.setLatitude(geofenceWrapper.getLatitude());
geofenceData.setLongitude(geofenceWrapper.getLongitude());
geofenceData.setRadius(geofenceWrapper.getRadius());
geofenceData.setFenceShape(geofenceWrapper.getFenceShape());
geofenceData.setGeoJson(geofenceWrapper.getGeoJson());
if (geofenceWrapper.getGroupIds() == null || geofenceWrapper.getGroupIds().isEmpty()) {
String msg = "Group ID / IDs are mandatory, since cannot be null or empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST)
.setMessage(msg).build());
}
geofenceData.setGroupIds(geofenceWrapper.getGroupIds());
geofenceData.setEventConfig(mapRequestEvent(geofenceWrapper.getEventConfig()));
return geofenceData;
}
} }

@ -136,12 +136,19 @@ public class PolicyManagementServiceImpl implements PolicyManagementService {
} }
} }
/**
* GEt {@link Policy} from {@link PolicyWrapper}
*
* @param policyWrapper {@link PolicyWrapper}
* @return {@link Policy}
* @throws DeviceManagementException if error occurred while creating {@link Policy} object from
* {@link PolicyWrapper}
*/
private Policy getPolicyFromWrapper(@Valid PolicyWrapper policyWrapper) throws DeviceManagementException { private Policy getPolicyFromWrapper(@Valid PolicyWrapper policyWrapper) throws DeviceManagementException {
Policy policy = new Policy(); Policy policy = new Policy();
policy.setPolicyName(policyWrapper.getPolicyName()); policy.setPolicyName(policyWrapper.getPolicyName());
policy.setDescription(policyWrapper.getDescription()); policy.setDescription(policyWrapper.getDescription());
policy.setProfile(DeviceMgtUtil.convertProfile(policyWrapper.getProfile())); policy.setProfile(DeviceMgtUtil.convertProfile(policyWrapper.getProfile()));
policy.setCorrectiveActions(policyWrapper.getCorrectiveActions());
policy.setOwnershipType(policyWrapper.getOwnershipType()); policy.setOwnershipType(policyWrapper.getOwnershipType());
policy.setActive(policyWrapper.isActive()); policy.setActive(policyWrapper.isActive());
policy.setRoles(policyWrapper.getRoles()); policy.setRoles(policyWrapper.getRoles());
@ -149,8 +156,10 @@ public class PolicyManagementServiceImpl implements PolicyManagementService {
policy.setCompliance(policyWrapper.getCompliance()); policy.setCompliance(policyWrapper.getCompliance());
policy.setDeviceGroups(policyWrapper.getDeviceGroups()); policy.setDeviceGroups(policyWrapper.getDeviceGroups());
policy.setPolicyType(policyWrapper.getPolicyType()); policy.setPolicyType(policyWrapper.getPolicyType());
policy.setPolicyPayloadVersion(policyWrapper.getPayloadVersion());
policy.setCorrectiveActions(policyWrapper.getCorrectiveActions());
//TODO iterates the device identifiers to create the object. need to implement a proper DAO layer here. //TODO iterates the device identifiers to create the object. need to implement a proper DAO layer here.
List<Device> devices = new ArrayList<Device>(); List<Device> devices = new ArrayList<>();
List<DeviceIdentifier> deviceIdentifiers = policyWrapper.getDeviceIdentifiers(); List<DeviceIdentifier> deviceIdentifiers = policyWrapper.getDeviceIdentifiers();
if (deviceIdentifiers != null) { if (deviceIdentifiers != null) {
for (DeviceIdentifier id : deviceIdentifiers) { for (DeviceIdentifier id : deviceIdentifiers) {

@ -41,8 +41,15 @@ import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.MDMAppConstants;
import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.exceptions.UserNotFoundException; import org.wso2.carbon.device.mgt.common.exceptions.UserNotFoundException;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
@ -56,8 +63,10 @@ import javax.validation.constraints.Size;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -190,4 +199,38 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
} }
} }
@POST
@Path("/{deviceId}/{featureCode}")
@Override
public Response triggerCorrectiveActions(
@PathParam("deviceId") String deviceIdentifier,
@PathParam("featureCode") String featureCode,
List<String> actions){
DeviceManagementProviderService deviceManagementService = DeviceMgtAPIUtils.getDeviceManagementService();
PlatformConfigurationManagementService platformConfigurationManagementService = DeviceMgtAPIUtils
.getPlatformConfigurationManagementService();
try {
PlatformConfiguration config = platformConfigurationManagementService
.getConfiguration(MDMAppConstants.RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH);
List<ConfigurationEntry> configList = config.getConfiguration();
deviceManagementService.triggerCorrectiveActions(deviceIdentifier, featureCode, actions, configList);
} catch (ConfigurationManagementException e) {
String msg = "Error occurred while processing platform configuration.";
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (BadRequestException e) {
String msg = "Bad request, can't proceed. Hence verify the request and re-try";
log.error(msg);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while getting device data which has ID: " + deviceIdentifier;
log.error(msg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (DeviceNotFoundException e) {
String msg = "Couldn't find an device for device identifier: " + deviceIdentifier;
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
return Response.status(Response.Status.OK).entity("Triggered action successfully").build();
}
} }

@ -23,32 +23,43 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.OperationLogFilters;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata; import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.notification.mgt.Notification; import org.wso2.carbon.device.mgt.common.notification.mgt.Notification;
import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.EventConfig;
import org.wso2.carbon.device.mgt.jaxrs.beans.GeofenceWrapper;
import org.wso2.carbon.device.mgt.jaxrs.beans.OldPasswordResetWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.OldPasswordResetWrapper;
import org.wso2.carbon.device.mgt.jaxrs.beans.PolicyWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.PolicyWrapper;
import org.wso2.carbon.device.mgt.jaxrs.beans.ProfileFeature; import org.wso2.carbon.device.mgt.jaxrs.beans.ProfileFeature;
import org.wso2.carbon.device.mgt.jaxrs.beans.RoleInfo; import org.wso2.carbon.device.mgt.jaxrs.beans.RoleInfo;
import org.wso2.carbon.device.mgt.jaxrs.beans.Scope; import org.wso2.carbon.device.mgt.jaxrs.beans.Scope;
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceTypeManagementService;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.policy.mgt.common.PolicyPayloadValidator; import org.wso2.carbon.policy.mgt.common.PolicyPayloadValidator;
import javax.ws.rs.core.Response;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class RequestValidationUtil { public class RequestValidationUtil {
private static final Log log = LogFactory.getLog(RequestValidationUtil.class); private static final Log log = LogFactory.getLog(RequestValidationUtil.class);
/** /**
* Checks if multiple criteria are specified in a conditional request. * Checks if multiple criteria are specified in a conditional request.
* *
@ -476,6 +487,155 @@ public class RequestValidationUtil {
} }
} }
/**
* Checks if operation log filters are valid
*
* @param type Device type upon which the selection is done
* @param createdFrom Since when created date and time upon to filter operation logs
* @param createdTo Till when created date and time upon to filter operation logs
* @param updatedFrom Since when received date and time upon to filter operation logs
* @param updatedTo Till when received date and time upon to filter operation logs
* @param status List of operation status codes upon to filter operation logs
*/
public OperationLogFilters validateOperationLogFilters(List<String> operationCode,
Long createdFrom, Long createdTo, Long updatedFrom,
Long updatedTo, List<String> status, String type)
throws DeviceTypeNotFoundException, DeviceManagementException {
OperationLogFilters operationLogFilters = new OperationLogFilters();
Calendar date = Calendar.getInstance();
long timeMilli = date.getTimeInMillis();
if (updatedFrom != null || updatedTo != null) {
validateDates(updatedFrom, updatedTo);
//if user only sends the fromDate toDate sets as current date
if (updatedFrom != null && updatedTo == null) {
timeMilli = timeMilli / 1000;
operationLogFilters.setUpdatedDayTo(timeMilli);
operationLogFilters.setUpdatedDayFrom(updatedFrom);
} else {
operationLogFilters.setUpdatedDayFrom(updatedFrom);
operationLogFilters.setUpdatedDayTo(updatedTo);
}
}
if (createdTo != null || createdFrom != null) {
validateDates(createdFrom, createdTo);
createdFrom = createdFrom * 1000;
//if user only sends the fromDate toDate sets as current date
if (createdFrom != null && createdTo == null) {
operationLogFilters.setCreatedDayFrom(createdFrom);
operationLogFilters.setCreatedDayTo(timeMilli);
} else {
createdTo = createdTo * 1000;
operationLogFilters.setCreatedDayFrom(createdFrom);
operationLogFilters.setCreatedDayTo(createdTo);
}
}
if (status != null && !status.isEmpty()) {
validateStatusFiltering(status);
operationLogFilters.setStatus(status);
}
if (operationCode != null && !operationCode.isEmpty()) {
validateOperationCodeFiltering(operationCode, type);
operationLogFilters.setOperationCode(operationCode);
}
return operationLogFilters;
}
/**
* Checks if date ranges requested by user are valid
*
* @param toDate Till when created/updated dates upon to validate dates
* @param fromDate Since when created/updated dates upon to validate dates
*/
public static void validateDates(Long fromDate, Long toDate) {
Calendar date = Calendar.getInstance();
long timeMilli = date.getTimeInMillis();
timeMilli = timeMilli / 1000;
//if user only sends toDate
if (fromDate == null && toDate != null) {
String msg = "Request parameter must sent with the from date parameter";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
//if user sends future dates
if (fromDate != null && toDate != null) {
if (timeMilli < fromDate || timeMilli < toDate) {
String msg = "Bad Request cannot apply future dates";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
}
//if user send future dates - only when from date sends
if (fromDate != null && toDate == null) {
if (fromDate > timeMilli) {
String msg = "Bad Request cannot apply future dates";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
}
}
/**
* Checks if user requested operation status codes are valid.
*
* @param status status codes upon to filter operation logs using status
*/
public static void validateStatusFiltering(List<String> status) {
for (int i = 0; i < status.size(); i++) {
if (Constants.OperationStatus.COMPLETED.toUpperCase().equals(status.get(i))
|| Constants.OperationStatus.ERROR.toUpperCase().equals(status.get(i))
|| Constants.OperationStatus.NOTNOW.toUpperCase().equals(status.get(i))
|| Constants.OperationStatus.REPEATED.toUpperCase().equals(status.get(i))
|| Constants.OperationStatus.PENDING.toUpperCase().equals(status.get(i))
|| Constants.OperationStatus.IN_PROGRESS.toUpperCase().equals(status.get(i))) {
} else {
String msg = "Invalid status type: " + status + ". \nValid status types are COMPLETED | ERROR | " +
"IN_PROGRESS | NOTNOW | PENDING | REPEATED";
log.error(msg);
throw new InputValidationException(new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST)
.setMessage(msg).build());
}
}
}
/**
* Checks if user requested operation codes are valid.
*
* @param operationCode operation codes upon to filter operation logs using operation codes
* @param type status codes upon to filter operation logs using status
*/
public static void validateOperationCodeFiltering(List<String> operationCode, String type)
throws DeviceTypeNotFoundException, DeviceManagementException {
int count = 0;
List<Feature> features;
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
FeatureManager fm = dms.getFeatureManager(type);
features = fm.getFeatures("operation");
for (String oc : operationCode) {
for (Feature f : features) {
if (f.getCode().equals(oc)) {
count++;
break;
}
}
}
if (!(count == operationCode.size())) {
String msg = "Requested Operation code invalid";
log.error(msg);
throw new InputValidationException(new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST)
.setMessage(msg).build());
}
}
/** /**
* Validate if the metaData and metaKey values are non empty & in proper format. * Validate if the metaData and metaKey values are non empty & in proper format.
* *
@ -524,4 +684,73 @@ public class RequestValidationUtil {
&& StringUtils.isEmpty(emailAddress); && StringUtils.isEmpty(emailAddress);
} }
/**
* Check the request payload attributes are correct for create a geofence
* @param geofenceWrapper request payload data
*/
public static void validateGeofenceData(GeofenceWrapper geofenceWrapper) {
boolean isGeoJsonExists = false;
if (geofenceWrapper.getFenceName() == null || geofenceWrapper.getFenceName().trim().isEmpty()) {
String msg = "Geofence name should not be null or empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (geofenceWrapper.getGeoJson() != null && !geofenceWrapper.getGeoJson().trim().isEmpty()) {
isGeoJsonExists = true;
}
if ((geofenceWrapper.getLatitude() < -90 || geofenceWrapper.getLatitude() > 90) && !isGeoJsonExists) {
String msg = "Latitude should be a value between -90 and 90";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if ((geofenceWrapper.getLongitude() < -180 || geofenceWrapper.getLongitude() > 180) && !isGeoJsonExists) {
String msg = "Longitude should be a value between -180 and 180";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (geofenceWrapper.getRadius() < 1 && !isGeoJsonExists) {
String msg = "Minimum radius of the fence should be 1m";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (geofenceWrapper.getFenceShape().trim().isEmpty()) {
String msg = "Fence shape should not be empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
}
/**
* Check the request payload attributes are correct for create an event record
* @param eventConfig request payload data
*/
public static void validateEventConfigurationData(List<EventConfig> eventConfig) {
if (eventConfig == null ||eventConfig.isEmpty()) {
String msg = "Event configuration is mandatory, since should not be null or empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
for (EventConfig config : eventConfig) {
if (config.getActions() == null || config.getActions().isEmpty()) {
String msg = "Event actions are mandatory, since should not be null or empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (config.getEventLogic() == null || config.getEventLogic().trim().isEmpty()) {
String msg = "Event logic is mandatory, since should not be null or empty";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
}
}
} }

@ -53,16 +53,26 @@ import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.Utils; import org.wso2.carbon.core.util.Utils;
import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
import org.wso2.carbon.device.mgt.common.MonitoringOperation;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshotWrapper;
import org.wso2.carbon.device.mgt.common.event.config.EventConfigurationProviderService;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException; import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService; import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService;
import org.wso2.carbon.device.mgt.common.exceptions.UnAuthorizedException;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService; import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService; import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
@ -82,6 +92,7 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean;
import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.EventAttributeList; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.EventAttributeList;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.event.processor.stub.EventProcessorAdminServiceStub; import org.wso2.carbon.event.processor.stub.EventProcessorAdminServiceStub;
import org.wso2.carbon.event.publisher.stub.EventPublisherAdminServiceStub; import org.wso2.carbon.event.publisher.stub.EventPublisherAdminServiceStub;
import org.wso2.carbon.event.receiver.stub.EventReceiverAdminServiceStub; import org.wso2.carbon.event.receiver.stub.EventReceiverAdminServiceStub;
@ -123,7 +134,9 @@ import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException; import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Queue;
/** /**
* MDMAPIUtils class provides utility function used by CDM REST-API classes. * MDMAPIUtils class provides utility function used by CDM REST-API classes.
@ -940,4 +953,149 @@ public class DeviceMgtAPIUtils {
claimPropertyDTO.setPropertyValue(propertyValue); claimPropertyDTO.setPropertyValue(propertyValue);
return claimPropertyDTO; return claimPropertyDTO;
} }
/**
* Getting Device History Snapshots for given Device Type and Identifier.
*
* @param deviceType Device type of the device
* @param identifier Device identifier of the device
* @param authorizedUser user who initiates the request
* @param from time to start getting DeviceLocationHistorySnapshotWrapper in milliseconds
* @param to time to end getting DeviceLocationHistorySnapshotWrapper in milliseconds
* @param type output type should be for DeviceLocationHistorySnapshotWrapper
* @param dms DeviceManagementService instance
*
* @return DeviceLocationHistorySnapshotWrapper instance
* @throws DeviceManagementException if device information cannot be fetched
* @throws DeviceAccessAuthorizationException if device authorization get failed
*/
public static DeviceLocationHistorySnapshotWrapper getDeviceHistorySnapshots(String deviceType,
String identifier,
String authorizedUser,
long from,
long to,
String type,
DeviceManagementProviderService dms)
throws DeviceManagementException, DeviceAccessAuthorizationException {
RequestValidationUtil.validateDeviceIdentifier(deviceType, identifier);
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(identifier, deviceType);
if (!getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier, authorizedUser)) {
String msg = "User '" + authorizedUser + "' is not authorized to retrieve the given device id '" +
identifier + "'";
log.error(msg);
throw new UnAuthorizedException(msg);
}
// Get the location history snapshots for the given period
List<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshots = dms.getDeviceLocationInfo(deviceIdentifier, from, to);
OperationMonitoringTaskConfig operationMonitoringTaskConfig = dms.getDeviceMonitoringConfig(deviceType);
int taskFrequency = operationMonitoringTaskConfig.getFrequency();
int operationRecurrentTimes = 0;
List<MonitoringOperation> monitoringOperations = operationMonitoringTaskConfig.getMonitoringOperation();
for (MonitoringOperation monitoringOperation : monitoringOperations) {
if (monitoringOperation.getTaskName().equals("DEVICE_LOCATION")) {
operationRecurrentTimes = monitoringOperation.getRecurrentTimes();
break;
}
}
// Device Location operation frequency in milliseconds. Adding 100000 ms as an error
long operationFrequency = taskFrequency * operationRecurrentTimes + 100000;
Queue<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshotsQueue = new LinkedList<>(
deviceLocationHistorySnapshots);
List<List<DeviceLocationHistorySnapshot>> locationHistorySnapshotList = new ArrayList<>();
List<Object> pathsArray = new ArrayList<>();
DeviceLocationHistorySnapshotWrapper snapshotWrapper = new DeviceLocationHistorySnapshotWrapper();
while (!deviceLocationHistorySnapshotsQueue.isEmpty()) {
List<DeviceLocationHistorySnapshot> snapshots = new ArrayList<>();
// Make a copy of remaining snapshots
List<DeviceLocationHistorySnapshot> cachedSnapshots = new ArrayList<>(
deviceLocationHistorySnapshotsQueue);
List<Object> locationPoint = new ArrayList<>();
for (int i = 0; i < cachedSnapshots.size(); i++) {
DeviceLocationHistorySnapshot currentSnapshot = deviceLocationHistorySnapshotsQueue.poll();
snapshots.add(currentSnapshot);
if (currentSnapshot != null) {
locationPoint.add(currentSnapshot.getLatitude());
locationPoint.add(currentSnapshot.getLongitude());
locationPoint.add(currentSnapshot.getUpdatedTime());
pathsArray.add(new ArrayList<>(locationPoint));
locationPoint.clear();
}
if (!deviceLocationHistorySnapshotsQueue.isEmpty()) {
DeviceLocationHistorySnapshot nextSnapshot = deviceLocationHistorySnapshotsQueue.peek();
locationPoint.add(nextSnapshot.getLatitude());
locationPoint.add(nextSnapshot.getLongitude());
locationPoint.add(nextSnapshot.getUpdatedTime());
pathsArray.add(new ArrayList<>(locationPoint));
locationPoint.clear();
if (nextSnapshot.getUpdatedTime().getTime() - currentSnapshot.getUpdatedTime().getTime()
> operationFrequency) {
break;
}
}
}
locationHistorySnapshotList.add(snapshots);
}
DeviceLocationHistory deviceLocationHistory = new DeviceLocationHistory();
deviceLocationHistory.setLocationHistorySnapshots(locationHistorySnapshotList);
if (type != null) {
if (type.equals("path")) {
snapshotWrapper.setPathSnapshot(pathsArray);
} else if (type.equals("full")) {
snapshotWrapper.setFullSnapshot(deviceLocationHistory);
} else {
String msg = "Invalid type, use either 'path' or 'full'";
log.error(msg);
throw new BadRequestException(msg);
}
} else {
snapshotWrapper.setFullSnapshot(deviceLocationHistory);
}
return snapshotWrapper;
}
/**
* Check user who initiates the request has permission to list devices from given group Id.
*
* @param groupId Group ID of the group
* @param authorizedUser user who initiates the request
*
* @return boolean instance
* @throws UserStoreException if roles list of authorizedUser cannot be fetched
* @throws DeviceAccessAuthorizationException if device authorization get failed.
* @throws GroupManagementException if group or roles cannot be fetched using groupId
*/
public static boolean checkPermission(int groupId, String authorizedUser) throws UserStoreException, DeviceAccessAuthorizationException, GroupManagementException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
UserStoreManager userStoreManager = DeviceMgtAPIUtils.getRealmService()
.getTenantUserRealm(tenantId).getUserStoreManager();
String[] userRoles = userStoreManager.getRoleListOfUser(authorizedUser);
boolean isPermitted = false;
if (getDeviceAccessAuthorizationService().isDeviceAdminUser()) {
isPermitted = true;
} else {
List<String> roles = DeviceMgtAPIUtils.getGroupManagementProviderService().getRoles(groupId);
for (String userRole : userRoles) {
if (roles.contains(userRole)) {
isPermitted = true;
break;
}
}
if (!isPermitted) {
DeviceGroup deviceGroup = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroup(groupId, false);
if (deviceGroup != null && authorizedUser.equals(deviceGroup.getOwner())) {
isPermitted = true;
}
}
}
return isPermitted;
}
} }

@ -60,6 +60,7 @@ public class DeviceMgtUtil {
profileFeature.setDeviceType(mdmProfileFeature.getDeviceTypeId()); profileFeature.setDeviceType(mdmProfileFeature.getDeviceTypeId());
profileFeature.setFeatureCode(mdmProfileFeature.getFeatureCode()); profileFeature.setFeatureCode(mdmProfileFeature.getFeatureCode());
profileFeature.setId(mdmProfileFeature.getId()); profileFeature.setId(mdmProfileFeature.getId());
profileFeature.setCorrectiveActions(mdmProfileFeature.getCorrectiveActions());
return profileFeature; return profileFeature;
} }

@ -648,24 +648,28 @@ public class DeviceManagementServiceImplTest {
@Test(description = "Testing getting operation list of a device") @Test(description = "Testing getting operation list of a device")
public void testGetDeviceOperations() { public void testGetDeviceOperations() {
List<String> operationCodes = new ArrayList<>();
List<String> statusCodes = new ArrayList<>();
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService); .toReturn(this.deviceManagementProviderService);
Response response = this.deviceManagementService Response response = this.deviceManagementService
.getDeviceOperations(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), "", 10, 5, DEFAULT_USERNAME, .getDeviceOperations(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), "", 10, 5, DEFAULT_USERNAME,
DEFAULT_OWNERSHIP); DEFAULT_OWNERSHIP, null, null, null, null, operationCodes, statusCodes);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(), Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode(),
"Expects to return HTTP 200 when the operation is retrieved successfully."); "Expects to return HTTP 200 when the operation is retrieved successfully.");
} }
@Test(description = "Testing getting operation list of a device when unable to retrieve operations") @Test(description = "Testing getting operation list of a device when unable to retrieve operations")
public void testGetDeviceOperationsException() throws OperationManagementException { public void testGetDeviceOperationsException() throws OperationManagementException {
List<String> operationCodes = new ArrayList<>();
List<String> statusCodes = new ArrayList<>();
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService"))
.toReturn(this.deviceManagementProviderService); .toReturn(this.deviceManagementProviderService);
Mockito.when(this.deviceManagementProviderService.getOperations(Mockito.any(DeviceIdentifier.class), Mockito.when(this.deviceManagementProviderService.getOperations(Mockito.any(DeviceIdentifier.class),
Mockito.any(PaginationRequest.class))).thenThrow(new OperationManagementException()); Mockito.any(PaginationRequest.class))).thenThrow(new OperationManagementException());
Response response = this.deviceManagementService Response response = this.deviceManagementService
.getDeviceOperations(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), "", 10, 5, DEFAULT_USERNAME, .getDeviceOperations(TEST_DEVICE_TYPE, UUID.randomUUID().toString(), "", 10, 5, DEFAULT_USERNAME,
DEFAULT_OWNERSHIP); DEFAULT_OWNERSHIP, null, null, null, null, operationCodes, statusCodes);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
"Expects to return HTTP 500 when an exception occurred while retrieving operation list of the device"); "Expects to return HTTP 500 when an exception occurred while retrieving operation list of the device");
} }

@ -20,8 +20,10 @@ package org.wso2.carbon.device.mgt.common;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.wso2.carbon.device.mgt.common.app.mgt.Application; import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshotWrapper;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@ -70,6 +72,12 @@ public class Device implements Serializable {
required = false) required = false)
private List<Application> applications; private List<Application> applications;
@ApiModelProperty(
name = "historySnapshot",
value = "device history snapshots")
@JsonProperty(value = "historySnapshot")
private DeviceLocationHistorySnapshotWrapper historySnapshot;
public Device() { public Device() {
} }
@ -164,6 +172,14 @@ public class Device implements Serializable {
this.applications = applications; this.applications = applications;
} }
public DeviceLocationHistorySnapshotWrapper getHistorySnapshot() {
return historySnapshot;
}
public void setHistorySnapshot(DeviceLocationHistorySnapshotWrapper historySnapshot) {
this.historySnapshot = historySnapshot;
}
public static class Property { public static class Property {
private String name; private String name;

@ -58,6 +58,7 @@ public class DeviceIdentifier implements Serializable{
public void setType(String type) { public void setType(String type) {
this.type = type.trim(); this.type = type.trim();
} }
public String getId() { public String getId() {
return id; return id;
} }

@ -124,6 +124,7 @@ public final class DeviceManagementConstants {
public static final String DAS_HOST_NAME = "${iot.analytics.host}"; public static final String DAS_HOST_NAME = "${iot.analytics.host}";
public static final String DEFAULT_HTTP_PROTOCOL = "https"; public static final String DEFAULT_HTTP_PROTOCOL = "https";
public static final String DAS_URL = DEFAULT_HTTP_PROTOCOL + "://" + DAS_HOST_NAME + ":" + DAS_PORT; public static final String DAS_URL = DEFAULT_HTTP_PROTOCOL + "://" + DAS_HOST_NAME + ":" + DAS_PORT;
public static final String FENCE_NAME = "name";
} }
public static final class OTPProperties { public static final class OTPProperties {
@ -135,4 +136,10 @@ public final class DeviceManagementConstants {
public static final String TENANT_ADMIN_PASSWORD = "tenant-admin-password"; public static final String TENANT_ADMIN_PASSWORD = "tenant-admin-password";
} }
public static final class EventServices {
private EventServices() { throw new AssertionError(); }
public static final String GEOFENCE = "GEOFENCE";
}
} }

@ -30,7 +30,9 @@ public class EnrolmentInfo implements Serializable {
private static final long serialVersionUID = 1998101712L; private static final long serialVersionUID = 1998101712L;
public enum Status { public enum Status {
CREATED, ACTIVE, INACTIVE, UNREACHABLE, UNCLAIMED, SUSPENDED, BLOCKED, REMOVED, DISENROLLMENT_REQUESTED CREATED, ACTIVE, INACTIVE, UNREACHABLE, UNCLAIMED, SUSPENDED, BLOCKED, REMOVED, DISENROLLMENT_REQUESTED,
CONFIGURED, READY_TO_CONNECT, RETURN_PENDING, RETURNED, DEFECTIVE, WARRANTY_PENDING, WARRANTY_SENT,
WARRANTY_REPLACED
} }
public enum OwnerShip { public enum OwnerShip {

@ -19,7 +19,7 @@
package org.wso2.carbon.device.mgt.common; package org.wso2.carbon.device.mgt.common;
/** /**
* This class holds all the constants used for IOS and Android. * This class holds all the constants used for IOS, Android, Windows.
*/ */
public class MDMAppConstants { public class MDMAppConstants {
@ -49,6 +49,29 @@ public class MDMAppConstants {
public static final String OPCODE_UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION"; public static final String OPCODE_UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION";
} }
public class WindowsConstants {
private WindowsConstants() {
throw new AssertionError();
}
public static final String INSTALL_ENTERPRISE_APPLICATION = "INSTALL_ENTERPRISE_APPLICATION";
//App type constants related to window device type
public static final String MSI = "MSI";
public static final String APPX = "APPX";
//MSI Meta Key Constant
public static final String MSI_PRODUCT_ID = "Product_Id";
public static final String MSI_CONTENT_URI = "Content_Uri";
public static final String MSI_FILE_HASH = "File_Hash";
//APPX Meta Key Constant
public static final String APPX_PACKAGE_URI = "Package_Url";
public static final String APPX_DEPENDENCY_PACKAGE_URL = "Dependency_Package_Url";
public static final String APPX_CERTIFICATE_HASH = "Certificate_Hash";
public static final String APPX_ENCODED_CERT_CONTENT = "Encoded_Cert_Content";
public static final String APPX_PACKAGE_FAMILY_NAME = "Package_Family_Name";
}
public class RegistryConstants { public class RegistryConstants {
private RegistryConstants() { private RegistryConstants() {

@ -0,0 +1,72 @@
/*
* Copyright (c) 2020, 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;
import java.util.List;
/**
* This class carries information related to operation log filtering values which will be used in the UI to filter operations.
*/
public class OperationLogFilters {
private List<String> operationCode;
private Long createdDayFrom;
private Long createdDayTo ;
private Long updatedDayFrom;
private Long updatedDayTo ;
private List<String> status;
public OperationLogFilters() {
}
public OperationLogFilters(List<String> operationCode , Long createdDayFrom, Long createdDayTo,
Long updatedDayFrom, Long updatedDayTo, List<String> status) {
this.operationCode = operationCode;
this.createdDayFrom = createdDayFrom;
this.createdDayTo = createdDayTo;
this.updatedDayFrom = updatedDayFrom;
this.updatedDayTo = updatedDayTo;
this.status = status;
}
public List<String> getOperationCode() {
return operationCode;
}
public void setOperationCode(List<String> operationCode) {
this.operationCode = operationCode;
}
public List<String> getStatus() {
return status;
}
public void setStatus(List<String> status) {
this.status = status;
}
public Long getUpdatedDayFrom() {
return updatedDayFrom;
}
public void setUpdatedDayFrom(Long updatedDayFrom) {
this.updatedDayFrom = updatedDayFrom;
}
public Long getUpdatedDayTo() {
return updatedDayTo;
}
public void setUpdatedDayTo(Long updatedDayTo) {
this.updatedDayTo = updatedDayTo;
}
public Long getCreatedDayFrom() { return createdDayFrom; }
public void setCreatedDayFrom(Long createdDayFrom) { this.createdDayFrom = createdDayFrom; }
public Long getCreatedDayTo() { return createdDayTo; }
public void setCreatedDayTo(Long createdDayTo) { this.createdDayTo = createdDayTo; }
}

@ -42,12 +42,17 @@ public class PaginationRequest {
private String filter; private String filter;
private Map<String, Object> property = new HashMap<>(); private Map<String, Object> property = new HashMap<>();
private List<String> statusList = new ArrayList<>(); private List<String> statusList = new ArrayList<>();
private OperationLogFilters operationLogFilters = new OperationLogFilters();
public OperationLogFilters getOperationLogFilters() {
return operationLogFilters;
}
public void setOperationLogFilters(OperationLogFilters operationLogFilters) {
this.operationLogFilters = operationLogFilters;
}
public PaginationRequest(int start, int rowCount) { public PaginationRequest(int start, int rowCount) {
this.startIndex = start; this.startIndex = start;
this.rowCount = rowCount; this.rowCount = rowCount;
} }
public int getStartIndex() { public int getStartIndex() {
return startIndex; return startIndex;
} }

@ -62,6 +62,10 @@ public class App {
private String location; private String location;
@ApiModelProperty(name = "properties", value = "List of meta data.", required = true) @ApiModelProperty(name = "properties", value = "List of meta data.", required = true)
private Properties properties; private Properties properties;
@ApiModelProperty(name = "metaData",
value = "Meta data of the application release",
required = true)
private String metaData;
public MobileAppTypes getType() { public MobileAppTypes getType() {
return type; return type;
@ -142,4 +146,8 @@ public class App {
public void setProperties(Properties properties) { public void setProperties(Properties properties) {
this.properties = properties; this.properties = properties;
} }
public String getMetaData() { return metaData; }
public void setMetaData(String metaData) { this.metaData = metaData; }
} }

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.app.mgt.windows;
import com.google.gson.Gson;
import java.io.Serializable;
/**
* This class represents the Windows Enterprise App Types information.
*/
public class EnterpriseApplication implements Serializable {
private HostedAppxApplication hostedAppxApplication;
private HostedMSIApplication hostedMSIApplication;
public HostedAppxApplication getHostedAppxApplication() {
return hostedAppxApplication;
}
public void setHostedAppxApplication(HostedAppxApplication hostedAppxApplication) {
this.hostedAppxApplication = hostedAppxApplication;
}
public HostedMSIApplication getHostedMSIApplication() {
return hostedMSIApplication;
}
public void setHostedMSIApplication(HostedMSIApplication hostedMSIApplication) {
this.hostedMSIApplication = hostedMSIApplication;
}
public String toJSON() {
Gson gson = new Gson();
return gson.toJson(this);
}
}

@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.app.mgt.windows;
import java.util.List;
public class HostedAppxApplication {
private String packageUri;
private String packageFamilyName;
private List<String> dependencyPackageUri;
private String certificateHash;
private String encodedCertificate;
public String getPackageUri() {
return packageUri;
}
public void setPackageUri(String packageUri) {
this.packageUri = packageUri;
}
public String getPackageFamilyName() {
return packageFamilyName;
}
public void setPackageFamilyName(String packageFamilyName) {
this.packageFamilyName = packageFamilyName;
}
public List<String> getDependencyPackageUri() {
return dependencyPackageUri;
}
public void setDependencyPackageUri(List<String> dependencyPackageUri) {
this.dependencyPackageUri = dependencyPackageUri;
}
public String getCertificateHash() {
return certificateHash;
}
public void setCertificateHash(String certificateHash) {
this.certificateHash = certificateHash;
}
public String getEncodedCertificate() {
return encodedCertificate;
}
public void setEncodedCertificate(String encodedCertificate) {
this.encodedCertificate = encodedCertificate;
}
}

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.app.mgt.windows;
public class HostedMSIApplication {
private String productId;
private String contentUrl;
private String fileHash;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getContentUrl() {
return contentUrl;
}
public void setContentUrl(String contentUrl) {
this.contentUrl = contentUrl;
}
public String getFileHash() {
return fileHash;
}
public void setFileHash(String fileHash) {
this.fileHash = fileHash;
}
}

@ -0,0 +1,60 @@
/* Copyright (c) 2020, 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.configuration.mgt;
import java.util.List;
public class CorrectiveActionConfig {
private List<String> mailReceivers;
private String mailSubject;
private String mailBody;
private List<String> actionTypes;
public List<String> getMailReceivers() {
return mailReceivers;
}
public void setMailReceivers(List<String> mailReceivers) {
this.mailReceivers = mailReceivers;
}
public String getMailSubject() {
return mailSubject;
}
public void setMailSubject(String mailSubject) {
this.mailSubject = mailSubject;
}
public String getMailBody() {
return mailBody;
}
public void setMailBody(String mailBody) {
this.mailBody = mailBody;
}
public List<String> getActionTypes() {
return actionTypes;
}
public void setActionTypes(List<String> actionTypes) {
this.actionTypes = actionTypes;
}
}

@ -33,15 +33,6 @@ public class DeviceInfo implements Serializable {
private static final long serialVersionUID = 1998101733L; private static final long serialVersionUID = 1998101733L;
// @ApiModelProperty(name = "deviceId", value = "Device Id.", required = false)
// private int deviceId;
//
// @ApiModelProperty(name = "deviceType", value = "Type of the device.", required = true)
// private String deviceType;
//
// @ApiModelProperty(name = "deviceId", value = "Device identifier.", required = true)
// private DeviceIdentifier deviceIdentifier;
@ApiModelProperty(name = "IMEI", value = "IMEI number of the device.", required = true) @ApiModelProperty(name = "IMEI", value = "IMEI number of the device.", required = true)
private String IMEI; private String IMEI;

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.device.details;
import java.util.List;
public class DeviceLocationHistorySnapshotWrapper {
private DeviceLocationHistory fullSnapshot;
private List<Object> pathSnapshot;
public DeviceLocationHistory getFullSnapshot() {
return fullSnapshot;
}
public void setFullSnapshot(DeviceLocationHistory fullSnapshot) {
this.fullSnapshot = fullSnapshot;
}
public List<Object> getPathSnapshot() {
return pathSnapshot;
}
public void setPathSnapshot(List<Object> pathSnapshot) {
this.pathSnapshot = pathSnapshot;
}
}

@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.device.details;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(
value = "LocationBean",
description = "This class carries all information related IOS Device location."
)
public class LocationBean {
@ApiModelProperty(
name = "latitude",
value = "Latitude of the IOS device Location.",
required = true
)
private float latitude;
@ApiModelProperty(
name = "longitude",
value = "Longitude of the IOS device Location.",
required = true
)
private float longitude;
@ApiModelProperty(
name = "operationId",
value = "Specific Id of the Location operation.",
required = true
)
private String operationId;
@ApiModelProperty(
name = "locationEvents",
value = "If this is a device initiated location publishing."
)
private List<LocationEventBean> locations;
public List<LocationEventBean> getLocationEvents() {
return locations;
}
public void setLocationEvents(List<LocationEventBean> locationEvents) {
this.locations = locationEvents;
}
public String getOperationId() {
return operationId;
}
public void setOperationId(String operationId) {
this.operationId = operationId;
}
public float getLatitude() {
return latitude;
}
public void setLatitude(float latitude) {
this.latitude = latitude;
}
public float getLongitude() {
return longitude;
}
public void setLongitude(float longitude) {
this.longitude = longitude;
}
}

@ -0,0 +1,69 @@
/*
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common.device.details;
import io.swagger.annotations.ApiModelProperty;
public class LocationEventBean {
@ApiModelProperty(
name = "latitude",
value = "Latitude of the IOS device Location.",
required = true
)
private String latitude;
@ApiModelProperty(
name = "longitude",
value = "Longitude of the IOS device Location.",
required = true
)
private String longitude;
@ApiModelProperty(
name = "timestamp",
value = "Device Location time.",
required = true
)
private String timestamp;
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}

@ -0,0 +1,40 @@
/*
* Copyright (c) 2020, 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.event.config;
public class EventAction {
private String actionType;
private Object payload;
public String getActionType() {
return actionType;
}
public void setActionType(String actionType) {
this.actionType = actionType;
}
public Object getPayload() {
return payload;
}
public void setPayload(Object payload) {
this.payload = payload;
}
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2020, 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.event.config;
public class EventConfig {
private int eventId;
private String eventSource;
private String eventLogic;
private String actions;
public String getEventLogic() {
return eventLogic;
}
public void setEventLogic(String eventLogic) {
this.eventLogic = eventLogic;
}
public String getActions() {
return actions;
}
public void setActions(String actions) {
this.actions = actions;
}
public int getEventId() {
return eventId;
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
public String getEventSource() {
return eventSource;
}
public void setEventSource(String eventSource) {
this.eventSource = eventSource;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof EventConfig) {
EventConfig eventConfig = (EventConfig) obj;
return this.eventSource.equalsIgnoreCase(eventConfig.getEventSource()) &&
this.eventLogic.equalsIgnoreCase(eventConfig.getEventLogic());
}
return false;
}
@Override
public String toString() {
return "{eventId=" + eventId +
", eventSource='" + eventSource + '\'' +
", eventLogic='" + eventLogic + '\'' +
", actions='" + actions + '\'' +
'}';
}
}

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020, 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.event.config;
public class EventConfigurationException extends Exception {
public EventConfigurationException() {
super();
}
public EventConfigurationException(String message) {
super(message);
}
public EventConfigurationException(String message, Throwable cause) {
super(message, cause);
}
public EventConfigurationException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,75 @@
/*
* Copyright (c) 2020, 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.event.config;
import java.util.List;
public interface EventConfigurationProviderService {
/**
* Create event configuration records
*
* @param eventConfigList event list to be added
* @param groupIds group ids of the events are mapped
* @return generated event ids
* @throws EventConfigurationException errors thrown while creating event configuration
*/
List<Integer> createEventsOfDeviceGroup(List<EventConfig> eventConfigList, List<Integer> groupIds)
throws EventConfigurationException;
/**
* Update event configuration records
*
* @param eventConfig updated event configuration list. event ids should be present for
* the updating events and event ids should be -1 for the newly creating events
* @param removedEventIdList event ids of removed while updating the event configuration
* @param groupIds group ids to be mapped with updated events
* @return Newly created event Ids
* @throws EventConfigurationException
*/
List<Integer> updateEventsOfDeviceGroup(List<EventConfig> eventConfig, List<Integer> removedEventIdList,
List<Integer> groupIds) throws EventConfigurationException;
/**
* Retrieve event list using event IDs
*
* @param createdEventIds event ids
* @return {@link EventConfig} List of events of defined IDs
* @throws EventConfigurationException
*/
List<EventConfig> getEvents(List<Integer> createdEventIds) throws EventConfigurationException;
/**
* Get event sources attached to a specific group
*
* @param groupId mapped group id of events
* @param tenantId event owning tenant
* @return Event sources of the group
* @throws EventConfigurationException error thrown while retrieving event sources
*/
List<String> getEventsSourcesOfGroup(int groupId, int tenantId) throws EventConfigurationException;
/**
* Delete events by event Ids
*
* @param eventList event list to be deleted
* @throws EventConfigurationException error thrown while deleting event records
*/
void deleteEvents(List<EventConfig> eventList) throws EventConfigurationException;
}

@ -0,0 +1,21 @@
/*
* Copyright (c) 2020, 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.event.config;
public interface EventMetaData {}

@ -0,0 +1,69 @@
/*
* Copyright (c) 2020, 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.event.config;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.List;
public class EventOperation {
private String eventSource;
private EventMetaData eventDefinition;
private String eventTriggers;
public String getEventSource() {
return eventSource;
}
public void setEventSource(String eventSource) {
this.eventSource = eventSource;
}
public EventMetaData getEventDefinition() {
return eventDefinition;
}
public void setEventDefinition(EventMetaData eventDefinition) {
this.eventDefinition = eventDefinition;
}
public String getEventTriggers() {
return eventTriggers;
}
public void setEventTriggers(List<EventConfig> eventList) {
JsonArray eventTriggers = new JsonArray();
JsonObject eventTrigger;
for (EventConfig eventConfig : eventList) {
eventTrigger = new JsonObject();
eventTrigger.addProperty("eventId", eventConfig.getEventId());
eventTrigger.addProperty("eventLogic", eventConfig.getEventLogic());
eventTrigger.addProperty("actions", eventConfig.getActions());
eventTriggers.add(eventTrigger);
}
this.eventTriggers = eventTriggers.toString();
}
public String toJSON() {
Gson gson = new Gson();
return gson.toJson(this);
}
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020, 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.event.config;
public class EventRevokeOperation {
private String eventSource;
private int id;
public String getEventSource() {
return eventSource;
}
public void setEventSource(String eventSource) {
this.eventSource = eventSource;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

@ -0,0 +1,110 @@
/*
* Copyright (c) 2020, 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.event.config.EventMetaData;
public class GeoFenceEventMeta implements EventMetaData {
private int id;
private String fenceName;
private String description;
private double latitude;
private double longitude;
private float radius;
private String geoJson;
private String fenceShape;
public GeoFenceEventMeta() {
}
public GeoFenceEventMeta(GeofenceData geofenceData) {
this.id = geofenceData.getId();
this.fenceName = geofenceData.getFenceName();
this.description = geofenceData.getDescription();
this.latitude = geofenceData.getLatitude();
this.longitude = geofenceData.getLongitude();
this.radius = geofenceData.getRadius();
this.geoJson = geofenceData.getGeoJson();
this.fenceShape = geofenceData.getFenceShape();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFenceName() {
return fenceName;
}
public void setFenceName(String fenceName) {
this.fenceName = fenceName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public String getGeoJson() {
return geoJson;
}
public void setGeoJson(String geoJson) {
this.geoJson = geoJson;
}
public String getFenceShape() {
return fenceShape;
}
public void setFenceShape(String fenceShape) {
this.fenceShape = fenceShape;
}
}

@ -19,7 +19,12 @@
package org.wso2.carbon.device.mgt.common.geo.service; package org.wso2.carbon.device.mgt.common.geo.service;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; 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.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.event.config.EventConfigurationException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -69,4 +74,101 @@ public interface GeoLocationProviderService {
List<GeoFence> getTrafficAlerts(DeviceIdentifier identifier, String owner) throws GeoLocationBasedServiceException; List<GeoFence> getTrafficAlerts(DeviceIdentifier identifier, String owner) throws GeoLocationBasedServiceException;
List<GeoFence> getTrafficAlerts() throws GeoLocationBasedServiceException; List<GeoFence> getTrafficAlerts() throws GeoLocationBasedServiceException;
/**
* Create new GeoFence
* @param geofenceData fence data
* @return true if the fence creation success
* @throws GeoLocationBasedServiceException error occurs while creating a geofence
* @throws EventConfigurationException for errors occur while creating event configuration for the geofence
*/
boolean createGeofence(GeofenceData geofenceData) throws GeoLocationBasedServiceException, EventConfigurationException;
/**
* Get geofence by ID
* @param fenceId id of the fence which should be retrieved
* @return {@link GeofenceData} Extracted geofence data
* @throws GeoLocationBasedServiceException error occurs while retrieving a geofence
*/
GeofenceData getGeoFences(int fenceId) throws GeoLocationBasedServiceException;
/**
* Get paginated geofence list
* @param request Pagination Request
* @return {@link GeofenceData} List of Geofences retrieved
* @throws GeoLocationBasedServiceException error occurs while retrieving geofences
*/
List<GeofenceData> getGeoFences(PaginationRequest request) throws GeoLocationBasedServiceException;
/**
* Search geo fences using the fence name
* @param name searching name of the fence
* @return {@link GeofenceData} list of fences found for the specific name
* @throws GeoLocationBasedServiceException for errors occur while querying geo fences
*/
List<GeofenceData> getGeoFences(String name) throws GeoLocationBasedServiceException;
/**
* Get all geo fences of the tenant
* @return {@link GeofenceData} list of the all geo fences of the tenant
* @throws GeoLocationBasedServiceException for errors occur while querying geo fences
*/
List<GeofenceData> getGeoFences() throws GeoLocationBasedServiceException;
/**
* Delete Geofence with ID
* @param fenceId Id of the fence which should be deleted
* @return true if deletion success. false if not record found for the used Id
* @throws GeoLocationBasedServiceException for errors occur while deleting geo fences
*/
boolean deleteGeofenceData(int fenceId) throws GeoLocationBasedServiceException;
/**
* Update a Geofence. Will not be updated tenantId and owner
* @param geofenceData Bean with updated geofence data
* @param fenceId Id of the fence which should be updated
* @return true if update success. false if not a record found for the used Id
* @throws GeoLocationBasedServiceException for errors occur while updating geo fences
* @throws EventConfigurationException for errors occur while updating event records of the geofence
*/
boolean updateGeofence(GeofenceData geofenceData, int fenceId)
throws GeoLocationBasedServiceException, EventConfigurationException;
/**
* Update geofence event configuration
* @param geofenceData updated GeoFenceData object
* @param removedEventIdList removed event ids
* @param groupIds newly added group ids to be mapped with event records
* @param fenceId updating fence id
* @return true for successful update of geofence event data
* @throws GeoLocationBasedServiceException any errors occurred while updating event records of the fence
*/
boolean updateGeoEventConfigurations(GeofenceData geofenceData, List<Integer> removedEventIdList,
List<Integer> groupIds, int fenceId) throws GeoLocationBasedServiceException;
/**
* Attach event data into geofence objects
* @param geoFences list of GeofenceData to attach corresponding event data
* @return {@link GeofenceData} events attached geofence object list
* @throws GeoLocationBasedServiceException any errors occurred while attaching event records to geofences
*/
List<GeofenceData> attachEventObjects(List<GeofenceData> geoFences) throws GeoLocationBasedServiceException;
/**
* Get Geofence records of groups. Attaching with corresponding event data of fences
* @param groupId Id of the group geo which fences attached
* @param tenantId Id of the tenant which geo fences attached
* @param requireEventData use true for attach event records with the geo fence data
* @return {@link GeofenceData} Queried geo fence data using group Id
* @throws GeoLocationBasedServiceException any errors occurred while getting geofences of group
*/
List<GeofenceData> getGeoFencesOfGroup(int groupId, int tenantId, boolean requireEventData) throws GeoLocationBasedServiceException;
/**
* Get event records mapped with specific geo fence
* @param geoFenceId Id of the Geofence to retrieve mapped events
* @return {@link EventConfig} Event records of the geofence
* @throws GeoLocationBasedServiceException any errors occurred while reading event records to geofence
*/
List<EventConfig> getEventsOfGeoFence(int geoFenceId) throws GeoLocationBasedServiceException;
} }

@ -0,0 +1,145 @@
/*
* Copyright (c) 2020, 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.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.event.config.EventMetaData;
import java.util.List;
import java.util.Map;
public class GeofenceData {
private int id;
private String fenceName;
private String description;
private double latitude;
private double longitude;
private float radius;
private int tenantId;
private String owner;
private String geoJson;
private String fenceShape;
private List<EventConfig> eventConfig;
private List<Integer> groupIds;
private Map<Integer, String> groupData;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFenceName() {
return fenceName;
}
public void setFenceName(String fenceName) {
this.fenceName = fenceName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public int getTenantId() {
return tenantId;
}
public void setTenantId(int tenantId) {
this.tenantId = tenantId;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getGeoJson() {
return geoJson;
}
public void setGeoJson(String geoJson) {
this.geoJson = geoJson;
}
public String getFenceShape() {
return fenceShape;
}
public void setFenceShape(String fenceShape) {
this.fenceShape = fenceShape;
}
public List<EventConfig> getEventConfig() {
return eventConfig;
}
public void setEventConfig(List<EventConfig> eventConfig) {
this.eventConfig = eventConfig;
}
public List<Integer> getGroupIds() {
return groupIds;
}
public void setGroupIds(List<Integer> groupIds) {
this.groupIds = groupIds;
}
public Map<Integer, String> getGroupData() {
return groupData;
}
public void setGroupData(Map<Integer, String> groupData) {
this.groupData = groupData;
}
}

@ -55,6 +55,16 @@ public class CorrectiveAction implements Serializable {
) )
private List<ProfileFeature> operations; private List<ProfileFeature> operations;
@ApiModelProperty(
name = "isReactive",
value = "Declare the action as a reactive action"
)
private boolean isReactive;
private Integer featureId;
private Integer associatedGeneralPolicyId;
public String getActionType() { public String getActionType() {
return actionType; return actionType;
} }
@ -78,4 +88,28 @@ public class CorrectiveAction implements Serializable {
public void setOperations(List<ProfileFeature> operations) { public void setOperations(List<ProfileFeature> operations) {
this.operations = operations; this.operations = operations;
} }
public Integer getFeatureId() {
return featureId;
}
public void setFeatureId(Integer featureId) {
this.featureId = featureId;
}
public Integer getAssociatedGeneralPolicyId() {
return associatedGeneralPolicyId;
}
public void setAssociatedGeneralPolicyId(Integer associatedGeneralPolicyId) {
this.associatedGeneralPolicyId = associatedGeneralPolicyId;
}
public boolean isReactive() {
return isReactive;
}
public void setReactive(boolean reactive) {
isReactive = reactive;
}
} }

@ -53,6 +53,12 @@ public class Policy implements Comparable<Policy>, Serializable {
private static final long serialVersionUID = 19981017L; private static final long serialVersionUID = 19981017L;
@ApiModelProperty(
name = "payloadVersion",
value = "Payload version of the Policy",
example = "1")
private String policyPayloadVersion;
@ApiModelProperty( @ApiModelProperty(
name = "id", name = "id",
value = "The policy ID", value = "The policy ID",
@ -201,13 +207,19 @@ public class Policy implements Comparable<Policy>, Serializable {
example = "GENERAL") example = "GENERAL")
private String policyType; private String policyType;
@ApiModelProperty( @ApiModelProperty(name = "correctiveActions",
name = "correctiveActions", value = "List of corrective actions to be applied when the policy is violated")
value = "List of corrective actions to be applied when the policy is violated",
example = "[{'actionType': 'POLICY', 'policyId': 1}]"
)
private List<CorrectiveAction> correctiveActions; private List<CorrectiveAction> correctiveActions;
@XmlElement
public String getPolicyPayloadVersion() {
return policyPayloadVersion;
}
public void setPolicyPayloadVersion(String policyPayloadVersion) {
this.policyPayloadVersion = policyPayloadVersion;
}
@XmlElement @XmlElement
public int getId() { public int getId() {
return id; return id;
@ -379,13 +391,11 @@ public class Policy implements Comparable<Policy>, Serializable {
this.policyType = policyType; this.policyType = policyType;
} }
@XmlElement
public List<CorrectiveAction> getCorrectiveActions() { public List<CorrectiveAction> getCorrectiveActions() {
return correctiveActions; return correctiveActions;
} }
public void setCorrectiveActions( public void setCorrectiveActions(List<CorrectiveAction> correctiveActions) {
List<CorrectiveAction> correctiveActions) {
this.correctiveActions = correctiveActions; this.correctiveActions = correctiveActions;
} }

@ -19,7 +19,6 @@
package org.wso2.carbon.device.mgt.common.policy.mgt; package org.wso2.carbon.device.mgt.common.policy.mgt;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData; import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException; import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException;

@ -22,6 +22,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
@ApiModel(value = "ProfileFeature", description = "This class carries all information related to profile " @ApiModel(value = "ProfileFeature", description = "This class carries all information related to profile "
+ "features") + "features")
@ -64,6 +65,11 @@ public class ProfileFeature implements Serializable {
example = "{\\\"enabled\\\":false}") example = "{\\\"enabled\\\":false}")
private Object content; private Object content;
@ApiModelProperty(name = "correctiveActions",
value = "List of corrective actions to be applied when the policy is violated",
required = true)
private List<CorrectiveAction> correctiveActions;
public int getId() { public int getId() {
return id; return id;
} }
@ -103,4 +109,12 @@ public class ProfileFeature implements Serializable {
public void setContent(Object content) { public void setContent(Object content) {
this.content = content; this.content = content;
} }
public List<CorrectiveAction> getCorrectiveActions() {
return correctiveActions;
}
public void setCorrectiveActions(List<CorrectiveAction> correctiveActions) {
this.correctiveActions = correctiveActions;
}
} }

@ -28,6 +28,9 @@ public class Input {
private String type; private String type;
private String placeholderValue; private String placeholderValue;
private List<Rule> rules; private List<Rule> rules;
private String apiUrl;
private String arrayPath;
private String dataKey;
@XmlElement(name = "Type") @XmlElement(name = "Type")
public String getType() { public String getType() {
@ -52,4 +55,31 @@ public class Input {
public List<Rule> getRules() { return rules; } public List<Rule> getRules() { return rules; }
public void setRules(List<Rule> rules) { this.rules = rules; } public void setRules(List<Rule> rules) { this.rules = rules; }
@XmlElement(name = "Url")
public String getUrl() {
return apiUrl;
}
public void setUrl(String url) {
this.apiUrl = url;
}
@XmlElement(name = "ArrayPath")
public String getArrayPath() {
return arrayPath;
}
public void setArrayPath(String arrayPath) {
this.arrayPath = arrayPath;
}
@XmlElement(name = "DataKey")
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
} }

@ -45,6 +45,7 @@ public class Item {
private InputList inputList; private InputList inputList;
private String nullableValue; private String nullableValue;
private String divider; private String divider;
private boolean isHidden;
@XmlElement(name = "Label") @XmlElement(name = "Label")
public String getLabel() { public String getLabel() {
@ -207,4 +208,13 @@ public class Item {
public void setDivider(String divider) { public void setDivider(String divider) {
this.divider = divider; this.divider = divider;
} }
@XmlElement(name = "Hidden")
public boolean isHidden() {
return isHidden;
}
public void setHidden(boolean hidden) {
isHidden = hidden;
}
} }

@ -28,6 +28,10 @@ public class Select {
private String valueType; private String valueType;
private List<Option> options; private List<Option> options;
private String mode; private String mode;
private String apiUrl;
private String defineValueKey;
private String displayValueKey;
private String arrayPath;
@XmlElement(name = "ValueType", required = true) @XmlElement(name = "ValueType", required = true)
public String getValueType() { public String getValueType() {
@ -56,4 +60,40 @@ public class Select {
public void setMode(String mode) { public void setMode(String mode) {
this.mode = mode; this.mode = mode;
} }
@XmlElement(name = "Url")
public String getUrl() {
return apiUrl;
}
public void setUrl(String url) {
this.apiUrl = url;
}
@XmlElement(name = "DefineValueKey")
public String getDefineValueKey() {
return defineValueKey;
}
public void setDefineValueKey(String defineValueKey) {
this.defineValueKey = defineValueKey;
}
@XmlElement(name = "DisplayValueKey")
public String getDisplayValueKey() {
return displayValueKey;
}
public void setDisplayValueKey(String displayValueKey) {
this.displayValueKey = displayValueKey;
}
@XmlElement(name = "ArrayPath")
public String getArrayPath() {
return arrayPath;
}
public void setArrayPath(String arrayPath) {
this.arrayPath = arrayPath;
}
} }

@ -42,6 +42,7 @@ public final class DeviceManagementConstants {
public static final String DM_CACHE_MANAGER = "DM_CACHE_MANAGER"; public static final String DM_CACHE_MANAGER = "DM_CACHE_MANAGER";
public static final String DEVICE_CACHE = "DEVICE_CACHE"; public static final String DEVICE_CACHE = "DEVICE_CACHE";
public static final String GEOFENCE_CACHE = "GEOFENCE_CACHE";
public static final String ENROLLMENT_NOTIFICATION_API_ENDPOINT = "/api/device-mgt/enrollment-notification"; public static final String ENROLLMENT_NOTIFICATION_API_ENDPOINT = "/api/device-mgt/enrollment-notification";
public static final String URL_SEPERATOR = "/"; public static final String URL_SEPERATOR = "/";
@ -97,6 +98,14 @@ public final class DeviceManagementConstants {
public static final String MONITOR_OPERATION_CODE = "MONITOR"; public static final String MONITOR_OPERATION_CODE = "MONITOR";
public static final String POLICY_OPERATION_CODE = PolicyOperation.POLICY_OPERATION_CODE; public static final String POLICY_OPERATION_CODE = PolicyOperation.POLICY_OPERATION_CODE;
public static final String POLICY_REVOKE_OPERATION_CODE = OperationMgtConstants.OperationCodes.POLICY_REVOKE; public static final String POLICY_REVOKE_OPERATION_CODE = OperationMgtConstants.OperationCodes.POLICY_REVOKE;
public static final String EVENT_CONFIG_OPERATION_CODE = OperationMgtConstants.OperationCodes.EVENT_CONFIG;
public static final String EVENT_REVOKE_OPERATION_CODE = OperationMgtConstants.OperationCodes.EVENT_REVOKE;
}
public static final class CorrectiveActions {
private CorrectiveActions() {throw new AssertionError();}
public static final String E_MAIL = "MAIL";
} }
public static final class EmailAttributes { public static final class EmailAttributes {
@ -117,6 +126,7 @@ public final class DeviceManagementConstants {
public static final String USER_REGISTRATION_TEMPLATE = "user-registration"; public static final String USER_REGISTRATION_TEMPLATE = "user-registration";
public static final String USER_ENROLLMENT_TEMPLATE = "user-enrollment"; public static final String USER_ENROLLMENT_TEMPLATE = "user-enrollment";
public static final String USER_VERIFY_TEMPLATE = "user-verify"; public static final String USER_VERIFY_TEMPLATE = "user-verify";
public static final String POLICY_VIOLATE_TEMPLATE = "policy-violating-notifier";
public static final String USER_WELCOME_TEMPLATE = "user-welcome"; public static final String USER_WELCOME_TEMPLATE = "user-welcome";
public static final String DEFAULT_ENROLLMENT_TEMPLATE = "default-enrollment-invitation"; public static final String DEFAULT_ENROLLMENT_TEMPLATE = "default-enrollment-invitation";
} }

@ -0,0 +1,73 @@
/*
* Copyright (c) 2020, 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.core.cache;
import java.util.Objects;
public class GeoCacheKey {
private int fenceId;
private int tenantId;
private volatile int hashCode;
public GeoCacheKey(int fenceId, int tenantId) {
this.fenceId = fenceId;
this.tenantId = tenantId;
}
public GeoCacheKey() {
}
public int getFenceId() {
return fenceId;
}
public void setFenceId(int fenceId) {
this.fenceId = fenceId;
}
public int getTenantId() {
return tenantId;
}
public void setTenantId(int tenantId) {
this.tenantId = tenantId;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!GeoCacheKey.class.isAssignableFrom(obj.getClass())) {
return false;
}
final GeoCacheKey other = (GeoCacheKey) obj;
String thisId = this.fenceId + "-" + "_" + this.tenantId;
String otherId = other.fenceId + "-" + "_" + other.tenantId;
return thisId.equals(otherId);
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Objects.hash(fenceId, tenantId);
}
return hashCode;
}
}

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, 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.core.cache;
import org.wso2.carbon.device.mgt.common.geo.service.GeofenceData;
public interface GeoCacheManager {
/**
* Add geo fences to the cache
* @param geofenceData adding fence object
* @param fenceId id of the fence
* @param tenantId id of the tenant
*/
void addFenceToCache(GeofenceData geofenceData, int fenceId, int tenantId);
/**
* Update geo fences already in cache
* @param geofenceData updating geo fence object
* @param fenceId id of the fence
* @param tenantId id of the tenant
*/
void updateGeoFenceInCache(GeofenceData geofenceData, int fenceId, int tenantId);
/**
* Remove geo fence from cache
* @param fenceId id of the fence
* @param tenantId id of the tenant
*/
void removeFenceFromCache(int fenceId, int tenantId);
/**
* Get geo fence data from the cache
* @param fenceId id of the retrieving fence object
* @param tenantId tenant id of the fence created
* @return GeofenceData object if the cache have the specific object or null if there is no entry
*/
GeofenceData getGeoFenceFromCache(int fenceId, int tenantId);
}

@ -0,0 +1,95 @@
/*
* Copyright (c) 2020, 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.core.cache.impl;
import org.wso2.carbon.device.mgt.common.geo.service.GeofenceData;
import org.wso2.carbon.device.mgt.core.cache.GeoCacheKey;
import org.wso2.carbon.device.mgt.core.cache.GeoCacheManager;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import javax.cache.Cache;
public class GeoCacheManagerImpl implements GeoCacheManager {
private static GeoCacheManager geoCacheManager;
private GeoCacheManagerImpl() {}
public static GeoCacheManager getInstance() {
if (geoCacheManager == null) {
synchronized (GeoCacheManagerImpl.class) {
if (geoCacheManager == null) {
geoCacheManager = new GeoCacheManagerImpl();
}
}
}
return geoCacheManager;
}
@Override
public void addFenceToCache(GeofenceData geofenceData, int fenceId, int tenantId) {
Cache<GeoCacheKey, GeofenceData> lCache = DeviceManagerUtil.getGeoCache();
if (lCache != null) {
GeoCacheKey cacheKey = getCacheKey(fenceId, tenantId);
if (lCache.containsKey(cacheKey)) {
this.updateGeoFenceInCache(geofenceData, fenceId, tenantId);
} else {
lCache.put(cacheKey, geofenceData);
}
}
}
@Override
public void removeFenceFromCache(int fenceId, int tenantId) {
Cache<GeoCacheKey, GeofenceData> lCache = DeviceManagerUtil.getGeoCache();
if (lCache != null) {
GeoCacheKey cacheKey = getCacheKey(fenceId, tenantId);
if (lCache.containsKey(cacheKey)) {
lCache.remove(cacheKey);
}
}
}
@Override
public void updateGeoFenceInCache(GeofenceData geofenceData, int fenceId, int tenantId) {
Cache<GeoCacheKey, GeofenceData> lCache = DeviceManagerUtil.getGeoCache();
if (lCache != null) {
GeoCacheKey cacheKey = getCacheKey(fenceId, tenantId);
if (lCache.containsKey(cacheKey)) {
lCache.replace(cacheKey, geofenceData);
}
}
}
@Override
public GeofenceData getGeoFenceFromCache(int fenceId, int tenantId) {
GeofenceData geofenceData = null;
Cache<GeoCacheKey, GeofenceData> lCache = DeviceManagerUtil.getGeoCache();
if (lCache != null) {
geofenceData = lCache.get(getCacheKey(fenceId, tenantId));
}
return geofenceData;
}
private GeoCacheKey getCacheKey(int fenceId, int tenantId) {
GeoCacheKey geoCacheKey = new GeoCacheKey();
geoCacheKey.setFenceId(fenceId);
geoCacheKey.setTenantId(tenantId);
return geoCacheKey;
}
}

@ -23,6 +23,7 @@ import org.wso2.carbon.device.mgt.core.config.analytics.OperationAnalyticsConfig
import org.wso2.carbon.device.mgt.core.config.archival.ArchivalConfiguration; import org.wso2.carbon.device.mgt.core.config.archival.ArchivalConfiguration;
import org.wso2.carbon.device.mgt.core.config.cache.CertificateCacheConfiguration; import org.wso2.carbon.device.mgt.core.config.cache.CertificateCacheConfiguration;
import org.wso2.carbon.device.mgt.core.config.cache.DeviceCacheConfiguration; import org.wso2.carbon.device.mgt.core.config.cache.DeviceCacheConfiguration;
import org.wso2.carbon.device.mgt.core.config.cache.GeoFenceCacheConfiguration;
import org.wso2.carbon.device.mgt.core.config.geo.location.GeoLocationConfiguration; import org.wso2.carbon.device.mgt.core.config.geo.location.GeoLocationConfiguration;
import org.wso2.carbon.device.mgt.core.config.identity.IdentityConfigurations; import org.wso2.carbon.device.mgt.core.config.identity.IdentityConfigurations;
import org.wso2.carbon.device.mgt.core.config.keymanager.KeyManagerConfigurations; import org.wso2.carbon.device.mgt.core.config.keymanager.KeyManagerConfigurations;
@ -54,6 +55,7 @@ public final class DeviceManagementConfig {
private PullNotificationConfiguration pullNotificationConfiguration; private PullNotificationConfiguration pullNotificationConfiguration;
private DeviceStatusTaskConfig deviceStatusTaskConfig; private DeviceStatusTaskConfig deviceStatusTaskConfig;
private DeviceCacheConfiguration deviceCacheConfiguration; private DeviceCacheConfiguration deviceCacheConfiguration;
private GeoFenceCacheConfiguration geoFenceCacheConfiguration;
private CertificateCacheConfiguration certificateCacheConfiguration; private CertificateCacheConfiguration certificateCacheConfiguration;
private OperationAnalyticsConfiguration operationAnalyticsConfiguration; private OperationAnalyticsConfiguration operationAnalyticsConfiguration;
private GeoLocationConfiguration geoLocationConfiguration; private GeoLocationConfiguration geoLocationConfiguration;
@ -154,6 +156,15 @@ public final class DeviceManagementConfig {
this.deviceCacheConfiguration = deviceCacheConfiguration; this.deviceCacheConfiguration = deviceCacheConfiguration;
} }
@XmlElement(name = "GeoFenceCacheConfiguration", required = true)
public GeoFenceCacheConfiguration getGeoFenceCacheConfiguration() {
return geoFenceCacheConfiguration;
}
public void setGeoFenceCacheConfiguration(GeoFenceCacheConfiguration geoFenceCacheConfiguration) {
this.geoFenceCacheConfiguration = geoFenceCacheConfiguration;
}
@XmlElement(name = "CertificateCacheConfiguration", required = true) @XmlElement(name = "CertificateCacheConfiguration", required = true)
public CertificateCacheConfiguration getCertificateCacheConfiguration() { public CertificateCacheConfiguration getCertificateCacheConfiguration() {
return certificateCacheConfiguration; return certificateCacheConfiguration;

@ -0,0 +1,57 @@
/*
* Copyright (c) 2020, 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.core.config.cache;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "GeoFenceCacheConfiguration")
public class GeoFenceCacheConfiguration {
private boolean isEnabled;
private int expiryTime;
private long capacity;
@XmlElement(name = "Enable", required = true)
public boolean isEnabled() {
return isEnabled;
}
public void setEnabled(boolean enabled) {
isEnabled = enabled;
}
@XmlElement(name = "ExpiryTime", required = true)
public int getExpiryTime() {
return expiryTime;
}
public void setExpiryTime(int expiryTime) {
this.expiryTime = expiryTime;
}
@XmlElement(name = "Capacity", required = true)
public long getCapacity() {
return capacity;
}
public void setCapacity(long capacity) {
this.capacity = capacity;
}
}

@ -29,10 +29,13 @@ import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
import org.wso2.carbon.device.mgt.core.dao.impl.ApplicationDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.ApplicationDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.DeviceTypeDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.DeviceTypeDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.EnrollmentDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.EnrollmentDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.event.GenericEventConfigDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.GeofenceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.device.GenericDeviceDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.device.GenericDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.device.OracleDeviceDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.device.OracleDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.device.PostgreSQLDeviceDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.device.PostgreSQLDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.device.SQLServerDeviceDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.device.SQLServerDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.event.H2EventConfigDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO;
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.impl.DeviceDetailsDAOImpl; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.impl.DeviceDetailsDAOImpl;
@ -149,6 +152,27 @@ public class DeviceManagementDAOFactory {
return new PrivacyComplianceDAOImpl(); return new PrivacyComplianceDAOImpl();
} }
public static GeofenceDAO getGeofenceDAO() {
return new GeofenceDAOImpl();
}
public static EventConfigDAO getEventConfigDAO() {
if (databaseEngine != null) {
switch (databaseEngine) {
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_POSTGRESQL:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_ORACLE:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MSSQL:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
return new GenericEventConfigDAOImpl();
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_H2:
return new H2EventConfigDAOImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
}
}
throw new IllegalStateException("Database engine has not initialized properly.");
}
public static void init(DataSourceConfig config) { public static void init(DataSourceConfig config) {
dataSource = resolveDataSource(config); dataSource = resolveDataSource(config);
try { try {

@ -0,0 +1,115 @@
/*
* Copyright (c) 2020, 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.core.dao;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import java.util.List;
public interface EventConfigDAO {
/**
* Create event configuration entries of the db for a selected tenant
* @param eventConfigList event list to be created
* @param tenantId corresponding tenant id of the events
* @return generated event ids while storing geofence data
* @throws EventManagementDAOException error occurred while creating event records
*/
List<Integer> storeEventRecords(List<EventConfig> eventConfigList, int tenantId) throws EventManagementDAOException;
/**
* Cerate even-group mapping records
* @param eventIds event ids to be mapped with groups
* @param groupIds group ids of the event attached with
* @return true for the successful creation
* @throws EventManagementDAOException error occurred while creating event-group mapping records
*/
boolean addEventGroupMappingRecords(List<Integer> eventIds, List<Integer> groupIds) throws EventManagementDAOException;
/**
* Get events owned by a specific device group
* @param groupIds group ids of the events
* @param tenantId tenant of the events owning
* @return list of event configuration filtered by tenant id and group ids
* @throws EventManagementDAOException error occurred while reading event records
*/
List<EventConfig> getEventsOfGroups(List<Integer> groupIds, int tenantId) throws EventManagementDAOException;
/**
* Get events of groups using group Id
* @param groupId id of the group
* @param tenantId id of the tenant
* @return EventConfig list of specific group
* @throws EventManagementDAOException errors occur while retrieving events of groups
*/
List<EventConfig> getEventsOfGroups(int groupId, int tenantId) throws EventManagementDAOException;
/**
* Delete event group mapping records using the group ids
* @param groupIdsToDelete id of groups
* @throws EventManagementDAOException error occurred while deleting event-group mapping records
*/
void deleteEventGroupMappingRecordsByGroupIds(List<Integer> groupIdsToDelete) throws EventManagementDAOException;
/**
* Update event records of the tenant
* @param eventsToUpdate updating event records
* @throws EventManagementDAOException error occurred while updating events
*/
void updateEventRecords(List<EventConfig> eventsToUpdate) throws EventManagementDAOException;
/**
* Delete events using event ids
* @param eventsIdsToDelete ids of the events which should be deleted
* @throws EventManagementDAOException error occurred while deleting event records
*/
void deleteEventRecords(List<Integer> eventsIdsToDelete) throws EventManagementDAOException;
/**
* Get event records by event ids
* @param eventIds filtering event ids
* @return filtered event configuration list
* @throws EventManagementDAOException error occurred while reading events
*/
List<EventConfig> getEventsById(List<Integer> eventIds) throws EventManagementDAOException;
/**
* Get group ids belong to events using event ids
* @param eventIds Ids of the events mapped with group
* @return Group Id list
* @throws EventManagementDAOException thrown errors while retrieving group Ids of events
*/
List<Integer> getGroupsOfEvents(List<Integer> eventIds) throws EventManagementDAOException;
/**
* Delete event group mapping records using event Ids
* @param eventIds Ids of the events
* @throws EventManagementDAOException thrown errors while deleting event group mappings
*/
void deleteEventGroupMappingRecordsByEventIds(List<Integer> eventIds) throws EventManagementDAOException;
/**
* Retrieve event sources mapped with specific groups and tenant
* @param groupId Id of the group
* @param tenantId Id of the tenant
* @return Event source list belong to
* @throws EventManagementDAOException thrown errors while retrieving event sources
*/
List<String> getEventSourcesOfGroups(int groupId, int tenantId) throws EventManagementDAOException;
}

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020, 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.core.dao;
public class EventManagementDAOException extends Exception{
public EventManagementDAOException() {
super();
}
public EventManagementDAOException(String message) {
super(message);
}
public EventManagementDAOException(String message, Throwable cause) {
super(message, cause);
}
public EventManagementDAOException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,177 @@
/*
* Copyright (c) 2020, 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.core.dao;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.geo.service.GeofenceData;
import org.wso2.carbon.device.mgt.core.dto.event.config.GeoFenceGroupMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Use to manage geofence data in DB
*/
public interface GeofenceDAO {
/**
* Create new record of GeoFence
* @param geofenceData GeoFence record data
* @return created row count
* @throws DeviceManagementDAOException error occurs while saving the data
*/
GeofenceData saveGeofence(GeofenceData geofenceData) throws DeviceManagementDAOException;
/**
* Retrieve a geofence record for specified Id
* @param fenceId Id of the fence which should be queried
* @return Retrieved geofence data with tenant and owner info
* @throws DeviceManagementDAOException error occurs while reading the data
*/
GeofenceData getGeofence(int fenceId) throws DeviceManagementDAOException;
/**
* Retrieve a paginated list of geofence data for a specific tenant
* @param request pagination request with offset and limit
* @param tenantId Id of the tenant which fences owned
* @return List of geofences retrieved
* @throws DeviceManagementDAOException error occurs while reading the data
*/
List<GeofenceData> getGeoFencesOfTenant(PaginationRequest request, int tenantId)
throws DeviceManagementDAOException;
/**
* Search geofence by fence name of a specific tenant
* @param fenceName searching name
* @param tenantId searching tenant
* @return list of found fences
* @throws DeviceManagementDAOException
*/
List<GeofenceData> getGeoFencesOfTenant(String fenceName, int tenantId)
throws DeviceManagementDAOException;
/**
* Get all fences of the specific tenant
* @param tenantId tenant id of the fences
* @return list of the fences owned by the tenant
* @throws DeviceManagementDAOException
*/
List<GeofenceData> getGeoFencesOfTenant(int tenantId)
throws DeviceManagementDAOException;
/**
* Delete a geofence using the geofence Id
* @param fenceId Id of the fence which should be deleted
* @return Affected row count
* @throws DeviceManagementDAOException error occurs while deleting the data
*/
int deleteGeofenceById(int fenceId) throws DeviceManagementDAOException;
/**
* Update a geofence record using fence id
* @param geofenceData updated geofence data
* @param fenceId id of the fence which should be updated
* @return affected row count
* @throws DeviceManagementDAOException error occurs while updating the data
*/
int updateGeofence(GeofenceData geofenceData, int fenceId) throws DeviceManagementDAOException;
/**
* Create geofence-group mapping records for the fence associated groups
* @param geofenceData geofence data to be mapped with device group
* @param groupIds group ids of the geofence
* @return true for the successful record creation
* @throws DeviceManagementDAOException error occurred while saving event records
*/
boolean createGeofenceGroupMapping(GeofenceData geofenceData, List<Integer> groupIds) throws DeviceManagementDAOException;
/**
* Get associated group ids of a geofence mapped with
* @param fenceId id of the fence
* @return list of group ids mapped with the specified fence
* @throws DeviceManagementDAOException error occurred while reading group id records
*/
List<Integer> getGroupIdsOfGeoFence(int fenceId) throws DeviceManagementDAOException;
/**
* Delete geofence-group mapping records
* @param groupIdsToDelete group ids to be removed from the mapping table
* @throws DeviceManagementDAOException error occurred while deleting group id mapping records
*/
void deleteGeofenceGroupMapping(List<Integer> groupIdsToDelete) throws DeviceManagementDAOException;
/**
* Create geofence-event mapping records
* @param fenceId geofence id of the mapping records to be placed
* @param eventIds generated event ids for the geofence event configuration
* @throws DeviceManagementDAOException error occurred while creating geofence event mapping records
*/
void createGeofenceEventMapping(int fenceId, List<Integer> eventIds) throws DeviceManagementDAOException;
/**
* Remove geofence-event mapping records
* @param removedEventIdList event ids should be removed from the records
* @throws DeviceManagementDAOException error occurred deleting geofence event mapping
*/
void deleteGeofenceEventMapping(List<Integer> removedEventIdList) throws DeviceManagementDAOException;
/**
* Get events of the geofence using fence ids
* @param geofenceIds ids of geo fences to be queried
* @return Event config list mapped with fence id
* @throws DeviceManagementDAOException error occurred while retrieving geo fence event map
*/
Map<Integer, List<EventConfig>> getEventsOfGeoFences(List<Integer> geofenceIds) throws DeviceManagementDAOException;
/**
* Get events of a particular geofence
* @param geofenceId id of the fence to be queried
* @return EventConfig list of the particular geofence
* @throws DeviceManagementDAOException thrown errors while getting events of geofence
*/
List<EventConfig> getEventsOfGeoFence(int geofenceId) throws DeviceManagementDAOException;
/**
* Get group Ids mapped with fence ids
* @param fenceIds fence id list to be queried
* @return GroupIds mapped with geofence id
* @throws DeviceManagementDAOException thrown errors while retrieving group Ids of geo fence
*/
Set<GeoFenceGroupMap> getGroupIdsOfGeoFences(List<Integer> fenceIds) throws DeviceManagementDAOException;
/**
* Get geo fences of the specific group and tenant
* @param groupId id of the group
* @param tenantId tenant id of the geo fences
* @return List of geofence data mapped with specific group and tenant
* @throws DeviceManagementDAOException
*/
List<GeofenceData> getGeoFences(int groupId, int tenantId) throws DeviceManagementDAOException;
/**
* Get geofence using fence id and attached group Ids
* @param fenceId id of the fence
* @param requireGroupData true if mapped group data needed
* @return Geofence data
* @throws DeviceManagementDAOException
*/
GeofenceData getGeofence(int fenceId, boolean requireGroupData) throws DeviceManagementDAOException;
}

@ -118,7 +118,8 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
try { try {
conn = this.getConnection(); conn = this.getConnection();
String sql = "UPDATE DM_DEVICE SET NAME = ?, DESCRIPTION = ?, LAST_UPDATED_TIMESTAMP = ? " + String sql = "UPDATE DM_DEVICE SET NAME = ?, DESCRIPTION = ?, LAST_UPDATED_TIMESTAMP = ? " +
"WHERE DEVICE_TYPE_ID = (SELECT ID FROM DM_DEVICE_TYPE WHERE NAME = ? AND (PROVIDER_TENANT_ID = ? OR SHARED_WITH_ALL_TENANTS = ?)) " + "WHERE DEVICE_TYPE_ID = (SELECT ID FROM DM_DEVICE_TYPE " +
"WHERE NAME = ? AND (PROVIDER_TENANT_ID = ? OR SHARED_WITH_ALL_TENANTS = ?)) " +
"AND DEVICE_IDENTIFICATION = ? AND TENANT_ID = ?"; "AND DEVICE_IDENTIFICATION = ? AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql, new String[]{"id"}); stmt = conn.prepareStatement(sql, new String[]{"id"});
stmt.setString(1, device.getName()); stmt.setString(1, device.getName());
@ -164,20 +165,14 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
+ "d.NAME, " + "d.NAME, "
+ "t.NAME AS DEVICE_TYPE, " + "t.NAME AS DEVICE_TYPE, "
+ "d.DEVICE_IDENTIFICATION " + "d.DEVICE_IDENTIFICATION "
+ "FROM DM_DEVICE d, DM_DEVICE_TYPE t"; + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE "
if (deviceData.getLastModifiedDate() != null) {
sql += ", DM_DEVICE_DETAIL dt";
}
sql += " WHERE "
+ "t.NAME = ? AND " + "t.NAME = ? AND "
+ "t.ID = d.DEVICE_TYPE_ID AND " + "t.ID = d.DEVICE_TYPE_ID AND "
+ "d.DEVICE_IDENTIFICATION = ? AND " + "d.DEVICE_IDENTIFICATION = ? AND "
+ "d.TENANT_ID = ?"; + "d.TENANT_ID = ?";
if (deviceData.getLastModifiedDate() != null) { if (deviceData.getLastModifiedDate() != null) {
sql += " AND dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?"; sql += " AND d.LAST_UPDATED_TIMESTAMP > ?";
} }
sql += ") d1 WHERE d1.ID = e.DEVICE_ID AND "; sql += ") d1 WHERE d1.ID = e.DEVICE_ID AND ";
@ -197,7 +192,7 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
stmt.setString(paramIndx++, deviceData.getDeviceIdentifier().getId()); stmt.setString(paramIndx++, deviceData.getDeviceIdentifier().getId());
stmt.setInt(paramIndx++, tenantId); stmt.setInt(paramIndx++, tenantId);
if (deviceData.getLastModifiedDate() != null) { if (deviceData.getLastModifiedDate() != null) {
stmt.setLong(paramIndx++, deviceData.getLastModifiedDate().getTime()); stmt.setTimestamp(paramIndx++, new Timestamp(deviceData.getLastModifiedDate().getTime()));
} }
if (!StringUtils.isBlank(deviceData.getDeviceOwner())) { if (!StringUtils.isBlank(deviceData.getDeviceOwner())) {
stmt.setString(paramIndx++, deviceData.getDeviceOwner()); stmt.setString(paramIndx++, deviceData.getDeviceOwner());
@ -354,15 +349,15 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
String sql = "SELECT d1.ID AS DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + String sql = "SELECT d1.ID AS DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " +
"d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.IS_TRANSFERRED, e.DATE_OF_LAST_UPDATE, " + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.IS_TRANSFERRED, e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, (SELECT d.ID, d.DESCRIPTION, d.NAME, " + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, (SELECT d.ID, d.DESCRIPTION, d.NAME, " +
"t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_DETAIL dt " + "t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION FROM DM_DEVICE d, DM_DEVICE_TYPE t " +
"WHERE t.NAME = ? AND t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? AND dt.DEVICE_ID = d.ID " + "WHERE t.NAME = ? AND t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? " +
"AND dt.UPDATE_TIMESTAMP > ?) d1 WHERE d1.ID = e.DEVICE_ID AND TENANT_ID = ? ORDER BY e.DATE_OF_LAST_UPDATE DESC"; "AND d.LAST_UPDATED_TIMESTAMP > ?) d1 WHERE d1.ID = e.DEVICE_ID AND TENANT_ID = ? ORDER BY e.DATE_OF_LAST_UPDATE DESC";
stmt = conn.prepareStatement(sql); stmt = conn.prepareStatement(sql);
int paramIdx = 1; int paramIdx = 1;
stmt.setString(paramIdx++, deviceIdentifier.getType()); stmt.setString(paramIdx++, deviceIdentifier.getType());
stmt.setString(paramIdx++, deviceIdentifier.getId()); stmt.setString(paramIdx++, deviceIdentifier.getId());
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
stmt.setInt(paramIdx, tenantId); stmt.setInt(paramIdx, tenantId);
rs = stmt.executeQuery(); rs = stmt.executeQuery();
if (rs.next()) { if (rs.next()) {
@ -549,11 +544,10 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
"(SELECT d.ID, d.DESCRIPTION, d.NAME, " + "(SELECT d.ID, d.DESCRIPTION, d.NAME, " +
"t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION " + "t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION " +
"FROM" + "FROM" +
" DM_DEVICE d, DM_DEVICE_TYPE t," + " DM_DEVICE d, DM_DEVICE_TYPE t " +
" DM_DEVICE_DETAIL dt " +
"WHERE " + "WHERE " +
"t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? AND" + "t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? AND" +
" dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?) d1 " + " d.LAST_UPDATED_TIMESTAMP > ?) d1 " +
"WHERE" + "WHERE" +
" d1.ID = e.DEVICE_ID AND TENANT_ID = ? " + " d1.ID = e.DEVICE_ID AND TENANT_ID = ? " +
"ORDER BY " + "ORDER BY " +
@ -562,7 +556,7 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
int paramIdx = 1; int paramIdx = 1;
stmt.setString(paramIdx++, deviceIdentifier); stmt.setString(paramIdx++, deviceIdentifier);
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
stmt.setInt(paramIdx, tenantId); stmt.setInt(paramIdx, tenantId);
rs = stmt.executeQuery(); rs = stmt.executeQuery();
if (rs.next()) { if (rs.next()) {
@ -589,14 +583,15 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
String sql = "SELECT d1.ID AS DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " + String sql = "SELECT d1.ID AS DEVICE_ID, d1.DESCRIPTION, d1.NAME AS DEVICE_NAME, d1.DEVICE_TYPE, " +
"d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.IS_TRANSFERRED, e.DATE_OF_LAST_UPDATE, " + "d1.DEVICE_IDENTIFICATION, e.OWNER, e.OWNERSHIP, e.STATUS, e.IS_TRANSFERRED, e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, (SELECT d.ID, d.DESCRIPTION, d.NAME, " + "e.DATE_OF_ENROLMENT, e.ID AS ENROLMENT_ID FROM DM_ENROLMENT e, (SELECT d.ID, d.DESCRIPTION, d.NAME, " +
"t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_DETAIL dt " + "t.NAME AS DEVICE_TYPE, d.DEVICE_IDENTIFICATION FROM DM_DEVICE d, DM_DEVICE_TYPE t " +
"WHERE t.NAME = ? AND t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? AND dt.DEVICE_ID = d.ID " + "WHERE t.NAME = ? AND t.ID = d.DEVICE_TYPE_ID AND d.DEVICE_IDENTIFICATION = ? AND d.TENANT_ID = ? " +
"AND dt.UPDATE_TIMESTAMP > ?) d1 WHERE d1.ID = e.DEVICE_ID AND TENANT_ID = ? AND e.OWNER = ? ORDER BY e.DATE_OF_LAST_UPDATE DESC"; "AND d.LAST_UPDATED_TIMESTAMP > ?) d1 WHERE d1.ID = e.DEVICE_ID AND TENANT_ID = ? AND e.OWNER = ? " +
"ORDER BY e.DATE_OF_LAST_UPDATE DESC";
stmt = conn.prepareStatement(sql); stmt = conn.prepareStatement(sql);
stmt.setString(1, deviceIdentifier.getType()); stmt.setString(1, deviceIdentifier.getType());
stmt.setString(2, deviceIdentifier.getId()); stmt.setString(2, deviceIdentifier.getId());
stmt.setInt(3, tenantId); stmt.setInt(3, tenantId);
stmt.setLong(4, since.getTime()); stmt.setTimestamp(4, new Timestamp(since.getTime()));
stmt.setInt(5, tenantId); stmt.setInt(5, tenantId);
stmt.setString(6, owner); stmt.setString(6, owner);
rs = stmt.executeQuery(); rs = stmt.executeQuery();
@ -971,16 +966,12 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
sql = sql + " AND d.NAME LIKE ?"; sql = sql + " AND d.NAME LIKE ?";
isDeviceNameProvided = true; isDeviceNameProvided = true;
} }
sql = sql + ") gd, DM_DEVICE_TYPE t"; sql = sql + ") gd, DM_DEVICE_TYPE t WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -1013,7 +1004,7 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
stmt.setString(paramIdx++, deviceName + "%"); stmt.setString(paramIdx++, deviceName + "%");
} }
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);
@ -1241,17 +1232,12 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
"t.NAME AS DEVICE_TYPE " + "t.NAME AS DEVICE_TYPE " +
"FROM " + "FROM " +
"DM_DEVICE d, " + "DM_DEVICE d, " +
"DM_DEVICE_TYPE t"; "DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add query for last updated timestamp //Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + " , DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?";
}
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
isDeviceTypeProvided = true; isDeviceTypeProvided = true;
@ -1282,7 +1268,7 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
int paramIdx = 1; int paramIdx = 1;
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, request.getDeviceType()); stmt.setString(paramIdx++, request.getDeviceType());
@ -1947,41 +1933,46 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
} }
} }
@Override public List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from,
public List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to) long to) throws DeviceManagementDAOException {
throws DeviceManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
ResultSet rs = null;
List<DeviceLocationHistorySnapshot> deviceLocationHistories = new ArrayList<>(); List<DeviceLocationHistorySnapshot> deviceLocationHistories = new ArrayList<>();
String sql = "SELECT "
+ "DEVICE_ID, "
+ "TENANT_ID, "
+ "DEVICE_ID_NAME, "
+ "DEVICE_TYPE_NAME, "
+ "LATITUDE, "
+ "LONGITUDE, "
+ "SPEED, "
+ "HEADING, "
+ "TIMESTAMP, "
+ "GEO_HASH, "
+ "DEVICE_OWNER, "
+ "DEVICE_ALTITUDE, "
+ "DISTANCE "
+ "FROM DM_DEVICE_HISTORY_LAST_SEVEN_DAYS "
+ "WHERE "
+ "DEVICE_ID_NAME = ? AND "
+ "DEVICE_TYPE_NAME = ? AND "
+ "TIMESTAMP BETWEEN ? AND ? "
+ "ORDER BY timestamp";
try { try {
conn = this.getConnection(); Connection conn = this.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
String sql = stmt.setString(1, deviceIdentifier.getId());
"SELECT DEVICE_ID, TENANT_ID, DEVICE_ID_NAME, DEVICE_TYPE_NAME, LATITUDE, LONGITUDE, SPEED, " + stmt.setString(2, deviceIdentifier.getType());
"HEADING, TIMESTAMP, GEO_HASH, DEVICE_OWNER, DEVICE_ALTITUDE, DISTANCE " + stmt.setLong(3, from);
"FROM DM_DEVICE_HISTORY_LAST_SEVEN_DAYS " + stmt.setLong(4, to);
"WHERE DEVICE_ID_NAME = ? " + try (ResultSet rs = stmt.executeQuery()) {
"AND DEVICE_TYPE_NAME = ? " + while (rs.next()) {
"AND TIMESTAMP >= ? " + deviceLocationHistories.add(DeviceManagementDAOUtil.loadDeviceLocation(rs));
"AND TIMESTAMP <= ?"; }
}
stmt = conn.prepareStatement(sql);
stmt.setString(1, deviceIdentifier.getId());
stmt.setString(2, deviceIdentifier.getType());
stmt.setLong(3, from);
stmt.setLong(4, to);
rs = stmt.executeQuery();
while (rs.next()) {
deviceLocationHistories.add(DeviceManagementDAOUtil.loadDeviceLocation(rs));
} }
} catch (SQLException e) { } catch (SQLException e) {
String errMessage = "Error occurred while obtaining the DB connection to get device location information"; String msg = "Error occurred while obtaining the DB connection to get device location information";
log.error(errMessage, e); log.error(msg, e);
throw new DeviceManagementDAOException(errMessage, e); throw new DeviceManagementDAOException(msg, e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, rs);
} }
return deviceLocationHistories; return deviceLocationHistories;
} }

@ -0,0 +1,329 @@
/*
* Copyright (c) 2020, 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.core.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.EventConfigDAO;
import org.wso2.carbon.device.mgt.core.dao.EventManagementDAOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class AbstractEventConfigDAO implements EventConfigDAO {
private static final Log log = LogFactory.getLog(AbstractEventConfigDAO.class);
@Override
public boolean addEventGroupMappingRecords(List<Integer> eventIds, List<Integer> groupIds) throws EventManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "INSERT INTO DM_DEVICE_EVENT_GROUP_MAPPING(" +
"EVENT_ID ," +
"GROUP_ID) " +
"VALUES (?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer groupId : groupIds) {
for (Integer eventId : eventIds) {
stmt.setInt(1, eventId);
stmt.setInt(2, groupId);
stmt.addBatch();
}
}
return stmt.executeBatch().length > 0;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public List<EventConfig> getEventsOfGroups(List<Integer> groupIds, int tenantId) throws EventManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS " +
"FROM DM_DEVICE_EVENT E, DM_DEVICE_EVENT_GROUP_MAPPING G " +
"WHERE G.EVENT_ID = E.ID " +
"AND G.GROUP_ID IN (%s) " +
"AND E.TENANT_ID = ? " +
"GROUP BY E.ID";
String inClause = String.join(", ", Collections.nCopies(groupIds.size(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer groupId : groupIds) {
stmt.setInt(index++, groupId);
}
stmt.setInt(index, tenantId);
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
EventConfig event = new EventConfig();
event.setEventId(rst.getInt("EVENT_ID"));
event.setEventSource(rst.getString("EVENT_SOURCE"));
event.setEventLogic(rst.getString("EVENT_LOGIC"));
event.setActions(rst.getString("ACTIONS"));
eventList.add(event);
}
return eventList;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public List<EventConfig> getEventsOfGroups(int groupId, int tenantId) throws EventManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS " +
"FROM DM_DEVICE_EVENT E, DM_DEVICE_EVENT_GROUP_MAPPING G " +
"WHERE G.EVENT_ID = E.ID " +
"AND G.GROUP_ID = ? " +
"AND E.TENANT_ID = ? " +
"GROUP BY E.ID";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
EventConfig event = new EventConfig();
event.setEventId(rst.getInt("EVENT_ID"));
event.setEventSource(rst.getString("EVENT_SOURCE"));
event.setEventLogic(rst.getString("EVENT_LOGIC"));
event.setActions(rst.getString("ACTIONS"));
eventList.add(event);
}
return eventList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving event records of group " + groupId
+ " and tenant " + tenantId;
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public void deleteEventGroupMappingRecordsByEventIds(List<Integer> eventsIdsToDelete) throws EventManagementDAOException {
try {
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(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer eventId : eventsIdsToDelete) {
stmt.setInt(index++, eventId);
}
stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public void deleteEventGroupMappingRecordsByGroupIds(List<Integer> groupIdsToDelete) throws EventManagementDAOException {
try {
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(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer groupId : groupIdsToDelete) {
stmt.setInt(index++, groupId);
stmt.addBatch();
}
stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public void updateEventRecords(List<EventConfig> eventsToUpdate) throws EventManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "UPDATE DM_DEVICE_EVENT SET " +
"ACTIONS = ? " +
"WHERE ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (EventConfig updatingEvent : eventsToUpdate) {
stmt.setString(1, updatingEvent.getActions());
stmt.setInt(2, updatingEvent.getEventId());
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while updating event records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public void deleteEventRecords(List<Integer> eventsIdsToDelete) throws EventManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_DEVICE_EVENT WHERE ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer eventId : eventsIdsToDelete) {
stmt.setInt(1, eventId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting event records of tenant";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public List<EventConfig> getEventsById(List<Integer> eventIdList) throws EventManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"ID AS EVENT_ID, " +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS " +
"FROM DM_DEVICE_EVENT " +
"WHERE ID IN (%s) ";
String inClause = String.join(", ", Collections.nCopies(eventIdList.size(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer eventId : eventIdList) {
if (eventId != -1) {
stmt.setInt(index++, eventId);
}
}
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
EventConfig event = new EventConfig();
event.setEventId(rst.getInt("EVENT_ID"));
event.setEventSource(rst.getString("EVENT_SOURCE"));
event.setEventLogic(rst.getString("EVENT_LOGIC"));
event.setActions(rst.getString("ACTIONS"));
eventList.add(event);
}
return eventList;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public List<Integer> getGroupsOfEvents(List<Integer> eventIdList) throws EventManagementDAOException {
try {
List<Integer> groupIdList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"GROUP_ID " +
"FROM DM_DEVICE_EVENT_GROUP_MAPPING " +
"WHERE EVENT_ID IN (%s) " +
"GROUP BY GROUP_ID";
String inClause = String.join(", ", Collections.nCopies(eventIdList.size(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer eventId : eventIdList) {
if (eventId != -1) {
stmt.setInt(index++, eventId);
}
}
ResultSet resultSet = stmt.executeQuery();
while (resultSet.next()) {
groupIdList.add(resultSet.getInt("GROUP_ID"));
}
return groupIdList;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event group mapping records";
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
@Override
public List<String> getEventSourcesOfGroups(int groupId, int tenantId) throws EventManagementDAOException {
try {
List<String> eventSourceList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"EVENT_SOURCE " +
"FROM DM_DEVICE_EVENT E, DM_DEVICE_EVENT_GROUP_MAPPING G " +
"WHERE G.EVENT_ID = E.ID " +
"AND G.GROUP_ID = ? " +
"AND E.TENANT_ID = ? " +
"GROUP BY EVENT_SOURCE";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
eventSourceList.add(rst.getString("EVENT_SOURCE"));
}
return eventSourceList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving event records of group " + groupId
+ " and tenant " + tenantId;
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
private Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection();
}
}

@ -0,0 +1,640 @@
/*
* Copyright (c) 2020, 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.core.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.geo.service.GeofenceData;
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.GeofenceDAO;
import org.wso2.carbon.device.mgt.core.dto.event.config.GeoFenceGroupMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class GeofenceDAOImpl implements GeofenceDAO {
private static final Log log = LogFactory.getLog(GeofenceDAOImpl.class);
@Override
public GeofenceData saveGeofence(GeofenceData geofenceData) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "INSERT INTO DM_GEOFENCE(" +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"CREATED_TIMESTAMP, " +
"OWNER, " +
"TENANT_ID) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
stmt.setString(1, geofenceData.getFenceName());
stmt.setString(2, geofenceData.getDescription());
stmt.setDouble(3, geofenceData.getLatitude());
stmt.setDouble(4, geofenceData.getLongitude());
stmt.setFloat(5, geofenceData.getRadius());
stmt.setString(6, geofenceData.getGeoJson());
stmt.setString(7, geofenceData.getFenceShape());
stmt.setTimestamp(8, new Timestamp(new Date().getTime()));
stmt.setString(9, geofenceData.getOwner());
stmt.setInt(10, geofenceData.getTenantId());
if (stmt.executeUpdate() > 0) {
ResultSet generatedKeys = stmt.getGeneratedKeys();
if (generatedKeys.next()) {
geofenceData.setId(generatedKeys.getInt(1));
}
}
return geofenceData;
}
} catch (SQLException e) {
String msg = "Error occurred while creating Geofence for the tenant id "+geofenceData.getTenantId();
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public GeofenceData getGeofence(int fenceId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
GeofenceData geofenceData = null;
String sql = "SELECT " +
"ID, " +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"OWNER, " +
"TENANT_ID " +
"FROM DM_GEOFENCE " +
"WHERE ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, fenceId);
try (ResultSet rst = stmt.executeQuery()) {
List<GeofenceData> geofenceDataList = extractGeofenceData(rst);
if (!geofenceDataList.isEmpty()) {
geofenceData = geofenceDataList.get(0);
}
}
}
return geofenceData;
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geofence with id "+fenceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public List<GeofenceData> getGeoFencesOfTenant(PaginationRequest request, int tenantId)
throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
boolean isNameProvided = false;
List<GeofenceData> geofenceData;
String sql = "SELECT " +
"ID, " +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"OWNER, " +
"TENANT_ID " +
"FROM DM_GEOFENCE " +
"WHERE TENANT_ID = ? ";
if (request.getProperty(DeviceManagementConstants.GeoServices.FENCE_NAME) != null) {
sql += "AND FENCE_NAME LIKE ?";
isNameProvided = true;
}
sql += "LIMIT ? OFFSET ?";
int index = 1;
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(index++, tenantId);
if (isNameProvided) {
stmt.setString(index++, request.getProperty(DeviceManagementConstants.GeoServices.FENCE_NAME).toString() + "%");
}
stmt.setInt(index++, request.getRowCount());
stmt.setInt(index, request.getStartIndex());
try (ResultSet rst = stmt.executeQuery()) {
geofenceData = extractGeofenceData(rst);
}
}
return geofenceData;
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geofence of the tenant " + tenantId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public List<GeofenceData> getGeoFencesOfTenant(String fenceName, int tenantId)
throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
List<GeofenceData> geofenceData;
String sql = "SELECT " +
"ID, " +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"OWNER, " +
"TENANT_ID " +
"FROM DM_GEOFENCE " +
"WHERE FENCE_NAME LIKE ?" +
"AND TENANT_ID = ? ";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, fenceName + "%");
stmt.setInt(2, tenantId);
try (ResultSet rst = stmt.executeQuery()) {
geofenceData = extractGeofenceData(rst);
}
}
return geofenceData;
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geofence of the tenant " + tenantId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public List<GeofenceData> getGeoFencesOfTenant(int tenantId)
throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
List<GeofenceData> geofenceData;
String sql = "SELECT " +
"ID, " +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"OWNER, " +
"TENANT_ID " +
"FROM DM_GEOFENCE " +
"WHERE TENANT_ID = ? ";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
try (ResultSet rst = stmt.executeQuery()) {
geofenceData = extractGeofenceData(rst);
}
}
return geofenceData;
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geofence of the tenant " + tenantId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public int deleteGeofenceById(int fenceId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_GEOFENCE WHERE ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, fenceId);
return stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting Geofence with ID " + fenceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public int updateGeofence(GeofenceData geofenceData, int fenceId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "UPDATE DM_GEOFENCE SET " +
"FENCE_NAME = ?, " +
"DESCRIPTION = ?, " +
"LATITUDE = ?, " +
"LONGITUDE = ?, " +
"RADIUS = ?, " +
"GEO_JSON = ?, " +
"FENCE_SHAPE = ? " +
"WHERE ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, geofenceData.getFenceName());
stmt.setString(2, geofenceData.getDescription());
stmt.setDouble(3, geofenceData.getLatitude());
stmt.setDouble(4, geofenceData.getLongitude());
stmt.setFloat(5, geofenceData.getRadius());
stmt.setString(6, geofenceData.getGeoJson());
stmt.setString(7, geofenceData.getFenceShape());
stmt.setInt(8, fenceId);
return stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while updating Geofence record with id " + fenceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public boolean createGeofenceGroupMapping(GeofenceData geofenceData, List<Integer> groupIds) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "INSERT INTO DM_GEOFENCE_GROUP_MAPPING(" +
"FENCE_ID, " +
"GROUP_ID) " +
"VALUES (?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer groupId : groupIds) {
stmt.setInt(1, geofenceData.getId());
stmt.setInt(2, groupId);
stmt.addBatch();
}
return stmt.executeBatch().length > 0;
}
} catch (SQLException e) {
String msg = "Error occurred while creating geofence group mapping records";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
private Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection();
}
private List<GeofenceData> extractGeofenceData(ResultSet rst) throws SQLException {
List <GeofenceData> geofenceDataList = new ArrayList<>();
while (rst.next()) {
GeofenceData geofenceData = new GeofenceData();
geofenceData.setId(rst.getInt("ID"));
geofenceData.setFenceName(rst.getString("FENCE_NAME"));
geofenceData.setDescription(rst.getString("DESCRIPTION"));
geofenceData.setLatitude(rst.getDouble("LATITUDE"));
geofenceData.setLongitude(rst.getDouble("LONGITUDE"));
geofenceData.setRadius(rst.getFloat("RADIUS"));
geofenceData.setGeoJson(rst.getString("GEO_JSON"));
geofenceData.setFenceShape(rst.getString("FENCE_SHAPE"));
geofenceData.setOwner(rst.getString("OWNER"));
geofenceData.setTenantId(rst.getInt("TENANT_ID"));
geofenceDataList.add(geofenceData);
}
return geofenceDataList;
}
@Override
public List<Integer> getGroupIdsOfGeoFence(int fenceId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "SELECT " +
"GROUP_ID " +
"FROM DM_GEOFENCE_GROUP_MAPPING " +
"WHERE FENCE_ID = ? ";
List<Integer> groupIds = new ArrayList<>();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, fenceId);
try (ResultSet rst = stmt.executeQuery()) {
while (rst.next()) {
groupIds.add(rst.getInt(1));
}
}
}
return groupIds;
} catch (SQLException e) {
String msg = "Error occurred while fetching group IDs of the fence " + fenceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public void deleteGeofenceGroupMapping(List<Integer> groupIdsToDelete) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_GEOFENCE_GROUP_MAPPING WHERE GROUP_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer groupId : groupIdsToDelete) {
stmt.setInt(1, groupId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting Geofence group mapping records";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public void createGeofenceEventMapping(int fenceId, List<Integer> eventIds) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "INSERT INTO DM_GEOFENCE_EVENT_MAPPING(" +
"FENCE_ID, "+
"EVENT_ID) " +
"VALUES (?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer createdEventId : eventIds) {
stmt.setInt(1, fenceId);
stmt.setInt(2, createdEventId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while creating geofence event group mapping records";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public void deleteGeofenceEventMapping(List<Integer> removedEventIdList) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "DELETE FROM DM_GEOFENCE_EVENT_MAPPING WHERE EVENT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (Integer eventId : removedEventIdList) {
stmt.setInt(1, eventId);
stmt.addBatch();
}
stmt.executeBatch();
}
} catch (SQLException e) {
String msg = "Error occurred while deleting Geofence event mapping records";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public Map<Integer, List<EventConfig>> getEventsOfGeoFences(List<Integer> geofenceIds) throws DeviceManagementDAOException {
try {
Map<Integer, List<EventConfig>> geoFenceEventMap = new HashMap<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
"M.FENCE_ID AS FENCE_ID, " +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS " +
"FROM DM_DEVICE_EVENT E, DM_GEOFENCE_EVENT_MAPPING M " +
"WHERE E.ID = M.EVENT_ID " +
"AND M.FENCE_ID IN (%s)";
String inClause = String.join(", ", Collections.nCopies(geofenceIds.size(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer geofenceId : geofenceIds) {
stmt.setInt(index++, geofenceId);
}
ResultSet resultSet = stmt.executeQuery();
while (resultSet.next()) {
int fenceId = resultSet.getInt("FENCE_ID");
List<EventConfig> eventConfigList = geoFenceEventMap.get(fenceId);
if (eventConfigList == null) {
eventConfigList = new ArrayList<>();
}
EventConfig event = new EventConfig();
event.setEventId(resultSet.getInt("EVENT_ID"));
event.setEventSource(resultSet.getString("EVENT_SOURCE"));
event.setEventLogic(resultSet.getString("EVENT_LOGIC"));
event.setActions(resultSet.getString("ACTIONS"));
eventConfigList.add(event);
geoFenceEventMap.put(fenceId, eventConfigList);
}
return geoFenceEventMap;
}
} catch (SQLException e) {
String msg = "Error occurred while updating Geofence record with id ";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public List<EventConfig> getEventsOfGeoFence(int geofenceId) throws DeviceManagementDAOException {
try {
List<EventConfig> eventList = new ArrayList<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"E.ID AS EVENT_ID, " +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS " +
"FROM DM_DEVICE_EVENT E, DM_GEOFENCE_EVENT_MAPPING G " +
"WHERE E.ID = G.EVENT_ID " +
"AND G.FENCE_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, geofenceId);
return getEventConfigs(stmt);
}
} catch (SQLException e) {
String msg = "Error occurred while updating Geofence record with id ";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public Set<GeoFenceGroupMap> getGroupIdsOfGeoFences(List<Integer> fenceIds) throws DeviceManagementDAOException {
try {
Set<GeoFenceGroupMap> geoFenceGroupSet = new HashSet<>();
Connection conn = this.getConnection();
String sql = "SELECT " +
"FENCE_ID, " +
"M.GROUP_ID, " +
"G.GROUP_NAME " +
"FROM DM_GEOFENCE_GROUP_MAPPING M, DM_GROUP G " +
"WHERE M.GROUP_ID = G.ID " +
"AND FENCE_ID IN (%s)";
String inClause = String.join(", ", Collections.nCopies(fenceIds.size(), "?"));
sql = String.format(sql, inClause);
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int index = 1;
for (Integer fenceId : fenceIds) {
stmt.setInt(index++, fenceId);
}
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
GeoFenceGroupMap geoFenceGroupMap = new GeoFenceGroupMap();
geoFenceGroupMap.setFenceId(rst.getInt("FENCE_ID"));
geoFenceGroupMap.setGroupId(rst.getInt("GROUP_ID"));
geoFenceGroupMap.setGroupName(rst.getString("GROUP_NAME"));
geoFenceGroupSet.add(geoFenceGroupMap);
}
}
return geoFenceGroupSet;
} catch (SQLException e) {
String msg = "Error occurred while fetching group IDs of the fences";
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
/**
* Retrieve the geofence event extracted from the DB
* @param stmt prepared statement to retrieve data from the DB
* @return Retrieved Event list from the DB
* @throws SQLException for the errors occur while accessing the DB
*/
private List<EventConfig> getEventConfigs(PreparedStatement stmt) throws SQLException {
List<EventConfig> eventList = new ArrayList<>();
ResultSet resultSet = stmt.executeQuery();
EventConfig event;
while (resultSet.next()) {
event = new EventConfig();
event.setEventId(resultSet.getInt("EVENT_ID"));
event.setEventSource(resultSet.getString("EVENT_SOURCE"));
event.setEventLogic(resultSet.getString("EVENT_LOGIC"));
event.setActions(resultSet.getString("ACTIONS"));
eventList.add(event);
}
return eventList;
}
@Override
public List<GeofenceData> getGeoFences(int groupId, int tenantId) throws DeviceManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "SELECT " +
"G.ID AS FENCE_ID, " +
"FENCE_NAME, " +
"DESCRIPTION, " +
"LATITUDE," +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE " +
"FROM DM_GEOFENCE G, DM_GEOFENCE_GROUP_MAPPING M " +
"WHERE M.GROUP_ID = ? AND TENANT_ID = ? " +
"GROUP BY G.ID";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, groupId);
stmt.setInt(2, tenantId);
ResultSet rst = stmt.executeQuery();
List <GeofenceData> geofenceDataList = new ArrayList<>();
while (rst.next()) {
GeofenceData geofenceData = new GeofenceData();
geofenceData.setId(rst.getInt("FENCE_ID"));
geofenceData.setFenceName(rst.getString("FENCE_NAME"));
geofenceData.setDescription(rst.getString("DESCRIPTION"));
geofenceData.setLatitude(rst.getDouble("LATITUDE"));
geofenceData.setLongitude(rst.getDouble("LONGITUDE"));
geofenceData.setRadius(rst.getFloat("RADIUS"));
geofenceData.setGeoJson(rst.getString("GEO_JSON"));
geofenceData.setFenceShape(rst.getString("FENCE_SHAPE"));
geofenceDataList.add(geofenceData);
}
return geofenceDataList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geo fences of group " + groupId
+ " and tenant " + tenantId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
@Override
public GeofenceData getGeofence(int fenceId, boolean requireGroupData) throws DeviceManagementDAOException {
if (!requireGroupData) {
return getGeofence(fenceId);
}
try {
Connection con = this.getConnection();
String sql = "SELECT " +
"G.ID AS FENCE_ID, " +
"FENCE_NAME, " +
"G.DESCRIPTION, " +
"LATITUDE, " +
"LONGITUDE, " +
"RADIUS, " +
"GEO_JSON, " +
"FENCE_SHAPE, " +
"M.GROUP_ID AS GROUP_ID, " +
"GR.GROUP_NAME " +
"FROM DM_GEOFENCE G, DM_GEOFENCE_GROUP_MAPPING M, DM_GROUP GR " +
"WHERE G.ID = M.FENCE_ID " +
"AND M.GROUP_ID = GR.ID " +
"AND G.ID = ?";
try (PreparedStatement stmt = con.prepareStatement(sql)){
stmt.setInt(1, fenceId);
ResultSet rst = stmt.executeQuery();
Map<Integer, String> groupMap = new HashMap<>();
GeofenceData geofenceData = null;
while (rst.next()) {
groupMap.put(rst.getInt("GROUP_ID"), rst.getString("GROUP_NAME"));
if (rst.isLast()) {
geofenceData = new GeofenceData();
geofenceData.setId(rst.getInt("FENCE_ID"));
geofenceData.setFenceName(rst.getString("FENCE_NAME"));
geofenceData.setDescription(rst.getString("DESCRIPTION"));
geofenceData.setLatitude(rst.getDouble("LATITUDE"));
geofenceData.setLongitude(rst.getDouble("LONGITUDE"));
geofenceData.setRadius(rst.getFloat("RADIUS"));
geofenceData.setGeoJson(rst.getString("GEO_JSON"));
geofenceData.setFenceShape(rst.getString("FENCE_SHAPE"));
geofenceData.setGroupData(groupMap);
}
}
return geofenceData;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving Geo fence data " + fenceId;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
}
}
}

@ -30,14 +30,13 @@ 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.DeviceManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.impl.AbstractDeviceDAOImpl; import org.wso2.carbon.device.mgt.core.dao.impl.AbstractDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
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.report.mgt.Constants; import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -90,15 +89,12 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
"d.DEVICE_IDENTIFICATION, " + "d.DEVICE_IDENTIFICATION, " +
"t.NAME AS DEVICE_TYPE " + "t.NAME AS DEVICE_TYPE " +
"FROM DM_DEVICE d, DM_DEVICE_TYPE t "; "FROM DM_DEVICE d, DM_DEVICE_TYPE t ";
//Add the query to filter active devices on timestamp
if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt";
isSinceProvided = true;
}
sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?"; sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add query for last updated timestamp //Add query for last updated timestamp
if (isSinceProvided) { if (since != null) {
sql = sql + " AND dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true;
} }
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
@ -134,7 +130,7 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
int paramIdx = 1; int paramIdx = 1;
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);
@ -369,14 +365,11 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
isDeviceNameProvided = true; isDeviceNameProvided = true;
} }
sql = sql + ") gd, DM_DEVICE_TYPE t"; sql = sql + ") gd, DM_DEVICE_TYPE t";
if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt";
isSinceProvided = true;
}
sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID"; sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp //Add query for last updated timestamp
if (isSinceProvided) { if (since != null) {
sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true;
} }
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
@ -411,7 +404,7 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, deviceName + "%"); stmt.setString(paramIdx++, deviceName + "%");
} }
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);

@ -36,6 +36,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -89,17 +90,12 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
"d.DEVICE_IDENTIFICATION, " + "d.DEVICE_IDENTIFICATION, " +
"t.NAME AS DEVICE_TYPE " + "t.NAME AS DEVICE_TYPE " +
"FROM DM_DEVICE d, " + "FROM DM_DEVICE d, " +
"DM_DEVICE_TYPE t "; "DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add the query to filter active devices on timestamp //Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -134,7 +130,7 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
int paramIdx = 1; int paramIdx = 1;
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);
@ -373,16 +369,12 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
sql = sql + " AND d.NAME LIKE ?"; sql = sql + " AND d.NAME LIKE ?";
isDeviceNameProvided = true; isDeviceNameProvided = true;
} }
sql = sql + ") gd, DM_DEVICE_TYPE t"; sql = sql + ") gd, DM_DEVICE_TYPE t WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -416,7 +408,7 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, deviceName + "%"); stmt.setString(paramIdx++, deviceName + "%");
} }
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);

@ -35,6 +35,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -348,16 +349,12 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
sql = sql + " AND d.NAME LIKE ?"; sql = sql + " AND d.NAME LIKE ?";
isDeviceNameProvided = true; isDeviceNameProvided = true;
} }
sql = sql + ") gd, DM_DEVICE_TYPE t"; sql = sql + ") gd, DM_DEVICE_TYPE t WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -391,7 +388,7 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, deviceName + "%"); stmt.setString(paramIdx++, deviceName + "%");
} }
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);

@ -37,6 +37,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -89,17 +90,12 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
"d.NAME, " + "d.NAME, " +
"d.DEVICE_IDENTIFICATION, " + "d.DEVICE_IDENTIFICATION, " +
"t.NAME AS DEVICE_TYPE " + "t.NAME AS DEVICE_TYPE " +
"FROM DM_DEVICE d, DM_DEVICE_TYPE t "; "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add the query to filter active devices on timestamp //Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ?";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = d.ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -134,7 +130,7 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
int paramIdx = 1; int paramIdx = 1;
stmt.setInt(paramIdx++, tenantId); stmt.setInt(paramIdx++, tenantId);
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);
@ -371,16 +367,12 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
sql = sql + " AND d.NAME LIKE ?"; sql = sql + " AND d.NAME LIKE ?";
isDeviceNameProvided = true; isDeviceNameProvided = true;
} }
sql = sql + ") gd, DM_DEVICE_TYPE t"; sql = sql + ") gd, DM_DEVICE_TYPE t WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (since != null) { if (since != null) {
sql = sql + ", DM_DEVICE_DETAIL dt"; sql = sql + " AND d.LAST_UPDATED_TIMESTAMP > ?";
isSinceProvided = true; isSinceProvided = true;
} }
sql = sql + " WHERE gd.DEVICE_TYPE_ID = t.ID";
//Add query for last updated timestamp
if (isSinceProvided) {
sql = sql + " AND dt.DEVICE_ID = gd.DEVICE_ID AND dt.UPDATE_TIMESTAMP > ?";
}
//Add the query for device-type //Add the query for device-type
if (deviceType != null && !deviceType.isEmpty()) { if (deviceType != null && !deviceType.isEmpty()) {
sql = sql + " AND t.NAME = ?"; sql = sql + " AND t.NAME = ?";
@ -414,7 +406,7 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, deviceName + "%"); stmt.setString(paramIdx++, deviceName + "%");
} }
if (isSinceProvided) { if (isSinceProvided) {
stmt.setLong(paramIdx++, since.getTime()); stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
} }
if (isDeviceTypeProvided) { if (isDeviceTypeProvided) {
stmt.setString(paramIdx++, deviceType); stmt.setString(paramIdx++, deviceType);

@ -0,0 +1,83 @@
/*
* Copyright (c) 2020, 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.core.dao.impl.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.EventConfigDAO;
import org.wso2.carbon.device.mgt.core.dao.EventManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.impl.AbstractEventConfigDAO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class GenericEventConfigDAOImpl extends AbstractEventConfigDAO {
private static final Log log = LogFactory.getLog(GenericEventConfigDAOImpl.class);
@Override
public List<Integer> storeEventRecords(List<EventConfig> eventConfigList, int tenantId) throws EventManagementDAOException {
try {
Connection conn = this.getConnection();
String sql = "INSERT INTO DM_DEVICE_EVENT(" +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS, "+
"CREATED_TIMESTAMP, " +
"TENANT_ID) " +
"VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
for (EventConfig eventConfig : eventConfigList) {
stmt.setString(1, eventConfig.getEventSource());
stmt.setString(2, eventConfig.getEventLogic());
stmt.setString(3, eventConfig.getActions());
stmt.setTimestamp(4, new Timestamp(new Date().getTime()));
stmt.setInt(5, tenantId);
stmt.addBatch();
}
int[] createdRowCount = stmt.executeBatch();
List<Integer> generatedIds = new ArrayList<>();
ResultSet generatedKeys = stmt.getGeneratedKeys();
for (int i = 0; i < createdRowCount.length; i++) {
if (generatedKeys.next()) {
generatedIds.add(generatedKeys.getInt(1));
}
}
return generatedIds;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event configurations for the tenant id " + tenantId;
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
private Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection();
}
}

@ -0,0 +1,80 @@
/*
* Copyright (c) 2020, 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.core.dao.impl.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.EventManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.impl.AbstractEventConfigDAO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class H2EventConfigDAOImpl extends AbstractEventConfigDAO {
private static final Log log = LogFactory.getLog(H2EventConfigDAOImpl.class);
@Override
public List<Integer> storeEventRecords(List<EventConfig> eventConfigList, int tenantId) throws EventManagementDAOException {
try {
Connection conn = this.getConnection();
List<Integer> generatedIds = new ArrayList<>();
String sql = "INSERT INTO DM_DEVICE_EVENT(" +
"EVENT_SOURCE, " +
"EVENT_LOGIC, " +
"ACTIONS, "+
"CREATED_TIMESTAMP, " +
"TENANT_ID) " +
"VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
for (EventConfig eventConfig : eventConfigList) {
stmt.setString(1, eventConfig.getEventSource());
stmt.setString(2, eventConfig.getEventLogic());
stmt.setString(3, eventConfig.getActions());
stmt.setTimestamp(4, new Timestamp(new Date().getTime()));
stmt.setInt(5, tenantId);
int affectedRawCount = stmt.executeUpdate();
if (affectedRawCount > 0) {
ResultSet generatedKeys = stmt.getGeneratedKeys();
if (generatedKeys.next()) {
generatedIds.add(generatedKeys.getInt(1));
}
}
}
return generatedIds;
}
} catch (SQLException e) {
String msg = "Error occurred while creating event configurations for the tenant id " + tenantId;
log.error(msg, e);
throw new EventManagementDAOException(msg, e);
}
}
private Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection();
}
}

@ -129,26 +129,4 @@ public interface DeviceDetailsDAO {
void updateDeviceInformation(int deviceId, int enrollmentId, DeviceInfo newDeviceInfo) throws DeviceDetailsMgtDAOException; void updateDeviceInformation(int deviceId, int enrollmentId, DeviceInfo newDeviceInfo) throws DeviceDetailsMgtDAOException;
void updateDeviceLocation(DeviceLocation deviceLocation, int enrollmentId) throws DeviceDetailsMgtDAOException; void updateDeviceLocation(DeviceLocation deviceLocation, int enrollmentId) throws DeviceDetailsMgtDAOException;
// /**
// * This method will add device application to database.
// * @param deviceApplication - Device application
// * @throws DeviceDetailsMgtDAOException
// */
// void addDeviceApplications(DeviceApplication deviceApplication) throws DeviceDetailsMgtDAOException;
//
// /**
// * This method will return the device application list once device id is provided.
// * @param deviceId
// * @return
// * @throws DeviceDetailsMgtDAOException
// */
// DeviceApplication getDeviceApplications(int deviceId) throws DeviceDetailsMgtDAOException;
//
// /**
// * This method will delete the application list from the database.
// * @param deviceId - Integer
// * @throws DeviceDetailsMgtDAOException
// */
// void deleteDeviceApplications(int deviceId) throws DeviceDetailsMgtDAOException;
} }

@ -41,7 +41,7 @@ import java.util.Map;
public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
private static Log log = LogFactory.getLog(DeviceDetailsDAOImpl.class); private static final Log log = LogFactory.getLog(DeviceDetailsDAOImpl.class);
@Override @Override
public void addDeviceInformation(int deviceId, int enrolmentId, DeviceInfo deviceInfo) public void addDeviceInformation(int deviceId, int enrolmentId, DeviceInfo deviceInfo)
@ -168,8 +168,6 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
rs = stmt.executeQuery(); rs = stmt.executeQuery();
if (rs.next()) { if (rs.next()) {
// deviceInfo.setIMEI(rs.getString("IMEI"));
// deviceInfo.setIMSI(rs.getString("IMSI"));
deviceInfo = new DeviceInfo(); deviceInfo = new DeviceInfo();
deviceInfo.setDeviceModel(rs.getString("DEVICE_MODEL")); deviceInfo.setDeviceModel(rs.getString("DEVICE_MODEL"));
deviceInfo.setVendor(rs.getString("VENDOR")); deviceInfo.setVendor(rs.getString("VENDOR"));
@ -180,9 +178,7 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
deviceInfo.setInternalAvailableMemory(rs.getDouble("INTERNAL_AVAILABLE_MEMORY")); deviceInfo.setInternalAvailableMemory(rs.getDouble("INTERNAL_AVAILABLE_MEMORY"));
deviceInfo.setExternalTotalMemory(rs.getDouble("EXTERNAL_TOTAL_MEMORY")); deviceInfo.setExternalTotalMemory(rs.getDouble("EXTERNAL_TOTAL_MEMORY"));
deviceInfo.setExternalAvailableMemory(rs.getDouble("EXTERNAL_AVAILABLE_MEMORY")); deviceInfo.setExternalAvailableMemory(rs.getDouble("EXTERNAL_AVAILABLE_MEMORY"));
// deviceInfo.setOperator(rs.getString("OPERATOR"));
deviceInfo.setConnectionType(rs.getString("CONNECTION_TYPE")); deviceInfo.setConnectionType(rs.getString("CONNECTION_TYPE"));
// deviceInfo.setMobileSignalStrength(rs.getDouble("MOBILE_SIGNAL_STRENGTH"));
deviceInfo.setSsid(rs.getString("SSID")); deviceInfo.setSsid(rs.getString("SSID"));
deviceInfo.setCpuUsage(rs.getDouble("CPU_USAGE")); deviceInfo.setCpuUsage(rs.getDouble("CPU_USAGE"));
deviceInfo.setTotalRAMMemory(rs.getDouble("TOTAL_RAM_MEMORY")); deviceInfo.setTotalRAMMemory(rs.getDouble("TOTAL_RAM_MEMORY"));
@ -190,7 +186,6 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
deviceInfo.setPluggedIn(rs.getBoolean("PLUGGED_IN")); deviceInfo.setPluggedIn(rs.getBoolean("PLUGGED_IN"));
deviceInfo.setUpdatedTime(new java.util.Date(rs.getLong("UPDATE_TIMESTAMP"))); deviceInfo.setUpdatedTime(new java.util.Date(rs.getLong("UPDATE_TIMESTAMP")));
} }
return deviceInfo; return deviceInfo;
} catch (SQLException e) { } catch (SQLException e) {
throw new DeviceDetailsMgtDAOException("Error occurred while fetching the details of the registered devices.", e); throw new DeviceDetailsMgtDAOException("Error occurred while fetching the details of the registered devices.", e);
@ -447,7 +442,7 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
stmt.setDouble(6, location.getLongitude()); stmt.setDouble(6, location.getLongitude());
stmt.setFloat(7, location.getSpeed()); stmt.setFloat(7, location.getSpeed());
stmt.setFloat(8, location.getBearing()); stmt.setFloat(8, location.getBearing());
stmt.setLong(9, System.currentTimeMillis()); stmt.setLong(9, location.getUpdatedTime().getTime());
stmt.setString(10, GeoHashGenerator.encodeGeohash(location)); stmt.setString(10, GeoHashGenerator.encodeGeohash(location));
stmt.setString(11, device.getEnrolmentInfo().getOwner()); stmt.setString(11, device.getEnrolmentInfo().getOwner());
stmt.setDouble(12, location.getAltitude()); stmt.setDouble(12, location.getAltitude());
@ -508,21 +503,5 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO {
private Connection getConnection() throws SQLException { private Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection(); return DeviceManagementDAOFactory.getConnection();
} }
// @Override
// public void addDeviceApplications(DeviceApplication deviceApplication) throws DeviceDetailsMgtDAOException {
//
// }
//
// @Override
// public DeviceApplication getDeviceApplications(int deviceId) throws DeviceDetailsMgtDAOException {
// return null;
// }
//
// @Override
// public void deleteDeviceApplications(int deviceId) throws DeviceDetailsMgtDAOException {
//
// }
} }

@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, 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.core.dto.event.config;
public class GeoFenceGroupMap {
private int fenceId;
private int groupId;
private String groupName;
public int getFenceId() {
return fenceId;
}
public void setFenceId(int fenceId) {
this.fenceId = fenceId;
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof GeoFenceGroupMap) {
GeoFenceGroupMap map = (GeoFenceGroupMap)obj;
return map.getFenceId() == this.getFenceId()
&& map.getGroupId() == this.getGroupId()
&& map.getGroupName().equals(this.getGroupName());
}
return false;
}
}

@ -0,0 +1,239 @@
/*
* Copyright (c) 2020, 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.core.event.config;
import com.google.common.collect.Lists;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.event.config.EventConfig;
import org.wso2.carbon.device.mgt.common.event.config.EventConfigurationException;
import org.wso2.carbon.device.mgt.common.event.config.EventConfigurationProviderService;
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
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.EventConfigDAO;
import org.wso2.carbon.device.mgt.core.dao.EventManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class EventConfigurationProviderServiceImpl implements EventConfigurationProviderService {
private static final Log log = LogFactory.getLog(EventConfigurationProviderServiceImpl.class);
private final EventConfigDAO eventConfigDAO;
public EventConfigurationProviderServiceImpl() {
eventConfigDAO = DeviceManagementDAOFactory.getEventConfigDAO();
}
@Override
public List<Integer> createEventsOfDeviceGroup(List<EventConfig> eventConfigList, List<Integer> groupIds)
throws EventConfigurationException {
int tenantId;
try {
tenantId = DeviceManagementDAOUtil.getTenantId();
} catch (DeviceManagementDAOException e) {
String msg = "Error occurred while retrieving tenant Id";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
}
try {
DeviceManagementDAOFactory.beginTransaction();
if (log.isDebugEnabled()) {
log.debug("Creating event records of tenant " + tenantId);
}
List<Integer> generatedEventIds = eventConfigDAO.storeEventRecords(eventConfigList, tenantId);
if (log.isDebugEnabled()) {
log.debug("Created events with event ids : " + generatedEventIds.toString());
log.debug("Creating event group mapping for created events with group ids : " + groupIds.toString());
}
eventConfigDAO.addEventGroupMappingRecords(generatedEventIds, groupIds);
DeviceManagementDAOFactory.commitTransaction();
if (log.isDebugEnabled()) {
log.debug("Event configuration added successfully for the tenant " + tenantId);
}
return generatedEventIds;
} catch (TransactionManagementException e) {
String msg = "Failed to start/open transaction to store device event configurations";
throw new EventConfigurationException(msg, e);
} catch (EventManagementDAOException e) {
String msg = "Error occurred while saving event records";
log.error(msg, e);
DeviceManagementDAOFactory.rollbackTransaction();
throw new EventConfigurationException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public List<Integer> updateEventsOfDeviceGroup(List<EventConfig> newEventList, List<Integer> removedEventIdList,
List<Integer> groupIds) throws EventConfigurationException {
//todo when concerning about other event types, all of this steps might not necessary.
// so divide them into separate service methods
if (log.isDebugEnabled()) {
log.debug("Updating event configurations of tenant");
}
List<EventConfig> eventsToAdd;
try {
DeviceManagementDAOFactory.beginTransaction();
eventsToAdd = new ArrayList<>();
List<EventConfig> eventsToUpdate = new ArrayList<>();
List<Integer> updateEventIdList = new ArrayList<>();
for (EventConfig newEvent : newEventList) {
if (newEvent.getEventId() == -1) {
eventsToAdd.add(newEvent);
continue;
}
eventsToUpdate.add(newEvent);
updateEventIdList.add(newEvent.getEventId());
}
List<Integer> savedGroups = eventConfigDAO.getGroupsOfEvents(updateEventIdList);
List<Integer> groupIdsToAdd = new ArrayList<>();
List<Integer> groupIdsToDelete = new ArrayList<>();
for (Integer savedGroup : savedGroups) {
if (!groupIds.contains(savedGroup)) {
groupIdsToDelete.add(savedGroup);
}
}
for (Integer newGroupId : groupIds) {
if (!savedGroups.contains(newGroupId)) {
groupIdsToAdd.add(newGroupId);
}
}
if (!eventsToUpdate.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Updating event records ");
}
eventConfigDAO.updateEventRecords(eventsToUpdate);
}
if (!groupIdsToDelete.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Deleting event group mapping records of groups");
}
eventConfigDAO.deleteEventGroupMappingRecordsByGroupIds(groupIdsToDelete);
}
if (!groupIdsToAdd.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Creating event group mapping records for updated events");
}
eventConfigDAO.addEventGroupMappingRecords(updateEventIdList, groupIdsToAdd);
}
if (!removedEventIdList.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Deleting event group mapping records of removing events");
}
eventConfigDAO.deleteEventGroupMappingRecordsByEventIds(removedEventIdList);
if (log.isDebugEnabled()) {
log.debug("Deleting removed event records");
}
eventConfigDAO.deleteEventRecords(removedEventIdList);
}
DeviceManagementDAOFactory.commitTransaction();
} catch (TransactionManagementException e) {
String msg = "Failed to start/open transaction to store device event configurations";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} catch (EventManagementDAOException e) {
String msg = "Error occurred while saving event records";
log.error(msg, e);
DeviceManagementDAOFactory.rollbackTransaction();
throw new EventConfigurationException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
if (log.isDebugEnabled()) {
log.debug("Adding new events while updating event");
}
return createEventsOfDeviceGroup(eventsToAdd, groupIds);
}
@Override
public List<EventConfig> getEvents(List<Integer> createdEventIds) throws EventConfigurationException {
try {
DeviceManagementDAOFactory.openConnection();
return eventConfigDAO.getEventsById(createdEventIds);
} catch (EventManagementDAOException e) {
String msg = "Error occurred while retrieving event by IDs : " + Arrays.toString(createdEventIds.toArray());
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} catch (SQLException e) {
String msg = "Failed to open connection while retrieving event by IDs";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public List<String> getEventsSourcesOfGroup(int groupId, int tenantId) throws EventConfigurationException {
try {
DeviceManagementDAOFactory.openConnection();
return eventConfigDAO.getEventSourcesOfGroups(groupId, tenantId);
} catch (EventManagementDAOException e) {
String msg = "Error occurred while retrieving events of group " + groupId + " and tenant " + tenantId;
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} catch (SQLException e) {
String msg = "Failed to open connection while retrieving event by IDs";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public void deleteEvents(List<EventConfig> events) throws EventConfigurationException {
try {
DeviceManagementDAOFactory.beginTransaction();
Set<Integer> eventIdSet = new HashSet<>();
for (EventConfig eventConfig : events) {
eventIdSet.add(eventConfig.getEventId());
}
if (!eventIdSet.isEmpty()) {
eventConfigDAO.deleteEventGroupMappingRecordsByEventIds(Lists.newArrayList(eventIdSet));
eventConfigDAO.deleteEventRecords(Lists.newArrayList(eventIdSet));
}
DeviceManagementDAOFactory.commitTransaction();
} catch (TransactionManagementException e) {
String msg = "Failed to start/open transaction to delete device event configurations";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
} catch (EventManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting event records";
log.error(msg, e);
throw new EventConfigurationException(msg, e);
}
}
}

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

Loading…
Cancel
Save