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 0000000000..53b037ff52
--- /dev/null
+++ b/components/subtype-mgt/io.entgra.device.mgt.subtype.mgt/pom.xml
@@ -0,0 +1,413 @@
+
+
+
+
+ org.wso2.carbon.devicemgt
+ subtype-mgt
+ 5.0.20-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 0000000000..3070f38c63
--- /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,79 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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();
+ int 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 0000000000..1b3ca0ce41
--- /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) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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(int subTypeId, int tenantId, DeviceSubType.DeviceType deviceType, String subTypeName,
+ String typeDefinition) throws SubTypeMgtDAOException;
+
+ DeviceSubType getDeviceSubType(int subTypeId, int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+
+ List getAllDeviceSubTypes(int tenantId, DeviceSubType.DeviceType deviceType)
+ throws SubTypeMgtDAOException;
+
+ int getDeviceSubTypeCount(DeviceSubType.DeviceType deviceType) throws SubTypeMgtDAOException;
+
+ int getMaxSubTypeId(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 0000000000..d92fc28352
--- /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,54 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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 0000000000..6d7dcf5e25
--- /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,254 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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.setInt(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(int 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.setInt(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(int 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.setInt(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 int getMaxSubTypeId(DeviceSubType.DeviceType deviceType) throws SubTypeMgtDAOException {
+ try {
+ String sql = "SELECT COALESCE(MAX(SUB_TYPE_ID),0) as MAX_ID 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("MAX_ID");
+ }
+ return 0;
+ }
+ }
+
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve max device subtype id for " +
+ deviceType + " subtype";
+ log.error(msg);
+ throw new SubTypeMgtDAOException(msg, e);
+ } catch (SQLException e) {
+ String msg = "Error occurred while processing SQL to retrieve max device subtype id for " + deviceType
+ + " subtype";
+ 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 0000000000..defb15afa7
--- /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,26 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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 0000000000..f6615254ed
--- /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,220 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.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