diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIConfig.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIConfig.java
index b3b880b2519..dd3efdeac83 100644
--- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIConfig.java
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIConfig.java
@@ -28,17 +28,16 @@ import java.util.Set;
/**
* This bean class carries the properties used by some API that needs to be published within the underlying
* API-Management infrastructure.
- *
* A sample API configuration accepted by this particular bean class would look like what's shown below.
* e.g.
*
*
- * enrollment
- * admin
- * /enrol
- * 1.0.0
- * http://localhost:9763/
- * http,https
+ * enrollment
+ * admin
+ * /enrol
+ * 1.0.0
+ * http://localhost:9763/
+ * http,https
*
*/
@XmlRootElement(name = "API")
@@ -47,6 +46,9 @@ public class APIConfig {
private String name;
private String owner;
private String context;
+ private String apiDocumentationName;
+ private String apiDocumentationSummary;
+ private String apiDocumentationSourceFile;
private String endpoint;
private String version;
private String policy;
@@ -82,6 +84,33 @@ public class APIConfig {
this.name = name;
}
+ @XmlElement(name = "ApiDocumentationName", required = false)
+ public String getApiDocumentationName() {
+ return apiDocumentationName;
+ }
+
+ public void setApiDocumentationName(String apiDocumentationName) {
+ this.apiDocumentationName = apiDocumentationName;
+ }
+
+ @XmlElement(name = "ApiDocumentationSummary", required = false)
+ public String getApiDocumentationSummary() {
+ return apiDocumentationSummary;
+ }
+
+ public void setApiDocumentationSummary(String apiDocumentationSummary) {
+ this.apiDocumentationSummary = apiDocumentationSummary;
+ }
+
+ @XmlElement(name = "ApiDocumentationSourceFile", required = false)
+ public String getApiDocumentationSourceFile() {
+ return apiDocumentationSourceFile;
+ }
+
+ public void setApiDocumentationSourceFile(String apiDocumentationSourceFile) {
+ this.apiDocumentationSourceFile = apiDocumentationSourceFile;
+ }
+
@XmlElement(name = "Owner", required = true)
public String getOwner() {
return owner;
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherServiceImpl.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherServiceImpl.java
index 5135e439bdf..0dcc92e6381 100644
--- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherServiceImpl.java
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherServiceImpl.java
@@ -21,6 +21,8 @@ package org.wso2.carbon.apimgt.webapp.publisher;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.apimgt.api.model.Documentation;
+import org.wso2.carbon.apimgt.api.model.DocumentationType;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.APIProvider;
import org.wso2.carbon.apimgt.api.FaultGatewaysException;
@@ -66,18 +68,19 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Date;
/**
* This class represents the concrete implementation of the APIPublisherService that corresponds to providing all
* API publishing related operations.
*/
public class APIPublisherServiceImpl implements APIPublisherService {
+ public static final APIManagerFactory API_MANAGER_FACTORY = APIManagerFactory.getInstance();
private static final String UNLIMITED_TIER = "Unlimited";
private static final String WS_UNLIMITED_TIER = "AsyncUnlimited";
private static final String API_PUBLISH_ENVIRONMENT = "Default";
private static final String CREATED_STATUS = "CREATED";
private static final String PUBLISH_ACTION = "Publish";
- public static final APIManagerFactory API_MANAGER_FACTORY = APIManagerFactory.getInstance();
private static final Log log = LogFactory.getLog(APIPublisherServiceImpl.class);
@Override
@@ -293,7 +296,45 @@ public class APIPublisherServiceImpl implements APIPublisherService {
}
}
}
- } catch (FaultGatewaysException | APIManagementException e) {
+ if (apiConfig.getApiDocumentationSourceFile() != null) {
+ API api = getAPI(apiConfig, true);
+
+ String fileName =
+ CarbonUtils.getCarbonHome() + File.separator + "repository" +
+ File.separator + "resources" + File.separator + "api-docs" + File.separator +
+ apiConfig.getApiDocumentationSourceFile();
+
+ BufferedReader br = new BufferedReader(new FileReader(fileName));
+ StringBuilder stringBuilder = new StringBuilder();
+ String line = null;
+ String ls = System.lineSeparator();
+ while ((line = br.readLine()) != null) {
+ stringBuilder.append(line);
+ stringBuilder.append(ls);
+ }
+ stringBuilder.deleteCharAt(stringBuilder.length() - 1);
+ br.close();
+ String docContent = stringBuilder.toString();
+
+ Documentation apiDocumentation = new Documentation(DocumentationType.HOWTO, apiConfig.getApiDocumentationName());
+ apiDocumentation.setVisibility(Documentation.DocumentVisibility.API_LEVEL);
+ apiDocumentation.setSourceType(Documentation.DocumentSourceType.MARKDOWN);
+ apiDocumentation.setCreatedDate(new Date());
+ apiDocumentation.setLastUpdated(new Date());
+ apiDocumentation.setSummary(apiConfig.getApiDocumentationSummary());
+ apiDocumentation.setOtherTypeName(null);
+
+ try {
+ //Including below code lines inside the try block because 'getDocumentation' method returns an APIManagementException exception when it doesn't have any existing doc
+ Documentation existingDoc = apiProvider.getDocumentation(api.getId(), DocumentationType.HOWTO, apiConfig.getApiDocumentationName());
+ apiProvider.removeDocumentation(api.getId(), existingDoc.getId(), null);
+ } catch (APIManagementException e) {
+ log.info("There is no any existing api documentation.");
+ }
+ apiProvider.addDocumentation(api.getId(), apiDocumentation);
+ apiProvider.addDocumentationContent(api, apiConfig.getApiDocumentationName(), docContent);
+ }
+ } catch (FaultGatewaysException | APIManagementException | IOException e) {
String msg = "Error occurred while publishing api";
log.error(msg, e);
throw new APIManagerPublisherException(e);
@@ -327,7 +368,7 @@ public class APIPublisherServiceImpl implements APIPublisherService {
try {
String fileName =
CarbonUtils.getCarbonConfigDirPath() + File.separator + "etc"
- + File.separator + tenantDomain + ".csv";
+ + File.separator + tenantDomain + ".csv";
if (Files.exists(Paths.get(fileName))) {
BufferedReader br = new BufferedReader(new FileReader(fileName));
int lineNumber = 0;
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherUtil.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherUtil.java
index b7ad837ed80..2b6a86fb069 100644
--- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherUtil.java
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/APIPublisherUtil.java
@@ -64,7 +64,7 @@ public class APIPublisherUtil {
}
public static String getWsServerBaseUrl() {
- return getServerBaseUrl().replace("https","wss");
+ return getServerBaseUrl().replace("https", "wss");
}
public static String getApiEndpointUrl(String context) {
@@ -104,7 +104,32 @@ public class APIPublisherUtil {
}
apiConfig.setVersion(version);
+ String apiDocumentationName = apiDef.getApiDocumentationName();
+ if (apiDocumentationName == null || apiDocumentationName.isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log.debug("'API Documentation not set in @SwaggerDefinition Annotation'");
+ }
+ } else {
+ apiConfig.setApiDocumentationName(apiDef.getApiDocumentationName());
+ }
+ String apiDocumentationSummary = apiDef.getApiDocumentationSummary();
+ if (apiDocumentationSummary == null || apiDocumentationSummary.isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log.debug("'API Documentation summary not set in @SwaggerDefinition Annotation'");
+ }
+ } else {
+ apiConfig.setApiDocumentationSummary(apiDef.getApiDocumentationSummary());
+ }
+
+ String apiDocumentationSourceFile = apiDef.getApiDocumentationSourceFile();
+ if (apiDocumentationSourceFile == null || apiDocumentationSourceFile.isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log.debug("'API Documentation source file not set in @SwaggerDefinition Annotation'");
+ }
+ } else {
+ apiConfig.setApiDocumentationSourceFile(apiDef.getApiDocumentationSourceFile());
+ }
String context = apiDef.getContext();
if (context == null || context.isEmpty()) {
if (log.isDebugEnabled()) {
@@ -302,20 +327,20 @@ public class APIPublisherUtil {
public static void setResourceAuthTypes(ServletContext servletContext, APIConfig apiConfig) {
List resourcesList = null;
String nonSecuredResources = servletContext.getInitParameter(NON_SECURED_RESOURCES);
- if(null != nonSecuredResources){
+ if (null != nonSecuredResources) {
resourcesList = Arrays.asList(nonSecuredResources.split(","));
}
Set templates = apiConfig.getUriTemplates();
- if(null != resourcesList) {
+ if (null != resourcesList) {
for (ApiUriTemplate template : templates) {
String fullPaath = "";
if (!template.getUriTemplate().equals(AnnotationProcessor.WILD_CARD)) {
fullPaath = apiConfig.getContext() + template.getUriTemplate();
}
- else{
+ else {
fullPaath = apiConfig.getContext();
}
- for(String context : resourcesList) {
+ for (String context : resourcesList) {
if (context.trim().equals(fullPaath)) {
template.setAuthType(AUTH_TYPE_NON_SECURED);
}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/config/APIResourceConfiguration.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/config/APIResourceConfiguration.java
index 49b66e6db9e..1fb2ab7880d 100644
--- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/config/APIResourceConfiguration.java
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/config/APIResourceConfiguration.java
@@ -25,60 +25,92 @@ import java.util.List;
@XmlRootElement(name = "ResourceConfiguration")
public class APIResourceConfiguration {
- private String name;
- private String context;
- private String version;
- private List resources;
- private String[] tags;
+ private String name;
+ private String context;
+ private String apiDocumentationName;
+ private String apiDocumentationSummary;
+ private String apiDocumentationSourceFile;
+ private String version;
+ private List resources;
+ private String[] tags;
private String endpointType;
private String inSequenceName;
private String inSequenceConfig;
private String asyncApiDefinition;
public List getResources() {
- return resources;
- }
-
- @XmlElement(name = "Resources", required = true)
- public void setResources(List resources) {
- this.resources = resources;
- }
-
- public String getContext() {
- return context;
- }
-
- @XmlElement(name = "Context", required = true)
- public void setContext(String context) {
- this.context = context;
- }
-
- public String getName() {
- return name;
- }
-
- @XmlElement(name = "Name")
- public void setName(String name) {
- this.name = name;
- }
-
- public String getVersion() {
- return version;
- }
-
- @XmlElement(name = "Version")
- public void setVersion(String version) {
- this.version = version;
- }
-
- public String[] getTags() {
- return tags;
- }
-
- @XmlElement(name = "Tags")
- public void setTags(String[] tags) {
- this.tags = tags;
- }
+ return resources;
+ }
+
+ @XmlElement(name = "Resources", required = true)
+ public void setResources(List resources) {
+ this.resources = resources;
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ @XmlElement(name = "Context", required = true)
+ public void setContext(String context) {
+ this.context = context;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @XmlElement(name = "Name")
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getApiDocumentationName() {
+ return apiDocumentationName;
+ }
+
+ @XmlElement(name = "ApiDocumentation")
+
+
+ public void setApiDocumentationName(String apiDocumentationName) {
+ this.apiDocumentationName = apiDocumentationName;
+ }
+
+ public String getApiDocumentationSummary() {
+ return apiDocumentationSummary;
+ }
+
+ @XmlElement(name = "ApiDocumentationSummary")
+ public void setApiDocumentationSummary(String apiDocumentationSummary) {
+ this.apiDocumentationSummary = apiDocumentationSummary;
+ }
+
+ public String getApiDocumentationSourceFile() {
+ return apiDocumentationSourceFile;
+ }
+
+ @XmlElement(name = "ApiDocumentationSourceFile")
+ public void setApiDocumentationSourceFile(String apiDocumentationSourceFile) {
+ this.apiDocumentationSourceFile = apiDocumentationSourceFile;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ @XmlElement(name = "Version")
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String[] getTags() {
+ return tags;
+ }
+
+ @XmlElement(name = "Tags")
+ public void setTags(String[] tags) {
+ this.tags = tags;
+ }
public String getEndpointType() {
return endpointType;
@@ -110,6 +142,7 @@ public class APIResourceConfiguration {
public String getAsyncApiDefinition() {
return asyncApiDefinition;
}
+
@XmlElement(name = "asyncApiDefinition")
public void setAsyncApiDefinition(String asyncApiDefinition) {
this.asyncApiDefinition = asyncApiDefinition;
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java
index 6774aa29bd4..f41c07967a5 100644
--- a/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.webapp.publisher/src/main/java/org/wso2/carbon/apimgt/webapp/publisher/lifecycle/util/AnnotationProcessor.java
@@ -53,7 +53,6 @@ import java.util.*;
public class AnnotationProcessor {
private static final Log log = LogFactory.getLog(AnnotationProcessor.class);
-
private static final String AUTH_TYPE = "Application & Application User";
private static final String STRING_ARR = "string_arr";
private static final String STRING = "string";
@@ -61,7 +60,6 @@ public class AnnotationProcessor {
private static final String PACKAGE_ORG_CODEHAUS = "org.codehaus";
private static final String PACKAGE_ORG_SPRINGFRAMEWORK = "org.springframework";
public static final String WILD_CARD = "/*";
-
private static final String SWAGGER_ANNOTATIONS_INFO = "info";
private static final String SWAGGER_ANNOTATIONS_TAGS = "tags";
private static final String SWAGGER_ANNOTATIONS_EXTENSIONS = "extensions";
@@ -73,6 +71,9 @@ public class AnnotationProcessor {
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_ROLES = "roles";
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_VERSION = "version";
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_CONTEXT = "context";
+ private static final String SWAGGER_ANNOTATIONS_PROPERTIES_API_DOCUMENTATION_NAME = "apiDocumentationName";
+ private static final String SWAGGER_ANNOTATIONS_PROPERTIES_API_DOCUMENTATION_SUMMARY = "apiDocumentationSummary";
+ private static final String SWAGGER_ANNOTATIONS_PROPERTIES_API_DOCUMENTATION_SOURCE_FILE = "apiDocumentationSourceFile";
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_ENDPOINT_TYPE = "endpointType";
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_IN_SEQUENCE_NAME = "inSequenceName";
private static final String SWAGGER_ANNOTATIONS_PROPERTIES_IN_SEQUENCE_CONFIG = "inSequenceConfig";
@@ -112,26 +113,25 @@ public class AnnotationProcessor {
pathClazz = (Class) classLoader.loadClass(Path.class.getName());
consumesClass = (Class) classLoader.loadClass(Consumes.class.getName());
producesClass = (Class) classLoader.loadClass(Produces.class.getName());
- apiClazz= (Class)classLoader.loadClass((SwaggerDefinition.class.getName()));
- infoClass = (Class)classLoader
+ apiClazz = (Class) classLoader.loadClass((SwaggerDefinition.class.getName()));
+ infoClass = (Class) classLoader
.loadClass((io.swagger.annotations.Info.class.getName()));
- tagClass = (Class)classLoader
+ tagClass = (Class) classLoader
.loadClass((io.swagger.annotations.Tag.class.getName()));
- extensionClass = (Class)classLoader
+ extensionClass = (Class) classLoader
.loadClass((io.swagger.annotations.Extension.class.getName()));
- extensionPropertyClass = (Class)classLoader
+ extensionPropertyClass = (Class) classLoader
.loadClass(io.swagger.annotations.ExtensionProperty.class.getName());
scopeClass = (Class) classLoader
.loadClass(org.wso2.carbon.apimgt.annotations.api.Scope.class.getName());
scopesClass = (Class) classLoader
.loadClass(org.wso2.carbon.apimgt.annotations.api.Scopes.class.getName());
- apiOperation = (Class)classLoader
+ apiOperation = (Class) classLoader
.loadClass((ApiOperation.class.getName()));
} catch (ClassNotFoundException e) {
log.error("An error has occurred while loading classes ", e);
}
}
-
public Set scanStandardContext(String className) throws IOException {
ExtendedAnnotationDB db = new ExtendedAnnotationDB();
db.addIgnoredPackages(PACKAGE_ORG_APACHE);
@@ -166,7 +166,7 @@ public class AnnotationProcessor {
if (Scopes != null) {
apiScopes = processAPIScopes(Scopes);
}
- if(apiResourceConfig != null){
+ if (apiResourceConfig != null) {
String rootContext = servletContext.getContextPath();
pathClazzMethods = pathClazz.getMethods();
Annotation rootContectAnno = clazz.getAnnotation(pathClazz);
@@ -199,21 +199,21 @@ public class AnnotationProcessor {
" This API will not be published.";
log.error(msg, e1);
} catch (RuntimeException e) {
- log.error("Unexpected error has been occurred while publishing "+ className
- +"hence, this API will not be published.");
+ log.error("Unexpected error has been occurred while publishing " + className
+ + "hence, this API will not be published.");
throw new RuntimeException(e);
}
return apiResourceConfig;
}
});
- if(apiResourceConfiguration !=null)
+ if (apiResourceConfiguration != null)
apiResourceConfigs.add(apiResourceConfiguration);
}
}
return apiResourceConfigs;
}
- private Map processAPIScopes(Annotation annotation) throws Throwable {
+ private Map processAPIScopes(Annotation annotation) throws Throwable {
Map scopes = new HashMap<>();
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
@@ -225,7 +225,7 @@ public class AnnotationProcessor {
StringBuilder aggregatedPermissions;
String roles[];
StringBuilder aggregatedRoles;
- for(int i=0; i applicationReleaseDTO = new AtomicReference<>(
applicationDTO.getApplicationReleaseDTOs().get(0));
validateAppReleaseUpdating(customAppReleaseWrapper, applicationDTO, applicationArtifact,
- ApplicationType.ENTERPRISE.toString());
+ ApplicationType.CUSTOM.toString());
applicationReleaseDTO.get().setPrice(customAppReleaseWrapper.getPrice());
applicationReleaseDTO.get()
.setIsSharedWithAllTenants(applicationReleaseDTO.get().getIsSharedWithAllTenants());
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java
index cbd7c697f4a..b6aadb113f6 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java
@@ -31,6 +31,8 @@ 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.PostgreSQLDeviceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.device.SQLServerDeviceDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.impl.enrolment.GenericEnrollmentDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.impl.enrolment.SQLServerEnrollmentDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.tracker.TrackerDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO;
@@ -41,7 +43,6 @@ import org.wso2.carbon.device.mgt.core.privacy.dao.impl.PrivacyComplianceDAOImpl
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
-import java.sql.Timestamp;
import java.util.Hashtable;
import java.util.List;
@@ -122,7 +123,20 @@ public class DeviceManagementDAOFactory {
}
public static EnrollmentDAO getEnrollmentDAO() {
- return new EnrollmentDAOImpl();
+ if (databaseEngine != null) {
+ switch (databaseEngine) {
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MSSQL:
+ return new SQLServerEnrollmentDAOImpl();
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_POSTGRESQL:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_ORACLE:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_H2:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
+ return new GenericEnrollmentDAOImpl();
+ default:
+ throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
+ }
+ }
+ throw new IllegalStateException("Database engine has not initialized properly.");
}
public static TrackerDAO getTrackerDAO() {
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/EventManagementDAOFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/EventManagementDAOFactory.java
index 754b5190041..09e5353fa61 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/EventManagementDAOFactory.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/EventManagementDAOFactory.java
@@ -29,6 +29,8 @@ import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
import org.wso2.carbon.device.mgt.core.dao.impl.*;
import org.wso2.carbon.device.mgt.core.dao.impl.event.GenericEventConfigDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.impl.event.H2EventConfigDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.impl.geofence.GenericGeofenceDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.impl.geofence.SQLServerGeofenceDAOImpl;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import javax.sql.DataSource;
@@ -45,7 +47,20 @@ public class EventManagementDAOFactory {
public static GeofenceDAO getGeofenceDAO() {
- return new GeofenceDAOImpl();
+ if (databaseEngine != null) {
+ switch (databaseEngine) {
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MSSQL:
+ return new SQLServerGeofenceDAOImpl();
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_POSTGRESQL:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_ORACLE:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_H2:
+ return new GenericGeofenceDAOImpl();
+ default:
+ throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
+ }
+ }
+ throw new IllegalStateException("Database engine has not initialized properly.");
}
public static EventConfigDAO getEventConfigDAO() {
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/EnrollmentDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java
similarity index 99%
rename from components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/EnrollmentDAOImpl.java
rename to components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java
index 7b3e08cd509..a3757bc523d 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/EnrollmentDAOImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractEnrollmentDAOImpl.java
@@ -37,7 +37,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-public class EnrollmentDAOImpl implements EnrollmentDAO {
+public abstract class AbstractEnrollmentDAOImpl implements EnrollmentDAO {
@Override
public EnrolmentInfo addEnrollment(int deviceId, EnrolmentInfo enrolmentInfo,
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/GeofenceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractGeofenceDAOImpl.java
similarity index 99%
rename from components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/GeofenceDAOImpl.java
rename to components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractGeofenceDAOImpl.java
index e845a43da92..4c8cd12e7e5 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/GeofenceDAOImpl.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractGeofenceDAOImpl.java
@@ -25,7 +25,6 @@ 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.EventManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.dao.GeofenceDAO;
import org.wso2.carbon.device.mgt.core.dto.event.config.GeoFenceGroupMap;
@@ -45,8 +44,8 @@ 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);
+public abstract class AbstractGeofenceDAOImpl implements GeofenceDAO {
+ private static final Log log = LogFactory.getLog(AbstractGeofenceDAOImpl.class);
@Override
public GeofenceData saveGeofence(GeofenceData geofenceData) throws DeviceManagementDAOException {
try {
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java
new file mode 100644
index 00000000000..041efbf285d
--- /dev/null
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/GenericEnrollmentDAOImpl.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2023, 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.core.dao.impl.enrolment;
+
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.device.mgt.common.Device;
+import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
+import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
+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.impl.AbstractEnrollmentDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class GenericEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
+
+ @Override
+ public EnrolmentInfo addEnrollment(int deviceId, EnrolmentInfo enrolmentInfo,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ String sql = "INSERT INTO DM_ENROLMENT(DEVICE_ID, OWNER, OWNERSHIP, STATUS, " +
+ "DATE_OF_ENROLMENT, DATE_OF_LAST_UPDATE, TENANT_ID) VALUES(?, ?, ?, ?, ?, ?, ?)";
+ stmt = conn.prepareStatement(sql, new String[] {"id"});
+ Timestamp enrollmentTime = new Timestamp(new Date().getTime());
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, enrolmentInfo.getOwner());
+ stmt.setString(3, enrolmentInfo.getOwnership().toString());
+ stmt.setString(4, enrolmentInfo.getStatus().toString());
+ stmt.setTimestamp(5, enrollmentTime);
+ stmt.setTimestamp(6, enrollmentTime);
+ stmt.setInt(7, tenantId);
+ stmt.execute();
+
+ rs = stmt.getGeneratedKeys();
+ if (rs.next()) {
+ int enrolmentId = rs.getInt(1);
+ enrolmentInfo.setId(enrolmentId);
+ enrolmentInfo.setDateOfEnrolment(enrollmentTime.getTime());
+ enrolmentInfo.setDateOfLastUpdate(enrollmentTime.getTime());
+ addDeviceStatus(enrolmentId, enrolmentInfo.getStatus());
+ return enrolmentInfo;
+ }
+ return null;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new DeviceManagementDAOException("Error occurred while adding enrolment configuration", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public int updateEnrollment(EnrolmentInfo enrolmentInfo, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET OWNERSHIP = ?, STATUS = ?, DATE_OF_LAST_UPDATE = ? " +
+ "WHERE ID = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, enrolmentInfo.getOwnership().toString());
+ stmt.setString(2, enrolmentInfo.getStatus().toString());
+ stmt.setTimestamp(3, new Timestamp(new Date().getTime()));
+ stmt.setInt(4, enrolmentInfo.getId());
+ stmt.setInt(5, tenantId);
+ int updatedCount = stmt.executeUpdate();
+ if (updatedCount == 1){
+ addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
+ }
+ return updatedCount;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while updating enrolment configuration", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public boolean updateEnrollmentStatus(List enrolmentInfos) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ boolean status = false;
+ int updateStatus = -1;
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ? WHERE ID = ?";
+ stmt = conn.prepareStatement(sql);
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ stmt.setString(1, enrolmentInfo.getStatus().toString());
+ stmt.setInt(2, enrolmentInfo.getId());
+ stmt.addBatch();
+ }
+ updateStatus = stmt.executeBatch().length;
+ } else {
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ stmt.setString(1, enrolmentInfo.getStatus().toString());
+ stmt.setInt(2, enrolmentInfo.getId());
+ updateStatus = stmt.executeUpdate();
+ }
+ }
+ if (updateStatus > 0) {
+ status = true;
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ addDeviceStatus(enrolmentInfo);
+ }
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while updating enrolment status of given device-list.", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return status;
+ }
+
+ @Override
+ public int removeEnrollment(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ int status = -1;
+ try {
+ conn = this.getConnection();
+ String sql = "DELETE FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql, new String[] {"id"});
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ stmt.executeUpdate();
+
+ rs = stmt.getGeneratedKeys();
+ if (rs.next()) {
+ status = 1;
+ }
+ return status;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while removing device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ private int getCountOfDevicesOfOwner(String owner, int tenantID) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ int count = 0;
+ try {
+ conn = this.getConnection();
+ String checkQuery = "SELECT COUNT(ID) AS COUNT FROM DM_ENROLMENT WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(checkQuery);
+ stmt.setString(1, owner);
+ stmt.setInt(2, tenantID);
+ rs = stmt.executeQuery();
+ if(rs.next()){
+ count = rs.getInt("COUNT");
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while trying to get device " +
+ "count of Owner : "+owner, e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return count;
+ }
+
+ @Override
+ public boolean setStatus(String currentOwner, EnrolmentInfo.Status status,
+ int tenantId) throws DeviceManagementDAOException {
+ return setStatusAllDevices(currentOwner, status, tenantId);
+ }
+
+ @Override
+ public boolean setStatusAllDevices(String currentOwner, EnrolmentInfo.Status status, int tenantId)
+ throws DeviceManagementDAOException{
+ Connection conn;
+ PreparedStatement stmt = null;
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ if(getCountOfDevicesOfOwner(currentOwner, tenantId) > 0){
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ?, DATE_OF_LAST_UPDATE = ? WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, status.toString());
+ stmt.setTimestamp(2, updateTime);
+ stmt.setString(3, currentOwner);
+ stmt.setInt(4, tenantId);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return addDeviceStatus(currentOwner, status, tenantId);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setStatus(int enrolmentID, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ?, DATE_OF_LAST_UPDATE = ? WHERE ID = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, status.toString());
+ stmt.setTimestamp(2, updateTime);
+ stmt.setInt(3, enrolmentID);
+ stmt.setInt(4, tenantId);
+ int updatedRowCount = stmt.executeUpdate();
+ if (updatedRowCount != 1){
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment: "+
+ updatedRowCount + " rows were updated instead of one row!!!");
+ }
+ // save the device status history
+ addDeviceStatus(enrolmentID, status);
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return true;
+ }
+
+ private boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
+ return addDeviceStatus(config.getId(), config.getStatus());
+ }
+
+ private boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
+ if (changedBy == null){
+ changedBy = DeviceManagementConstants.MaintenanceProperties.MAINTENANCE_USER;
+ }
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ List enrolmentInfoList = new ArrayList<>();
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, currentOwner);
+ stmt.setInt(2, tenantId);
+ rs = stmt.executeQuery();
+ while (rs.next()) {
+ int enrolmentId = rs.getInt("ID");
+ int deviceId = rs.getInt("DEVICE_ID");
+ enrolmentInfoList.add(new int[]{enrolmentId, deviceId});
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ sql = "INSERT INTO DM_DEVICE_STATUS (ENROLMENT_ID, DEVICE_ID, STATUS, UPDATE_TIME, CHANGED_BY) VALUES(?, ?, ?, ?, ?)";
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for(int[] info: enrolmentInfoList){
+ ps.setInt(1, info[0]);
+ ps.setInt(2, info[1]);
+ ps.setString(3, status.toString());
+ ps.setTimestamp(4, updateTime);
+ ps.setString(5, changedBy);
+ ps.addBatch();
+ }
+ int[] batchResult = ps.executeBatch();
+ for (int i : batchResult) {
+ if (i == 0 || i == Statement.SUCCESS_NO_INFO || i == Statement.EXECUTE_FAILED) {
+ return false;
+ }
+ }
+ } else {
+ for(int[] info: enrolmentInfoList){
+ ps.setInt(1, info[0]);
+ ps.setInt(2, info[1]);
+ ps.setString(3, status.toString());
+ ps.setTimestamp(4, updateTime);
+ ps.setString(5, changedBy);
+ ps.execute();
+ }
+
+ }
+ }
+
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolments " +
+ "information of owner '" + currentOwner + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return true;
+ }
+
+ private boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
+ Connection conn;
+ String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
+ if (changedBy == null){
+ changedBy = DeviceManagementConstants.MaintenanceProperties.MAINTENANCE_USER;
+ }
+ PreparedStatement stmt = null;
+ try {
+ conn = this.getConnection();
+ // get the device id and last udpated status from the device status table
+ String sql = "SELECT DEVICE_ID, STATUS FROM DM_DEVICE_STATUS WHERE ENROLMENT_ID = ? ORDER BY UPDATE_TIME DESC LIMIT 1";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, enrolmentId);
+ ResultSet rs = stmt.executeQuery();
+ int deviceId = -1;
+ EnrolmentInfo.Status previousStatus = null;
+ if (rs.next()) {
+ // if there is a record corresponding to the enrolment we save the status and the device id
+ previousStatus = EnrolmentInfo.Status.valueOf(rs.getString("STATUS"));
+ deviceId = rs.getInt("DEVICE_ID");
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ // if there was no record for the enrolment or the previous status is not the same as the current status
+ // we'll add a record
+ if (previousStatus == null || previousStatus != status){
+ if (deviceId == -1) {
+ // we need the device id in order to add a new record, therefore we get it from the enrolment table
+ sql = "SELECT DEVICE_ID FROM DM_ENROLMENT WHERE ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, enrolmentId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ deviceId = rs.getInt("DEVICE_ID");
+ } else {
+ // if there were no records corresponding to the enrolment id this is a problem. i.e. enrolment
+ // id is invalid
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment: no record for enrolment id " + enrolmentId);
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+
+ sql = "INSERT INTO DM_DEVICE_STATUS (ENROLMENT_ID, DEVICE_ID, STATUS, UPDATE_TIME, CHANGED_BY) VALUES(?, ?, ?, ?, ?)";
+ stmt = conn.prepareStatement(sql);
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ stmt.setInt(1, enrolmentId);
+ stmt.setInt(2, deviceId);
+ stmt.setString(3, status.toString());
+ stmt.setTimestamp(4, updateTime);
+ stmt.setString(5, changedBy);
+ stmt.execute();
+ } else {
+ // no need to update status since the last recorded status is the same as the current status
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return true;
+ }
+ @Override
+ public EnrolmentInfo.Status getStatus(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo.Status status = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT STATUS FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ status = EnrolmentInfo.Status.valueOf(rs.getString("STATUS"));
+ }
+ return status;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public EnrolmentInfo getEnrollment(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ }
+ return enrolmentInfo;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolment " +
+ "information of user '" + currentOwner + "' upon device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public EnrolmentInfo getEnrollment(int deviceId, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND TENANT_ID = ? " +
+ "ORDER BY DATE_OF_LAST_UPDATE DESC";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setInt(2, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ }
+ return enrolmentInfo;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolment " +
+ "information of device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public List getEnrollmentsOfUser(int deviceId, String user, int tenantId)
+ throws DeviceManagementDAOException {
+ List enrolmentInfos = new ArrayList<>();
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, user);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ while (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ enrolmentInfos.add(enrolmentInfo);
+ }
+ return enrolmentInfos;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolments " +
+ "information of user '" + user + "' upon device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public boolean updateOwnerOfEnrollment(List devices, String owner, int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ boolean updateStatus = true;
+ String sql = "UPDATE DM_ENROLMENT "
+ + "SET OWNER = ?, IS_TRANSFERRED = ?, DATE_OF_LAST_UPDATE = ? "
+ + "WHERE ID = ? AND TENANT_ID = ?";
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for (Device device : devices) {
+ ps.setString(1, owner);
+ ps.setBoolean(2, device.getEnrolmentInfo().isTransferred());
+ ps.setTimestamp(3, new Timestamp(new Date().getTime()));
+ ps.setInt(4, device.getEnrolmentInfo().getId());
+ ps.setInt(5, tenantId);
+ ps.addBatch();
+ }
+ int[] batchResult = ps.executeBatch();
+ for (int i : batchResult) {
+ if (i == 0 || i == Statement.SUCCESS_NO_INFO || i == Statement.EXECUTE_FAILED) {
+ updateStatus = false;
+ break;
+ }
+ }
+ } else {
+ for (Device device : devices) {
+ ps.setString(1, owner);
+ ps.setBoolean(2, device.getEnrolmentInfo().isTransferred());
+ ps.setInt(3, device.getId());
+ ps.setInt(4, tenantId);
+ if (ps.executeUpdate() == 0) {
+ updateStatus = false;
+ break;
+ }
+ }
+ }
+ }
+ return updateStatus;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while obtaining the DB connection to update the "
+ + "owner of the device enrollment.", e);
+ }
+ }
+
+ private Connection getConnection() throws SQLException {
+ return DeviceManagementDAOFactory.getConnection();
+ }
+
+ private EnrolmentInfo loadEnrolment(ResultSet rs) throws SQLException {
+ EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
+ enrolmentInfo.setOwner(rs.getString("OWNER"));
+ enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.valueOf(rs.getString("OWNERSHIP")));
+ enrolmentInfo.setTransferred(rs.getBoolean("IS_TRANSFERRED"));
+ enrolmentInfo.setDateOfEnrolment(rs.getTimestamp("DATE_OF_ENROLMENT").getTime());
+ enrolmentInfo.setDateOfLastUpdate(rs.getTimestamp("DATE_OF_LAST_UPDATE").getTime());
+ enrolmentInfo.setStatus(EnrolmentInfo.Status.valueOf(rs.getString("STATUS")));
+ enrolmentInfo.setId(rs.getInt("ID"));
+ return enrolmentInfo;
+ }
+
+}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java
new file mode 100644
index 00000000000..8041d07a598
--- /dev/null
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/enrolment/SQLServerEnrollmentDAOImpl.java
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2023, 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.core.dao.impl.enrolment;
+
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.device.mgt.common.Device;
+import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
+import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
+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.impl.AbstractEnrollmentDAOImpl;
+import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class SQLServerEnrollmentDAOImpl extends AbstractEnrollmentDAOImpl {
+
+ @Override
+ public EnrolmentInfo addEnrollment(int deviceId, EnrolmentInfo enrolmentInfo,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ String sql = "INSERT INTO DM_ENROLMENT(DEVICE_ID, OWNER, OWNERSHIP, STATUS, " +
+ "DATE_OF_ENROLMENT, DATE_OF_LAST_UPDATE, TENANT_ID) VALUES(?, ?, ?, ?, ?, ?, ?)";
+ stmt = conn.prepareStatement(sql, new String[] {"id"});
+ Timestamp enrollmentTime = new Timestamp(new Date().getTime());
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, enrolmentInfo.getOwner());
+ stmt.setString(3, enrolmentInfo.getOwnership().toString());
+ stmt.setString(4, enrolmentInfo.getStatus().toString());
+ stmt.setTimestamp(5, enrollmentTime);
+ stmt.setTimestamp(6, enrollmentTime);
+ stmt.setInt(7, tenantId);
+ stmt.execute();
+
+ rs = stmt.getGeneratedKeys();
+ if (rs.next()) {
+ int enrolmentId = rs.getInt(1);
+ enrolmentInfo.setId(enrolmentId);
+ enrolmentInfo.setDateOfEnrolment(enrollmentTime.getTime());
+ enrolmentInfo.setDateOfLastUpdate(enrollmentTime.getTime());
+ addDeviceStatus(enrolmentId, enrolmentInfo.getStatus());
+ return enrolmentInfo;
+ }
+ return null;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new DeviceManagementDAOException("Error occurred while adding enrolment configuration", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public int updateEnrollment(EnrolmentInfo enrolmentInfo, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET OWNERSHIP = ?, STATUS = ?, DATE_OF_LAST_UPDATE = ? " +
+ "WHERE ID = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, enrolmentInfo.getOwnership().toString());
+ stmt.setString(2, enrolmentInfo.getStatus().toString());
+ stmt.setTimestamp(3, new Timestamp(new Date().getTime()));
+ stmt.setInt(4, enrolmentInfo.getId());
+ stmt.setInt(5, tenantId);
+ int updatedCount = stmt.executeUpdate();
+ if (updatedCount == 1){
+ addDeviceStatus(enrolmentInfo.getId(), enrolmentInfo.getStatus());
+ }
+ return updatedCount;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while updating enrolment configuration", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public boolean updateEnrollmentStatus(List enrolmentInfos) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ boolean status = false;
+ int updateStatus = -1;
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ? WHERE ID = ?";
+ stmt = conn.prepareStatement(sql);
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ stmt.setString(1, enrolmentInfo.getStatus().toString());
+ stmt.setInt(2, enrolmentInfo.getId());
+ stmt.addBatch();
+ }
+ updateStatus = stmt.executeBatch().length;
+ } else {
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ stmt.setString(1, enrolmentInfo.getStatus().toString());
+ stmt.setInt(2, enrolmentInfo.getId());
+ updateStatus = stmt.executeUpdate();
+ }
+ }
+ if (updateStatus > 0) {
+ status = true;
+ for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
+ addDeviceStatus(enrolmentInfo);
+ }
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while updating enrolment status of given device-list.", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return status;
+ }
+
+ @Override
+ public int removeEnrollment(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ int status = -1;
+ try {
+ conn = this.getConnection();
+ String sql = "DELETE FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql, new String[] {"id"});
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ stmt.executeUpdate();
+
+ rs = stmt.getGeneratedKeys();
+ if (rs.next()) {
+ status = 1;
+ }
+ return status;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while removing device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ private int getCountOfDevicesOfOwner(String owner, int tenantID) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ int count = 0;
+ try {
+ conn = this.getConnection();
+ String checkQuery = "SELECT COUNT(ID) AS COUNT FROM DM_ENROLMENT WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(checkQuery);
+ stmt.setString(1, owner);
+ stmt.setInt(2, tenantID);
+ rs = stmt.executeQuery();
+ if(rs.next()){
+ count = rs.getInt("COUNT");
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while trying to get device " +
+ "count of Owner : "+owner, e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return count;
+ }
+
+ @Override
+ public boolean setStatus(String currentOwner, EnrolmentInfo.Status status,
+ int tenantId) throws DeviceManagementDAOException {
+ return setStatusAllDevices(currentOwner, status, tenantId);
+ }
+
+ @Override
+ public boolean setStatusAllDevices(String currentOwner, EnrolmentInfo.Status status, int tenantId)
+ throws DeviceManagementDAOException{
+ Connection conn;
+ PreparedStatement stmt = null;
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ if(getCountOfDevicesOfOwner(currentOwner, tenantId) > 0){
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ?, DATE_OF_LAST_UPDATE = ? WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, status.toString());
+ stmt.setTimestamp(2, updateTime);
+ stmt.setString(3, currentOwner);
+ stmt.setInt(4, tenantId);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return addDeviceStatus(currentOwner, status, tenantId);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setStatus(int enrolmentID, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ try {
+ conn = this.getConnection();
+ String sql = "UPDATE DM_ENROLMENT SET STATUS = ?, DATE_OF_LAST_UPDATE = ? WHERE ID = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, status.toString());
+ stmt.setTimestamp(2, updateTime);
+ stmt.setInt(3, enrolmentID);
+ stmt.setInt(4, tenantId);
+ int updatedRowCount = stmt.executeUpdate();
+ if (updatedRowCount != 1){
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment: "+
+ updatedRowCount + " rows were updated instead of one row!!!");
+ }
+ // save the device status history
+ addDeviceStatus(enrolmentID, status);
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return true;
+ }
+
+ private boolean addDeviceStatus(EnrolmentInfo config) throws DeviceManagementDAOException {
+ return addDeviceStatus(config.getId(), config.getStatus());
+ }
+
+ private boolean addDeviceStatus(String currentOwner, EnrolmentInfo.Status status, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
+ if (changedBy == null){
+ changedBy = DeviceManagementConstants.MaintenanceProperties.MAINTENANCE_USER;
+ }
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ List enrolmentInfoList = new ArrayList<>();
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setString(1, currentOwner);
+ stmt.setInt(2, tenantId);
+ rs = stmt.executeQuery();
+ while (rs.next()) {
+ int enrolmentId = rs.getInt("ID");
+ int deviceId = rs.getInt("DEVICE_ID");
+ enrolmentInfoList.add(new int[]{enrolmentId, deviceId});
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ sql = "INSERT INTO DM_DEVICE_STATUS (ENROLMENT_ID, DEVICE_ID, STATUS, UPDATE_TIME, CHANGED_BY) VALUES(?, ?, ?, ?, ?)";
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for(int[] info: enrolmentInfoList){
+ ps.setInt(1, info[0]);
+ ps.setInt(2, info[1]);
+ ps.setString(3, status.toString());
+ ps.setTimestamp(4, updateTime);
+ ps.setString(5, changedBy);
+ ps.addBatch();
+ }
+ int[] batchResult = ps.executeBatch();
+ for (int i : batchResult) {
+ if (i == 0 || i == Statement.SUCCESS_NO_INFO || i == Statement.EXECUTE_FAILED) {
+ return false;
+ }
+ }
+ } else {
+ for(int[] info: enrolmentInfoList){
+ ps.setInt(1, info[0]);
+ ps.setInt(2, info[1]);
+ ps.setString(3, status.toString());
+ ps.setTimestamp(4, updateTime);
+ ps.setString(5, changedBy);
+ ps.execute();
+ }
+
+ }
+ }
+
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolments " +
+ "information of owner '" + currentOwner + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ return true;
+ }
+
+ private boolean addDeviceStatus(int enrolmentId, EnrolmentInfo.Status status) throws DeviceManagementDAOException {
+ Connection conn;
+ String changedBy = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
+ if (changedBy == null){
+ changedBy = DeviceManagementConstants.MaintenanceProperties.MAINTENANCE_USER;
+ }
+ PreparedStatement stmt = null;
+ try {
+ conn = this.getConnection();
+ // get the device id and last udpated status from the device status table
+ String sql = "SELECT TOP 1 DEVICE_ID, STATUS FROM DM_DEVICE_STATUS WHERE ENROLMENT_ID = ? ORDER BY UPDATE_TIME DESC";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, enrolmentId);
+ ResultSet rs = stmt.executeQuery();
+ int deviceId = -1;
+ EnrolmentInfo.Status previousStatus = null;
+ if (rs.next()) {
+ // if there is a record corresponding to the enrolment we save the status and the device id
+ previousStatus = EnrolmentInfo.Status.valueOf(rs.getString("STATUS"));
+ deviceId = rs.getInt("DEVICE_ID");
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ // if there was no record for the enrolment or the previous status is not the same as the current status
+ // we'll add a record
+ if (previousStatus == null || previousStatus != status){
+ if (deviceId == -1) {
+ // we need the device id in order to add a new record, therefore we get it from the enrolment table
+ sql = "SELECT DEVICE_ID FROM DM_ENROLMENT WHERE ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, enrolmentId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ deviceId = rs.getInt("DEVICE_ID");
+ } else {
+ // if there were no records corresponding to the enrolment id this is a problem. i.e. enrolment
+ // id is invalid
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment: no record for enrolment id " + enrolmentId);
+ }
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+
+ sql = "INSERT INTO DM_DEVICE_STATUS (ENROLMENT_ID, DEVICE_ID, STATUS, UPDATE_TIME, CHANGED_BY) VALUES(?, ?, ?, ?, ?)";
+ stmt = conn.prepareStatement(sql);
+ Timestamp updateTime = new Timestamp(new Date().getTime());
+ stmt.setInt(1, enrolmentId);
+ stmt.setInt(2, deviceId);
+ stmt.setString(3, status.toString());
+ stmt.setTimestamp(4, updateTime);
+ stmt.setString(5, changedBy);
+ stmt.execute();
+ } else {
+ // no need to update status since the last recorded status is the same as the current status
+ }
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, null);
+ }
+ return true;
+ }
+ @Override
+ public EnrolmentInfo.Status getStatus(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo.Status status = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT STATUS FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ status = EnrolmentInfo.Status.valueOf(rs.getString("STATUS"));
+ }
+ return status;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while setting the status of device enrolment", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public EnrolmentInfo getEnrollment(int deviceId, String currentOwner,
+ int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, currentOwner);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ }
+ return enrolmentInfo;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolment " +
+ "information of user '" + currentOwner + "' upon device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public EnrolmentInfo getEnrollment(int deviceId, int tenantId) throws DeviceManagementDAOException {
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND TENANT_ID = ? " +
+ "ORDER BY DATE_OF_LAST_UPDATE DESC";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setInt(2, tenantId);
+ rs = stmt.executeQuery();
+ if (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ }
+ return enrolmentInfo;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolment " +
+ "information of device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public List getEnrollmentsOfUser(int deviceId, String user, int tenantId)
+ throws DeviceManagementDAOException {
+ List enrolmentInfos = new ArrayList<>();
+ Connection conn;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ EnrolmentInfo enrolmentInfo = null;
+ try {
+ conn = this.getConnection();
+ String sql = "SELECT ID, DEVICE_ID, OWNER, OWNERSHIP, STATUS, IS_TRANSFERRED, DATE_OF_ENROLMENT, " +
+ "DATE_OF_LAST_UPDATE, TENANT_ID FROM DM_ENROLMENT WHERE DEVICE_ID = ? AND OWNER = ? AND TENANT_ID = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, deviceId);
+ stmt.setString(2, user);
+ stmt.setInt(3, tenantId);
+ rs = stmt.executeQuery();
+ while (rs.next()) {
+ enrolmentInfo = this.loadEnrolment(rs);
+ enrolmentInfos.add(enrolmentInfo);
+ }
+ return enrolmentInfos;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while retrieving the enrolments " +
+ "information of user '" + user + "' upon device '" + deviceId + "'", e);
+ } finally {
+ DeviceManagementDAOUtil.cleanupResources(stmt, rs);
+ }
+ }
+
+ @Override
+ public boolean updateOwnerOfEnrollment(List devices, String owner, int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ boolean updateStatus = true;
+ String sql = "UPDATE DM_ENROLMENT "
+ + "SET OWNER = ?, IS_TRANSFERRED = ?, DATE_OF_LAST_UPDATE = ? "
+ + "WHERE ID = ? AND TENANT_ID = ?";
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ if (conn.getMetaData().supportsBatchUpdates()) {
+ for (Device device : devices) {
+ ps.setString(1, owner);
+ ps.setBoolean(2, device.getEnrolmentInfo().isTransferred());
+ ps.setTimestamp(3, new Timestamp(new Date().getTime()));
+ ps.setInt(4, device.getEnrolmentInfo().getId());
+ ps.setInt(5, tenantId);
+ ps.addBatch();
+ }
+ int[] batchResult = ps.executeBatch();
+ for (int i : batchResult) {
+ if (i == 0 || i == Statement.SUCCESS_NO_INFO || i == Statement.EXECUTE_FAILED) {
+ updateStatus = false;
+ break;
+ }
+ }
+ } else {
+ for (Device device : devices) {
+ ps.setString(1, owner);
+ ps.setBoolean(2, device.getEnrolmentInfo().isTransferred());
+ ps.setInt(3, device.getId());
+ ps.setInt(4, tenantId);
+ if (ps.executeUpdate() == 0) {
+ updateStatus = false;
+ break;
+ }
+ }
+ }
+ }
+ return updateStatus;
+ } catch (SQLException e) {
+ throw new DeviceManagementDAOException("Error occurred while obtaining the DB connection to update the "
+ + "owner of the device enrollment.", e);
+ }
+ }
+
+ private Connection getConnection() throws SQLException {
+ return DeviceManagementDAOFactory.getConnection();
+ }
+
+ private EnrolmentInfo loadEnrolment(ResultSet rs) throws SQLException {
+ EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
+ enrolmentInfo.setOwner(rs.getString("OWNER"));
+ enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.valueOf(rs.getString("OWNERSHIP")));
+ enrolmentInfo.setTransferred(rs.getBoolean("IS_TRANSFERRED"));
+ enrolmentInfo.setDateOfEnrolment(rs.getTimestamp("DATE_OF_ENROLMENT").getTime());
+ enrolmentInfo.setDateOfLastUpdate(rs.getTimestamp("DATE_OF_LAST_UPDATE").getTime());
+ enrolmentInfo.setStatus(EnrolmentInfo.Status.valueOf(rs.getString("STATUS")));
+ enrolmentInfo.setId(rs.getInt("ID"));
+ return enrolmentInfo;
+ }
+
+}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/GenericGeofenceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/GenericGeofenceDAOImpl.java
new file mode 100644
index 00000000000..b7784a34800
--- /dev/null
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/GenericGeofenceDAOImpl.java
@@ -0,0 +1,637 @@
+/*
+ * 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.geofence;
+
+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.EventManagementDAOFactory;
+import org.wso2.carbon.device.mgt.core.dao.GeofenceDAO;
+import org.wso2.carbon.device.mgt.core.dao.impl.AbstractGeofenceDAOImpl;
+import org.wso2.carbon.device.mgt.core.dto.event.config.GeoFenceGroupMap;
+
+import java.sql.*;
+import java.util.Date;
+import java.util.*;
+
+public class GenericGeofenceDAOImpl extends AbstractGeofenceDAOImpl {
+ private static final Log log = LogFactory.getLog(GenericGeofenceDAOImpl.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 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 getGeoFencesOfTenant(PaginationRequest request, int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ boolean isNameProvided = false;
+ List 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 getGeoFencesOfTenant(String fenceName, int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ List 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 getGeoFencesOfTenant(int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ List 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 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 EventManagementDAOFactory.getConnection();
+ }
+
+ private List extractGeofenceData(ResultSet rst) throws SQLException {
+ List 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 getGroupIdsOfGeoFence(int fenceId) throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ String sql = "SELECT " +
+ "GROUP_ID " +
+ "FROM DM_GEOFENCE_GROUP_MAPPING " +
+ "WHERE FENCE_ID = ? ";
+ List 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 groupIdsToDelete, int fenceId) throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ String sql = "DELETE FROM DM_GEOFENCE_GROUP_MAPPING WHERE GROUP_ID = ? AND FENCE_ID = ?";
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ for (Integer groupId : groupIdsToDelete) {
+ stmt.setInt(1, groupId);
+ stmt.setInt(2, fenceId);
+ 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 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 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> getEventsOfGeoFences(List geofenceIds) throws DeviceManagementDAOException {
+ try {
+ Map> geoFenceEventMap = new HashMap<>();
+ if (geofenceIds.isEmpty()) {
+ return geoFenceEventMap;
+ }
+ 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 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 getEventsOfGeoFence(int geofenceId) throws DeviceManagementDAOException {
+ try {
+ List 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 getGroupIdsOfGeoFences(List fenceIds) throws DeviceManagementDAOException {
+ try {
+ Set geoFenceGroupSet = new HashSet<>();
+ if (fenceIds.isEmpty()) {
+ return geoFenceGroupSet;
+ }
+ 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 getEventConfigs(PreparedStatement stmt) throws SQLException {
+ List 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 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 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 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);
+ }
+ }
+}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/SQLServerGeofenceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/SQLServerGeofenceDAOImpl.java
new file mode 100644
index 00000000000..7fe050a477f
--- /dev/null
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/geofence/SQLServerGeofenceDAOImpl.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2023, 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.geofence;
+
+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.EventManagementDAOFactory;
+import org.wso2.carbon.device.mgt.core.dao.GeofenceDAO;
+import org.wso2.carbon.device.mgt.core.dao.impl.AbstractGeofenceDAOImpl;
+import org.wso2.carbon.device.mgt.core.dto.event.config.GeoFenceGroupMap;
+
+import java.sql.*;
+import java.util.Date;
+import java.util.*;
+
+public class SQLServerGeofenceDAOImpl extends AbstractGeofenceDAOImpl {
+ private static final Log log = LogFactory.getLog(SQLServerGeofenceDAOImpl.class);
+
+ @Override
+ public List getGeoFencesOfTenant(PaginationRequest request, int tenantId)
+ throws DeviceManagementDAOException {
+ try {
+ Connection conn = this.getConnection();
+ boolean isNameProvided = false;
+ List 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 += "ORDER BY FENCE_NAME ";
+ sql += "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
+ 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.getStartIndex());
+ stmt.setInt(index, request.getRowCount());
+ 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);
+ }
+ }
+
+ private Connection getConnection() throws SQLException {
+ return EventManagementDAOFactory.getConnection();
+ }
+
+ private List extractGeofenceData(ResultSet rst) throws SQLException {
+ List 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;
+ }
+}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/DeviceStatusPersistenceTests.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/DeviceStatusPersistenceTests.java
index 65c22e11613..b2a8903c7fb 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/DeviceStatusPersistenceTests.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/DeviceStatusPersistenceTests.java
@@ -39,9 +39,15 @@ import static org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status.*;
public class DeviceStatusPersistenceTests extends BaseDeviceManagementTest {
private static final Log log = LogFactory.getLog(DeviceStatusPersistenceTests.class);
- private EnrollmentDAO enrollmentDAO = DeviceManagementDAOFactory.getEnrollmentDAO();
+ EnrollmentDAO enrollmentDAO;
private DeviceStatusDAO deviceStatusDAO = DeviceManagementDAOFactory.getDeviceStatusDAO();
+ @BeforeClass
+ @Override
+ public void init() throws Exception {
+ enrollmentDAO = DeviceManagementDAOFactory.getEnrollmentDAO();
+ }
+
/**
* Validate that the list of statuses received match the statuses
* @param device
@@ -245,10 +251,4 @@ public class DeviceStatusPersistenceTests extends BaseDeviceManagementTest {
}
return false;
}
-
- @BeforeClass
- @Override
- public void init() throws Exception {
-
- }
}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/EnrolmentPersistenceTests.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/EnrolmentPersistenceTests.java
index 9497324798e..10bf0a1b641 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/EnrolmentPersistenceTests.java
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/java/org/wso2/carbon/device/mgt/core/dao/EnrolmentPersistenceTests.java
@@ -33,7 +33,14 @@ import java.sql.SQLException;
public class EnrolmentPersistenceTests extends BaseDeviceManagementTest {
private static final Log log = LogFactory.getLog(EnrolmentPersistenceTests.class);
- private EnrollmentDAO enrollmentDAO = DeviceManagementDAOFactory.getEnrollmentDAO();
+ EnrollmentDAO enrollmentDAO;
+
+ @BeforeClass
+ @Override
+ public void init() throws Exception {
+ this.initDataSource();
+ enrollmentDAO = DeviceManagementDAOFactory.getEnrollmentDAO();
+ }
@Test
public void testAddEnrolment() {
@@ -86,10 +93,4 @@ public class EnrolmentPersistenceTests extends BaseDeviceManagementTest {
}
return enrolmentInfo;
}
-
- @BeforeClass
- @Override
- public void init() throws Exception {
- this.initDataSource();
- }
}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/pom.xml b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/pom.xml
new file mode 100644
index 00000000000..905ed65f0f8
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/pom.xml
@@ -0,0 +1,412 @@
+
+
+
+
+ org.wso2.carbon.devicemgt
+ subtype-mgt
+ 5.0.25-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ io.entgra.device.mgt.subtype.mgt
+ Entgra IoT - Subtype Mgt Impl
+ bundle
+ Entgra IoT - Subtype Management Component Implementation
+ http://entgra.io
+
+
+
+
+ org.apache.felix
+ maven-scr-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+ ${project.artifactId}
+ ${project.artifactId}
+ ${carbon.device.mgt.version}
+ Subtype Management Bundle
+ io.entgra.device.mgt.subtype.mgt.internal
+
+ org.osgi.framework.*;version="${imp.package.version.osgi.framework}",
+ org.osgi.service.*;version="${imp.package.version.osgi.service}",
+ org.apache.commons.logging,
+ org.apache.commons.lang,
+ javax.xml,
+ javax.xml.stream,
+ javax.xml.bind.*,
+ javax.sql,
+ javax.xml.parsers; version=0.0.0,
+ org.w3c.dom,
+ javax.naming,
+ org.wso2.carbon.context,
+ org.wso2.carbon.base,
+ org.wso2.carbon.utils.*,
+ org.wso2.carbon.device.mgt.common.*,
+ org.wso2.carbon.device.mgt.core.*,
+ org.wso2.carbon.ndatasource.core,
+ org.wso2.carbon.registry.core,
+ org.wso2.carbon.registry.core.session,
+ org.wso2.carbon.registry.core.service,
+ org.wso2.carbon.registry.api,
+ org.wso2.carbon.device.mgt.extensions.license.mgt.registry,
+ javax.net.ssl,
+ org.wso2.carbon.core.util,
+ okhttp3,
+ org.json.*,
+ com.google.gson.*,
+ com.fasterxml.jackson.core.*,
+ com.fasterxml.jackson.databind.*,
+ com.fasterxml.jackson.annotation.*
+
+
+ !io.entgra.device.mgt.subtype.mgt.internal,
+ io.entgra.device.mgt.subtype.mgt.*
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-site
+ test
+
+ report
+
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+ ${basedir}/target/coverage-reports/site
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ file:src/test/resources/carbon-home/repository/conf/log4j.properties
+
+
+
+ src/test/resources/testng.xml
+
+
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.common
+ provided
+
+
+ org.wso2.carbon.identity.inbound.auth.oauth2
+ org.wso2.carbon.identity.oauth.stub
+
+
+ org.apache.axis2.wso2
+ axis2-client
+
+
+ org.apache.geronimo.specs.wso2
+ geronimo-stax-api_1.0_spec
+
+
+ org.apache.ws.commons.axiom.wso2
+ axiom
+
+
+ org.codehaus.woodstox
+ woodstox-core-asl
+
+
+ org.codehaus.woodstox
+ wstx-asl
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.analytics.data.publisher
+
+
+ org.wso2.carbon.analytics
+ org.wso2.carbon.analytics.api
+
+
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.extensions
+ provided
+
+
+ org.codehaus.woodstox
+ stax2-api
+
+
+ org.codehaus.woodstox
+ woodstox-core-asl
+
+
+ org.wso2.carbon
+ org.wso2.carbon.securevault
+
+
+ org.apache.ws.commons.axiom.wso2
+ axiom
+
+
+
+
+ org.wso2.carbon
+ org.wso2.carbon.ndatasource.core
+ provided
+
+
+ org.wso2.securevault
+ org.wso2.securevault
+
+
+
+
+ org.wso2.carbon
+ org.wso2.carbon.base
+ provided
+
+
+ org.wso2.securevault
+ org.wso2.securevault
+
+
+ org.apache.ws.commons.axiom.wso2
+ axiom
+
+
+ org.mockito
+ mockito-core
+
+
+
+
+ org.eclipse.osgi
+ org.eclipse.osgi
+ provided
+
+
+ org.eclipse.osgi
+ org.eclipse.osgi.services
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.core
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.logging
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.utils
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.core
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.registry.api
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.registry.core
+ provided
+
+
+ org.apache.tomcat.wso2
+ jdbc-pool
+ provided
+
+
+ com.google.code.gson
+ gson
+ provided
+
+
+ io.github.openfeign
+ feign-core
+ provided
+
+
+ io.github.openfeign
+ feign-jackson
+ provided
+
+
+ io.github.openfeign
+ feign-jaxrs
+ provided
+
+
+ io.github.openfeign
+ feign-gson
+ provided
+
+
+ io.github.openfeign
+ feign-okhttp
+ provided
+
+
+ io.github.openfeign
+ feign-slf4j
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.identity.jwt.client.extension
+ provided
+
+
+ commons-validator
+ commons-validator
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxws
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxrs
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-transports-http
+ provided
+
+
+ commons-lang.wso2
+ commons-lang
+ provided
+
+
+ com.google.guava
+ guava
+
+
+ org.json
+ json
+ ${json.version}
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${fasterxml.jackson.version}
+ provided
+
+
+ org.powermock
+ powermock-module-testng
+ test
+
+
+ org.powermock
+ powermock-api-mockito
+ test
+
+
+ org.testng
+ testng
+ test
+
+
+ com.h2database.wso2
+ h2-database-engine
+ test
+
+
+ org.apache.httpcomponents.wso2
+ httpcore
+ test
+
+
+ org.wso2.apache.httpcomponents
+ httpclient
+ test
+
+
+ org.wso2.securevault
+ org.wso2.securevault
+ test
+
+
+ xerces.wso2
+ xercesImpl
+ test
+
+
+ org.apache.axis2.wso2
+ axis2
+ test
+
+
+ org.wso2.carbon
+ org.wso2.carbon.queuing
+ test
+
+
+ javax.xml.bind
+ jaxb-api
+ test
+
+
+
\ No newline at end of file
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/cache/GetDeviceSubTypeCacheLoader.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/cache/GetDeviceSubTypeCacheLoader.java
new file mode 100644
index 00000000000..d6296e4a734
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/cache/GetDeviceSubTypeCacheLoader.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.cache;
+
+import com.google.common.cache.CacheLoader;
+import io.entgra.device.mgt.subtype.mgt.dao.DeviceSubTypeDAO;
+import io.entgra.device.mgt.subtype.mgt.dao.DeviceSubTypeDAOFactory;
+import io.entgra.device.mgt.subtype.mgt.dao.util.ConnectionManagerUtil;
+import io.entgra.device.mgt.subtype.mgt.dto.DeviceSubType;
+import io.entgra.device.mgt.subtype.mgt.dto.DeviceSubTypeCacheKey;
+import io.entgra.device.mgt.subtype.mgt.exception.DBConnectionException;
+import io.entgra.device.mgt.subtype.mgt.exception.SubTypeMgtDAOException;
+import io.entgra.device.mgt.subtype.mgt.exception.SubTypeMgtPluginException;
+import io.entgra.device.mgt.subtype.mgt.util.DeviceSubTypeMgtUtil;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+public class GetDeviceSubTypeCacheLoader extends CacheLoader {
+
+ private static final Log log = LogFactory.getLog(GetDeviceSubTypeCacheLoader.class);
+
+ private final DeviceSubTypeDAO deviceSubTypeDAO;
+
+ public GetDeviceSubTypeCacheLoader() {
+ this.deviceSubTypeDAO = DeviceSubTypeDAOFactory.getDeviceSubTypeDAO();
+ }
+
+ @Override
+ public DeviceSubType load(String key) throws SubTypeMgtPluginException {
+ DeviceSubTypeCacheKey deviceSubTypeCacheKey = DeviceSubTypeMgtUtil.getDeviceSubTypeCacheKey(key);
+ int tenantId = deviceSubTypeCacheKey.getTenantId();
+ String subTypeId = deviceSubTypeCacheKey.getSubTypeId();
+ DeviceSubType.DeviceType deviceType = deviceSubTypeCacheKey.getDeviceType();
+
+ if (log.isTraceEnabled()) {
+ log.trace("Loading Device subtype for " + deviceType + " subtype & subtype Id : " + subTypeId);
+ }
+ try {
+ ConnectionManagerUtil.openDBConnection();
+ return deviceSubTypeDAO.getDeviceSubType(subTypeId, tenantId, deviceType);
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining the database connection to retrieve device subtype for " +
+ deviceType + " subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtPluginException(msg, e);
+ } catch (InvalidCacheLoadException e) {
+ String msg = "CacheLoader returned null for device subtype: " + deviceType + " subtype & subtype Id: " +
+ subTypeId;
+ log.error(msg, e);
+ return null;
+ } catch (SubTypeMgtDAOException e) {
+ String msg = "Error occurred in the database level while retrieving device subtype for " + deviceType
+ + " subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtPluginException(msg, e);
+ } finally {
+ ConnectionManagerUtil.closeDBConnection();
+ }
+ }
+
+}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAO.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAO.java
new file mode 100644
index 00000000000..9e3b889713d
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAO.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.dao;
+
+import io.entgra.device.mgt.subtype.mgt.dto.DeviceSubType;
+import io.entgra.device.mgt.subtype.mgt.exception.SubTypeMgtDAOException;
+
+import java.util.List;
+
+public interface DeviceSubTypeDAO {
+ boolean addDeviceSubType(DeviceSubType deviceSubType) throws SubTypeMgtDAOException;
+
+ boolean updateDeviceSubType(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType, String subTypeName,
+ String typeDefinition) throws SubTypeMgtDAOException;
+
+ DeviceSubType getDeviceSubType(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+
+ List getAllDeviceSubTypes(int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+
+ int getDeviceSubTypeCount(DeviceSubType.DeviceType deviceType) throws SubTypeMgtDAOException;
+
+ boolean checkDeviceSubTypeExist(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+
+ DeviceSubType getDeviceSubTypeByProvider(String subTypeName, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAOFactory.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAOFactory.java
new file mode 100644
index 00000000000..79ab3f304a9
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/DeviceSubTypeDAOFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.dao;
+
+import io.entgra.device.mgt.subtype.mgt.dao.impl.DeviceSubTypeDAOImpl;
+import io.entgra.device.mgt.subtype.mgt.dao.impl.DeviceSubTypeMySQLDAOImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
+import io.entgra.device.mgt.subtype.mgt.dao.util.ConnectionManagerUtil;
+import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
+
+public class DeviceSubTypeDAOFactory {
+ private static final Log log = LogFactory.getLog(DeviceSubTypeDAOFactory.class);
+ private static String databaseEngine;
+
+ public static void init(DataSourceConfig dataSourceConfiguration) {
+ if (log.isDebugEnabled()) {
+ log.debug("Initializing Device SubType Mgt Data Source");
+ }
+ ConnectionManagerUtil.resolveDataSource(dataSourceConfiguration);
+ databaseEngine = ConnectionManagerUtil.getDatabaseType();
+ }
+
+ public static DeviceSubTypeDAO getDeviceSubTypeDAO() {
+ if (databaseEngine != null) {
+ //noinspection SwitchStatementWithTooFewBranches
+ switch (databaseEngine) {
+ case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
+ return new DeviceSubTypeMySQLDAOImpl();
+ default:
+ return new DeviceSubTypeDAOImpl();
+ }
+ }
+ throw new IllegalStateException("Database engine has not initialized properly.");
+ }
+}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeDAOImpl.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeDAOImpl.java
new file mode 100644
index 00000000000..2b18e261b7c
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeDAOImpl.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.dao.impl;
+
+import io.entgra.device.mgt.subtype.mgt.dao.DeviceSubTypeDAO;
+import io.entgra.device.mgt.subtype.mgt.dao.util.ConnectionManagerUtil;
+import io.entgra.device.mgt.subtype.mgt.dto.DeviceSubType;
+import io.entgra.device.mgt.subtype.mgt.dao.util.DAOUtil;
+import io.entgra.device.mgt.subtype.mgt.exception.DBConnectionException;
+import io.entgra.device.mgt.subtype.mgt.exception.SubTypeMgtDAOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+
+public class DeviceSubTypeDAOImpl implements DeviceSubTypeDAO {
+ private static final Log log = LogFactory.getLog(DeviceSubTypeDAOImpl.class);
+
+ @Override
+ public boolean addDeviceSubType(DeviceSubType deviceSubType) throws SubTypeMgtDAOException {
+ try {
+ String sql = "INSERT INTO DM_DEVICE_SUB_TYPE (SUB_TYPE_ID, TENANT_ID, DEVICE_TYPE, SUB_TYPE_NAME, " +
+ "TYPE_DEFINITION) VALUES (?, ?, ?, ?, ?)";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, deviceSubType.getSubTypeId());
+ stmt.setInt(2, deviceSubType.getTenantId());
+ stmt.setString(3, deviceSubType.getDeviceType().toString());
+ stmt.setString(4, deviceSubType.getSubTypeName());
+ stmt.setString(5, deviceSubType.getTypeDefinition());
+ return stmt.executeUpdate() > 0;
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to insert device sub type for " +
+ deviceSubType.getDeviceType() + " subtype & subtype Id: " + deviceSubType.getSubTypeId();
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to insert device sub type for " +
+ deviceSubType.getDeviceType() + " subtype & subtype Id: " + deviceSubType.getSubTypeId();
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public boolean updateDeviceSubType(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType,
+ String subTypeName, String typeDefinition)
+ throws SubTypeMgtDAOException {
+ try {
+ String sql = "UPDATE DM_DEVICE_SUB_TYPE SET TYPE_DEFINITION = ? , SUB_TYPE_NAME = ? WHERE SUB_TYPE_ID = ? "
+ + "AND TENANT_ID = ? AND DEVICE_TYPE = ?";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, typeDefinition);
+ stmt.setString(2, subTypeName);
+ stmt.setString(3, subTypeId);
+ stmt.setInt(4, tenantId);
+ stmt.setString(5, deviceType.toString());
+ return stmt.executeUpdate() > 0;
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to update device sub type for " +
+ deviceType + " subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to update device sub type for " +
+ deviceType + " subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public DeviceSubType getDeviceSubType(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT * FROM DM_DEVICE_SUB_TYPE WHERE SUB_TYPE_ID = ? AND TENANT_ID = ? AND DEVICE_TYPE = ?";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, subTypeId);
+ stmt.setInt(2, tenantId);
+ stmt.setString(3, deviceType.toString());
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+ return DAOUtil.loadDeviceSubType(rs);
+ }
+ return null;
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve device subtype for " + deviceType
+ + " subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to retrieve device subtype for " + deviceType + " " +
+ "subtype & subtype Id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public List getAllDeviceSubTypes(int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT * FROM DM_DEVICE_SUB_TYPE WHERE TENANT_ID = ? AND DEVICE_TYPE = ? ORDER BY " +
+ "SUB_TYPE_ID";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setInt(1, tenantId);
+ stmt.setString(2, deviceType.toString());
+ try (ResultSet rs = stmt.executeQuery()) {
+ return DAOUtil.loadDeviceSubTypes(rs);
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve all device sub types for " +
+ deviceType + " subtypes";
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to retrieve all device sub types for " + deviceType + " "
+ + "subtypes";
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public int getDeviceSubTypeCount(DeviceSubType.DeviceType deviceType) throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT COUNT(*) as DEVICE_COUNT FROM DM_DEVICE_SUB_TYPE WHERE DEVICE_TYPE = ? ";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, deviceType.toString());
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+ return rs.getInt("DEVICE_COUNT");
+ }
+ return 0;
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve device sub types count for " +
+ deviceType + " subtypes";
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to retrieve device sub types count for " + deviceType +
+ " subtypes";
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public boolean checkDeviceSubTypeExist(String subTypeId, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT * FROM DM_DEVICE_SUB_TYPE WHERE SUB_TYPE_ID = ? AND TENANT_ID = ? AND DEVICE_TYPE " +
+ "= ? ";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, subTypeId);
+ stmt.setInt(2, tenantId);
+ stmt.setString(3, deviceType.toString());
+ try (ResultSet rs = stmt.executeQuery()) {
+ return rs.next();
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to check device subtype exist for " + deviceType
+ + " subtype & subtype id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to check device subtype exist for " + deviceType + " " +
+ "subtype & subtype id: " + subTypeId;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+
+ @Override
+ public DeviceSubType getDeviceSubTypeByProvider(String subTypeName, int tenantId,
+ DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT * FROM DM_DEVICE_SUB_TYPE WHERE SUB_TYPE_NAME = ? AND TENANT_ID = ? AND DEVICE_TYPE " +
+ "= ? ";
+
+ Connection conn = ConnectionManagerUtil.getDBConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, subTypeName);
+ stmt.setInt(2, tenantId);
+ stmt.setString(3, deviceType.toString());
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+ return DAOUtil.loadDeviceSubType(rs);
+ }
+ return null;
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve device subtype for " + deviceType
+ + " subtype & subtype name: " + subTypeName;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to retrieve device subtype for " + deviceType + " " +
+ "subtype & subtype name: " + subTypeName;
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ }
+ }
+}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeMySQLDAOImpl.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeMySQLDAOImpl.java
new file mode 100644
index 00000000000..972d16e1c58
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/impl/DeviceSubTypeMySQLDAOImpl.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.dao.impl;
+
+/**
+ * Implementation for MySQL
+ */
+public class DeviceSubTypeMySQLDAOImpl extends DeviceSubTypeDAOImpl {
+}
diff --git a/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/util/ConnectionManagerUtil.java b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/util/ConnectionManagerUtil.java
new file mode 100644
index 00000000000..7663ae94fc1
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/src/main/java/io/entgra/device/mgt/subtype/mgt/dao/util/ConnectionManagerUtil.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2023, Entgra Pvt Ltd. (http://www.wso2.org) 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 io.entgra.device.mgt.subtype.mgt.dao.util;
+
+import io.entgra.device.mgt.subtype.mgt.exception.DBConnectionException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.common.exceptions.IllegalTransactionStateException;
+import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
+import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
+
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.List;
+
+public class ConnectionManagerUtil {
+
+ private static final Log log = LogFactory.getLog(ConnectionManagerUtil.class);
+ private static final ThreadLocal currentConnection = new ThreadLocal<>();
+ private static DataSource dataSource;
+
+ public static void openDBConnection() throws DBConnectionException {
+ Connection conn = currentConnection.get();
+ if (conn != null) {
+ throw new IllegalTransactionStateException("Database connection has already been obtained.");
+ }
+ try {
+ conn = dataSource.getConnection();
+ } catch (SQLException e) {
+ throw new DBConnectionException("Failed to get a database connection.", e);
+ }
+ currentConnection.set(conn);
+ }
+
+ public static Connection getDBConnection() throws DBConnectionException {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ try {
+ conn = dataSource.getConnection();
+ currentConnection.set(conn);
+ } catch (SQLException e) {
+ throw new DBConnectionException("Failed to get database connection.", e);
+ }
+ }
+ return conn;
+ }
+
+ public static void beginDBTransaction() throws DBConnectionException {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ conn = getDBConnection();
+ } else if (inTransaction(conn)) {
+ throw new IllegalTransactionStateException("Transaction has already been started.");
+ }
+
+ try {
+ conn.setAutoCommit(false);
+ } catch (SQLException e) {
+ throw new DBConnectionException("Error occurred while starting a database transaction.", e);
+ }
+ }
+
+ public static void endDBTransaction() throws DBConnectionException {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ throw new IllegalTransactionStateException("Database connection is not active.");
+ }
+
+ if (!inTransaction(conn)) {
+ throw new IllegalTransactionStateException("Transaction has not been started.");
+ }
+
+ try {
+ conn.setAutoCommit(true);
+ } catch (SQLException e) {
+ throw new DBConnectionException("Error occurred while ending database transaction.", e);
+ }
+ }
+
+ public static void commitDBTransaction() {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ throw new IllegalTransactionStateException("Database connection is not active.");
+ }
+
+ if (!inTransaction(conn)) {
+ throw new IllegalTransactionStateException("Transaction has not been started.");
+ }
+
+ try {
+ conn.commit();
+ } catch (SQLException e) {
+ log.error("Error occurred while committing the transaction", e);
+ }
+ }
+
+ public static void rollbackDBTransaction() {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ throw new IllegalTransactionStateException("Database connection is not active.");
+ }
+
+ if (!inTransaction(conn)) {
+ throw new IllegalTransactionStateException("Transaction has not been started.");
+ }
+
+ try {
+ conn.rollback();
+ } catch (SQLException e) {
+ log.warn("Error occurred while roll-backing the transaction", e);
+ }
+ }
+
+ public static void closeDBConnection() {
+ Connection conn = currentConnection.get();
+ if (conn == null) {
+ throw new IllegalTransactionStateException("Database connection is not active.");
+ }
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ log.error("Error occurred while closing the connection", e);
+ }
+ currentConnection.remove();
+ }
+
+ private static boolean inTransaction(Connection conn) {
+ boolean inTransaction = true;
+ try {
+ if (conn.getAutoCommit()) {
+ inTransaction = false;
+ }
+ } catch (SQLException e) {
+ throw new IllegalTransactionStateException("Failed to get transaction state.");
+ }
+ return inTransaction;
+ }
+
+ public static boolean isTransactionStarted() throws DBConnectionException {
+ Connection connection = getDBConnection();
+ return inTransaction(connection);
+ }
+
+ /**
+ * Resolve data source from the data source definition.
+ *
+ * @param config Data source configuration
+ * @return data source resolved from the data source definition
+ */
+ public static DataSource resolveDataSource(DataSourceConfig config) {
+ if (config == null) {
+ throw new RuntimeException("Device Management Repository data source configuration " +
+ "is null and thus, is not initialized");
+ }
+ JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition();
+ if (jndiConfig != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Initializing Device Management Repository data source using the JNDI " +
+ "Lookup Definition");
+ }
+ List jndiPropertyList =
+ jndiConfig.getJndiProperties();
+ if (jndiPropertyList != null) {
+ Hashtable