mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Fix for sycning status update in Android
This commit is contained in:
parent
b98d787367
commit
8effa09a8f
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.common.device.details;
|
||||||
|
|
||||||
|
import org.wso2.carbon.device.mgt.common.Device;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class DeviceMonitoringData implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2448141793L;
|
||||||
|
long lastUpdatedTime;
|
||||||
|
Device device;
|
||||||
|
int tenantId;
|
||||||
|
|
||||||
|
public int getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(int tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevice(Device device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastUpdatedTime() {
|
||||||
|
return lastUpdatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUpdatedTime(long lastUpdatedTime) {
|
||||||
|
this.lastUpdatedTime = lastUpdatedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.common.Count;
|
|||||||
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||||
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
|
||||||
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
|
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
|
||||||
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
|
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
|
||||||
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
||||||
@ -682,6 +683,19 @@ public interface DeviceDAO {
|
|||||||
int getCountOfDeviceExpiredByOSVersion(String deviceType, Long osValue, int tenantId)
|
int getCountOfDeviceExpiredByOSVersion(String deviceType, Long osValue, int tenantId)
|
||||||
throws DeviceManagementDAOException;
|
throws DeviceManagementDAOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get All devices for monitoring
|
||||||
|
* @param deviceTypeId device type identifier
|
||||||
|
* @param deviceTypeName name of the type. (android, ios ...)
|
||||||
|
* @param activeServerCount Number of available servers
|
||||||
|
* @param serverHashIndex server index number
|
||||||
|
* @return device object
|
||||||
|
* @throws DeviceManagementDAOException
|
||||||
|
*/
|
||||||
|
List<DeviceMonitoringData> getAllDevicesForMonitoring(int deviceTypeId, String deviceTypeName,
|
||||||
|
int activeServerCount, int serverHashIndex)
|
||||||
|
throws DeviceManagementDAOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a paginated list of devices filtered by given encryption status
|
* Get a paginated list of devices filtered by given encryption status
|
||||||
*
|
*
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
|||||||
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||||
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||||
@ -2784,4 +2785,56 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
|
|||||||
}
|
}
|
||||||
return deviceCount;
|
return deviceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeviceMonitoringData> getAllDevicesForMonitoring(
|
||||||
|
int deviceTypeId, String deviceTypeName, int activeServerCount, int serverHashIndex)
|
||||||
|
throws DeviceManagementDAOException {
|
||||||
|
List<DeviceMonitoringData> devices = new ArrayList<>();
|
||||||
|
|
||||||
|
String sql = "SELECT D.ID AS DEVICE_ID," +
|
||||||
|
" D.NAME AS DEVICE_NAME, " +
|
||||||
|
" D.DESCRIPTION AS DESCRIPTION," +
|
||||||
|
" D.DEVICE_IDENTIFICATION, " +
|
||||||
|
" D.LAST_UPDATED_TIMESTAMP, " +
|
||||||
|
" D.TENANT_ID, " +
|
||||||
|
" E.ENROLMENT_ID, " +
|
||||||
|
" EN.OWNER, " +
|
||||||
|
" EN.OWNERSHIP, " +
|
||||||
|
" EN.IS_TRANSFERRED, " +
|
||||||
|
" EN.DATE_OF_ENROLMENT, " +
|
||||||
|
" EN.DATE_OF_LAST_UPDATE, " +
|
||||||
|
" EN.STATUS " +
|
||||||
|
"FROM DM_DEVICE D, DM_ENROLMENT EN," +
|
||||||
|
" (SELECT DEVICE_ID, MAX(ID) AS ENROLMENT_ID" +
|
||||||
|
" FROM DM_ENROLMENT" +
|
||||||
|
" WHERE STATUS IN ('ACTIVE', 'UNREACHABLE') " +
|
||||||
|
" GROUP BY DEVICE_ID) E" +
|
||||||
|
" WHERE D.ID = E.DEVICE_ID AND E.ENROLMENT_ID = EN.ID AND D.DEVICE_TYPE_ID = ?";
|
||||||
|
if (activeServerCount > 0) {
|
||||||
|
sql += " AND MOD(D.ID, ?) = ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Connection conn = this.getConnection();
|
||||||
|
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
stmt.setInt(1, deviceTypeId);
|
||||||
|
if (activeServerCount > 0) {
|
||||||
|
stmt.setInt(2, activeServerCount);
|
||||||
|
stmt.setInt(3, serverHashIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ResultSet rs = stmt.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
devices.add(DeviceManagementDAOUtil.loadDevice(rs, deviceTypeName));
|
||||||
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
String msg = "Error occurred while retrieving devices";
|
||||||
|
log.error(msg, e);
|
||||||
|
throw new DeviceManagementDAOException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
|||||||
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
|
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo;
|
||||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||||
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||||
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
|
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
|
||||||
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
|
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
|
||||||
@ -196,6 +197,23 @@ public final class DeviceManagementDAOUtil {
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DeviceMonitoringData loadDevice(ResultSet rs, String deviceTypeName) throws SQLException {
|
||||||
|
Device device = new Device();
|
||||||
|
device.setId(rs.getInt("DEVICE_ID"));
|
||||||
|
device.setName(rs.getString("DEVICE_NAME"));
|
||||||
|
device.setDescription(rs.getString("DESCRIPTION"));
|
||||||
|
device.setType(deviceTypeName);
|
||||||
|
device.setDeviceIdentifier(rs.getString("DEVICE_IDENTIFICATION"));
|
||||||
|
device.setEnrolmentInfo(loadEnrolment(rs));
|
||||||
|
|
||||||
|
DeviceMonitoringData deviceMonitoringData = new DeviceMonitoringData();
|
||||||
|
deviceMonitoringData.setLastUpdatedTime(rs
|
||||||
|
.getTimestamp("LAST_UPDATED_TIMESTAMP").getTime());
|
||||||
|
deviceMonitoringData.setTenantId(rs.getInt("TENANT_ID"));
|
||||||
|
deviceMonitoringData.setDevice(device);
|
||||||
|
return deviceMonitoringData;
|
||||||
|
}
|
||||||
|
|
||||||
//This method will retrieve most appropriate device information when there are multiple device enrollments for
|
//This method will retrieve most appropriate device information when there are multiple device enrollments for
|
||||||
//a single device. Here we'll consider only active status.
|
//a single device. Here we'll consider only active status.
|
||||||
public static Device loadActiveDevice(ResultSet rs, boolean deviceInfoIncluded) throws SQLException {
|
public static Device loadActiveDevice(ResultSet rs, boolean deviceInfoIncluded) throws SQLException {
|
||||||
|
|||||||
@ -19,13 +19,10 @@
|
|||||||
package org.wso2.carbon.device.mgt.core.operation.mgt.dao;
|
package org.wso2.carbon.device.mgt.core.operation.mgt.dao;
|
||||||
|
|
||||||
import org.wso2.carbon.device.mgt.common.Device;
|
import org.wso2.carbon.device.mgt.common.Device;
|
||||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
|
||||||
import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation;
|
import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation;
|
||||||
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationEnrolmentMapping;
|
|
||||||
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping;
|
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface OperationMappingDAO {
|
public interface OperationMappingDAO {
|
||||||
|
|
||||||
@ -41,63 +38,5 @@ public interface OperationMappingDAO {
|
|||||||
void updateOperationMapping(List<OperationMapping> operationMappingList) throws
|
void updateOperationMapping(List<OperationMapping> operationMappingList) throws
|
||||||
OperationManagementDAOException;
|
OperationManagementDAOException;
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns first pending/repeated operation available for each active enrolment of given device-type
|
|
||||||
* where the operation was created after the given timestamp.
|
|
||||||
*
|
|
||||||
* @param minDuration - Upper limit of Operation created time
|
|
||||||
* @param maxDuration - Lower limit of Operation created time
|
|
||||||
* @param deviceTypeId - Device Type Id of required devices
|
|
||||||
* @return List<OperationEnrolmentMapping> - List of OperationEnrolmentMapping objects containing required data
|
|
||||||
* @throws OperationManagementDAOException
|
|
||||||
*/
|
|
||||||
List<OperationEnrolmentMapping> getFirstPendingOperationMappingsForActiveEnrolments(long minDuration,
|
|
||||||
long maxDuration, int deviceTypeId)
|
|
||||||
throws OperationManagementDAOException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns first pending/repeated operation available for each active enrolment of given device-type
|
|
||||||
* in a task partitioned execution scenario
|
|
||||||
* where the operation was created after the given timestamp.
|
|
||||||
*
|
|
||||||
* @param minDuration
|
|
||||||
* @param maxDuration
|
|
||||||
* @param deviceTypeId
|
|
||||||
* @param activeServerCount
|
|
||||||
* @param serverHashIndex
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<OperationEnrolmentMapping> getFirstPendingOperationMappingsForActiveEnrolments(long minDuration,
|
|
||||||
long maxDuration, int deviceTypeId,
|
|
||||||
int activeServerCount, int serverHashIndex)
|
|
||||||
throws OperationManagementDAOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the timestamp of last completed Operation for each active enrolment of given device-type
|
|
||||||
* where the operation was completed after the given timestamp.
|
|
||||||
*
|
|
||||||
* @param timeStamp - Timestamp of considered time-interval
|
|
||||||
* @param deviceTypeId - Device Type of required devices
|
|
||||||
* @return List<OperationEnrolmentMapping> - List of OperationEnrolmentMapping objects containing required data
|
|
||||||
* @throws OperationManagementDAOException
|
|
||||||
*/
|
|
||||||
Map<Integer, Long> getLastConnectedTimeForActiveEnrolments(long timeStamp, int deviceTypeId)
|
|
||||||
throws OperationManagementDAOException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the timestamp of last completed Operation for each active enrolment of given device-type
|
|
||||||
* in a task partitioned execution scenario
|
|
||||||
* where the operation was completed after the given timestamp.
|
|
||||||
*
|
|
||||||
* @param timeStamp
|
|
||||||
* @param deviceTypeId
|
|
||||||
* @param activeServerCount
|
|
||||||
* @param serverHashIndex
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Map<Integer, Long> getLastConnectedTimeForActiveEnrolments(long timeStamp, int deviceTypeId, int activeServerCount, int serverHashIndex)
|
|
||||||
throws OperationManagementDAOException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -194,154 +194,6 @@ public class OperationMappingDAOImpl implements OperationMappingDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<OperationEnrolmentMapping> getFirstPendingOperationMappingsForActiveEnrolments(long minDuration,
|
|
||||||
long maxDuration, int deviceTypeId) throws OperationManagementDAOException {
|
|
||||||
PreparedStatement stmt = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
List<OperationEnrolmentMapping> enrolmentOperationMappingList;
|
|
||||||
try {
|
|
||||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
|
||||||
//We are specifically looking for operation mappings in 'Pending' & 'Repeated' states. Further we want
|
|
||||||
//devices to be active at that moment. Hence filtering by 'ACTIVE' & 'UNREACHABLE' device states.
|
|
||||||
String sql = "SELECT ENROLMENT_ID, D.DEVICE_IDENTIFICATION AS DEVICE_IDENTIFIER, MIN(CREATED_TIMESTAMP) " +
|
|
||||||
"AS CREATED_TIMESTAMP, E.STATUS AS ENROLMENT_STATUS, E.TENANT_ID FROM " +
|
|
||||||
"DM_ENROLMENT_OP_MAPPING OP INNER JOIN DM_ENROLMENT E ON OP.ENROLMENT_ID = E.ID INNER JOIN " +
|
|
||||||
"DM_DEVICE D ON E.DEVICE_ID = D.ID WHERE " +
|
|
||||||
"OP.STATUS IN ('"+ Operation.Status.PENDING.name() + "','" + Operation.Status.REPEATED.name() + "') " +
|
|
||||||
"AND OP.CREATED_TIMESTAMP BETWEEN ? AND ? AND E.STATUS IN ('" + EnrolmentInfo.Status.ACTIVE.name() +
|
|
||||||
"','" + EnrolmentInfo.Status.UNREACHABLE.name() + "') AND D.DEVICE_TYPE_ID = ? GROUP BY ENROLMENT_ID," +
|
|
||||||
" D.DEVICE_IDENTIFICATION, E.STATUS, E.TENANT_ID";
|
|
||||||
stmt = conn.prepareStatement(sql);
|
|
||||||
stmt.setLong(1, maxDuration);
|
|
||||||
stmt.setLong(2, minDuration);
|
|
||||||
stmt.setInt(3, deviceTypeId);
|
|
||||||
rs = stmt.executeQuery();
|
|
||||||
enrolmentOperationMappingList = new ArrayList<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
OperationEnrolmentMapping enrolmentOperationMapping = this.getEnrolmentOpMapping(rs);
|
|
||||||
enrolmentOperationMappingList.add(enrolmentOperationMapping);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new OperationManagementDAOException("Error occurred while fetching pending operation mappings for " +
|
|
||||||
"active devices of type '" + deviceTypeId + "'", e);
|
|
||||||
} finally {
|
|
||||||
OperationManagementDAOUtil.cleanupResources(stmt, rs);
|
|
||||||
}
|
|
||||||
return enrolmentOperationMappingList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<OperationEnrolmentMapping> getFirstPendingOperationMappingsForActiveEnrolments(
|
|
||||||
long minDuration,
|
|
||||||
long maxDuration, int deviceTypeId,
|
|
||||||
int activeServerCount, int serverHashIndex) throws OperationManagementDAOException {
|
|
||||||
List<OperationEnrolmentMapping> enrolmentOperationMappingList;
|
|
||||||
try {
|
|
||||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
|
||||||
//We are specifically looking for operation mappings in 'Pending' & 'Repeated' states. Further we want
|
|
||||||
//devices to be active at that moment. Hence filtering by 'ACTIVE' & 'UNREACHABLE' device states.
|
|
||||||
String sql = "SELECT ENROLMENT_ID, D.DEVICE_IDENTIFICATION AS DEVICE_IDENTIFIER, MIN(CREATED_TIMESTAMP) " +
|
|
||||||
"AS CREATED_TIMESTAMP, E.STATUS AS ENROLMENT_STATUS, E.TENANT_ID FROM " +
|
|
||||||
"DM_ENROLMENT_OP_MAPPING OP INNER JOIN DM_ENROLMENT E ON OP.ENROLMENT_ID = E.ID INNER JOIN " +
|
|
||||||
"DM_DEVICE D ON E.DEVICE_ID = D.ID WHERE " +
|
|
||||||
"OP.STATUS IN ('" + Operation.Status.PENDING.name() + "','" + Operation.Status.REPEATED.name() + "') " +
|
|
||||||
"AND OP.CREATED_TIMESTAMP BETWEEN ? AND ? AND E.STATUS IN ('" + EnrolmentInfo.Status.ACTIVE.name() +
|
|
||||||
"','" + EnrolmentInfo.Status.UNREACHABLE.name() + "') AND D.DEVICE_TYPE_ID = ? AND MOD(D.ID, ?) = ? GROUP BY ENROLMENT_ID," +
|
|
||||||
" D.DEVICE_IDENTIFICATION, E.STATUS, E.TENANT_ID";
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
||||||
stmt.setLong(1, maxDuration);
|
|
||||||
stmt.setLong(2, minDuration);
|
|
||||||
stmt.setInt(3, deviceTypeId);
|
|
||||||
stmt.setInt(4, activeServerCount);
|
|
||||||
stmt.setInt(5, serverHashIndex);
|
|
||||||
try (ResultSet rs = stmt.executeQuery()) {
|
|
||||||
enrolmentOperationMappingList = new ArrayList<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
OperationEnrolmentMapping enrolmentOperationMapping = this.getEnrolmentOpMapping(rs);
|
|
||||||
enrolmentOperationMappingList.add(enrolmentOperationMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
String msg = "Error occurred while fetching pending operation mappings for " +
|
|
||||||
"active devices of type '" + deviceTypeId + "'";
|
|
||||||
log.error(msg, e);
|
|
||||||
throw new OperationManagementDAOException(msg, e);
|
|
||||||
}
|
|
||||||
return enrolmentOperationMappingList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<Integer, Long> getLastConnectedTimeForActiveEnrolments(long timeStamp, int deviceTypeId) throws OperationManagementDAOException {
|
|
||||||
PreparedStatement stmt = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
Map<Integer, Long> lastConnectedTimeMap = null;
|
|
||||||
try {
|
|
||||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
|
||||||
//We are specifically looking for operation mappings in 'Pending' & 'Repeated' states. Further we want
|
|
||||||
//devices to be active at that moment. Hence filtering by 'ACTIVE' & 'UNREACHABLE' device states.
|
|
||||||
String sql = "SELECT OP.ENROLMENT_ID AS EID, MAX(OP.UPDATED_TIMESTAMP) AS LAST_CONNECTED_TIME FROM " +
|
|
||||||
"DM_ENROLMENT_OP_MAPPING OP INNER JOIN DM_ENROLMENT E ON OP.ENROLMENT_ID = E.ID INNER JOIN " +
|
|
||||||
"DM_DEVICE D ON E.DEVICE_ID = D.ID WHERE " +
|
|
||||||
"OP.STATUS = '" + Operation.Status.COMPLETED.name() + "'" +
|
|
||||||
"AND OP.UPDATED_TIMESTAMP >= ? AND E.STATUS IN ('" + EnrolmentInfo.Status.ACTIVE.name() +
|
|
||||||
"','" + EnrolmentInfo.Status.UNREACHABLE.name() + "') AND D.DEVICE_TYPE_ID = ? GROUP BY ENROLMENT_ID";
|
|
||||||
stmt = conn.prepareStatement(sql);
|
|
||||||
stmt.setLong(1, timeStamp);
|
|
||||||
stmt.setInt(2, deviceTypeId);
|
|
||||||
rs = stmt.executeQuery();
|
|
||||||
lastConnectedTimeMap = new HashMap<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
lastConnectedTimeMap.put(rs.getInt("EID"), rs.getLong("LAST_CONNECTED_TIME"));
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new OperationManagementDAOException("Error occurred while fetching last connected time for " +
|
|
||||||
"active devices of type '" + deviceTypeId + "'", e);
|
|
||||||
} finally {
|
|
||||||
OperationManagementDAOUtil.cleanupResources(stmt, rs);
|
|
||||||
}
|
|
||||||
return lastConnectedTimeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<Integer, Long> getLastConnectedTimeForActiveEnrolments(long timeStamp,
|
|
||||||
int deviceTypeId,
|
|
||||||
int activeServerCount,
|
|
||||||
int serverHashIndex)
|
|
||||||
throws OperationManagementDAOException {
|
|
||||||
Map<Integer, Long> lastConnectedTimeMap = null;
|
|
||||||
try {
|
|
||||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
|
||||||
//We are specifically looking for operation mappings in 'Pending' & 'Repeated' states. Further we want
|
|
||||||
//devices to be active at that moment. Hence filtering by 'ACTIVE' & 'UNREACHABLE' device states.
|
|
||||||
String sql = "SELECT OP.ENROLMENT_ID AS EID, MAX(OP.UPDATED_TIMESTAMP) AS LAST_CONNECTED_TIME FROM " +
|
|
||||||
"DM_ENROLMENT_OP_MAPPING OP INNER JOIN DM_ENROLMENT E ON OP.ENROLMENT_ID = E.ID INNER JOIN " +
|
|
||||||
"DM_DEVICE D ON E.DEVICE_ID = D.ID WHERE " +
|
|
||||||
"OP.STATUS = '" + Operation.Status.COMPLETED.name() + "'" +
|
|
||||||
"AND OP.UPDATED_TIMESTAMP >= ? AND E.STATUS IN ('" + EnrolmentInfo.Status.ACTIVE.name() +
|
|
||||||
"','" + EnrolmentInfo.Status.UNREACHABLE.name() + "') AND D.DEVICE_TYPE_ID = ? AND MOD(D.ID, ?) = ? GROUP BY ENROLMENT_ID";
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
||||||
stmt.setLong(1, timeStamp);
|
|
||||||
stmt.setInt(2, deviceTypeId);
|
|
||||||
stmt.setInt(3, activeServerCount);
|
|
||||||
stmt.setInt(4, serverHashIndex);
|
|
||||||
try (ResultSet rs = stmt.executeQuery()) {
|
|
||||||
lastConnectedTimeMap = new HashMap<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
lastConnectedTimeMap.put(rs.getInt("EID"), rs.getLong("LAST_CONNECTED_TIME"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
String msg = "Error occurred while fetching last connected time for " +
|
|
||||||
"active devices of type '" + deviceTypeId + "'";
|
|
||||||
log.error(msg, e);
|
|
||||||
throw new OperationManagementDAOException(msg, e);
|
|
||||||
}
|
|
||||||
return lastConnectedTimeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OperationEnrolmentMapping getEnrolmentOpMapping(ResultSet rs) throws SQLException {
|
private OperationEnrolmentMapping getEnrolmentOpMapping(ResultSet rs) throws SQLException {
|
||||||
OperationEnrolmentMapping enrolmentOperationMapping = new OperationEnrolmentMapping();
|
OperationEnrolmentMapping enrolmentOperationMapping = new OperationEnrolmentMapping();
|
||||||
enrolmentOperationMapping.setEnrolmentId(rs.getInt("ENROLMENT_ID"));
|
enrolmentOperationMapping.setEnrolmentId(rs.getInt("ENROLMENT_ID"));
|
||||||
|
|||||||
@ -1405,6 +1405,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
|||||||
log.debug(msg);
|
log.debug(msg);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
Device deviceFromCache = getDeviceFromCache(deviceData.getDeviceIdentifier());
|
||||||
|
if (deviceFromCache != null && device.getEnrolmentInfo() != null &&
|
||||||
|
deviceFromCache.getEnrolmentInfo().getStatus() != device.getEnrolmentInfo().getStatus()) {
|
||||||
|
this.addDeviceToCache(deviceData.getDeviceIdentifier(), device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (DeviceManagementDAOException e) {
|
} catch (DeviceManagementDAOException e) {
|
||||||
String msg =
|
String msg =
|
||||||
|
|||||||
@ -21,24 +21,18 @@ package org.wso2.carbon.device.mgt.core.status.task.impl;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.wso2.carbon.device.mgt.common.Device;
|
|
||||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||||
import org.wso2.carbon.device.mgt.common.DeviceStatusTaskPluginConfig;
|
import org.wso2.carbon.device.mgt.common.DeviceStatusTaskPluginConfig;
|
||||||
import org.wso2.carbon.device.mgt.common.DynamicTaskContext;
|
import org.wso2.carbon.device.mgt.common.DynamicTaskContext;
|
||||||
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
|
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
|
||||||
|
import org.wso2.carbon.device.mgt.common.device.details.DeviceMonitoringData;
|
||||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||||
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
|
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
|
||||||
import org.wso2.carbon.device.mgt.core.cache.impl.DeviceCacheManagerImpl;
|
import org.wso2.carbon.device.mgt.core.cache.impl.DeviceCacheManagerImpl;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||||
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
|
|
||||||
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationEnrolmentMapping;
|
|
||||||
import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException;
|
|
||||||
import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory;
|
|
||||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
|
||||||
import org.wso2.carbon.device.mgt.core.status.task.DeviceStatusTaskException;
|
import org.wso2.carbon.device.mgt.core.status.task.DeviceStatusTaskException;
|
||||||
import org.wso2.carbon.device.mgt.core.task.impl.DynamicPartitionedScheduleTask;
|
import org.wso2.carbon.device.mgt.core.task.impl.DynamicPartitionedScheduleTask;
|
||||||
import org.wso2.carbon.ntask.core.Task;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -67,64 +61,65 @@ public class DeviceStatusMonitoringTask extends DynamicPartitionedScheduleTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setup() {
|
protected void setup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeviceMonitoringData> getAllDevicesForMonitoring() throws DeviceManagementException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
DeviceManagementDAOFactory.openConnection();
|
||||||
|
DynamicTaskContext ctx = getTaskContext();
|
||||||
|
if (ctx != null && ctx.isPartitioningEnabled()) {
|
||||||
|
return DeviceManagementDAOFactory.getDeviceDAO()
|
||||||
|
.getAllDevicesForMonitoring(this.deviceTypeId, this.deviceType,
|
||||||
|
ctx.getActiveServerCount(), ctx.getServerHashIndex());
|
||||||
|
} else {
|
||||||
|
return DeviceManagementDAOFactory.getDeviceDAO()
|
||||||
|
.getAllDevicesForMonitoring(this.deviceTypeId, this.deviceType, -1, -1);
|
||||||
|
}
|
||||||
|
} catch (DeviceManagementDAOException e) {
|
||||||
|
String msg = "Error occurred while retrieving devices list for monitoring.";
|
||||||
|
log.error(msg, e);
|
||||||
|
throw new DeviceManagementException(msg, e);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
String msg = "Error occurred while opening a connection to the data source";
|
||||||
|
log.error(msg, e);
|
||||||
|
throw new DeviceManagementException(msg, e);
|
||||||
|
} finally {
|
||||||
|
DeviceManagementDAOFactory.closeConnection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeDynamicTask() {
|
public void executeDynamicTask() {
|
||||||
List<OperationEnrolmentMapping> operationEnrolmentMappings;
|
try {
|
||||||
List<EnrolmentInfo> enrolmentInfoTobeUpdated = new ArrayList<>();
|
List<EnrolmentInfo> enrolmentInfoTobeUpdated = new ArrayList<>();
|
||||||
Map<Integer, Long> lastActivities = null;
|
List<DeviceMonitoringData> allDevicesForMonitoring = getAllDevicesForMonitoring();
|
||||||
EnrolmentInfo enrolmentInfo;
|
long timeMillis = System.currentTimeMillis();
|
||||||
DeviceIdentifier deviceIdentifier;
|
for (DeviceMonitoringData monitoringData : allDevicesForMonitoring) {
|
||||||
Device device;
|
long lastUpdatedTime = (timeMillis - monitoringData
|
||||||
try {
|
.getLastUpdatedTime()) / 1000;
|
||||||
operationEnrolmentMappings = this.getOperationEnrolmentMappings(super.getTaskContext());
|
|
||||||
if (!operationEnrolmentMappings.isEmpty()) {
|
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
|
||||||
lastActivities = this.getLastDeviceActivities(super.getTaskContext());
|
enrolmentInfo.setId(monitoringData.getDevice().getEnrolmentInfo().getId());
|
||||||
}
|
EnrolmentInfo.Status status = null;
|
||||||
} catch (DeviceStatusTaskException e) {
|
if (lastUpdatedTime >= this.deviceStatusTaskPluginConfig
|
||||||
log.error("Error occurred while fetching OperationEnrolment mappings of deviceType '" + deviceType + "'", e);
|
.getIdleTimeToMarkInactive()) {
|
||||||
return;
|
status = EnrolmentInfo.Status.INACTIVE;
|
||||||
}
|
} else if (lastUpdatedTime >= this.deviceStatusTaskPluginConfig
|
||||||
for (OperationEnrolmentMapping mapping : operationEnrolmentMappings) {
|
.getIdleTimeToMarkUnreachable()) {
|
||||||
long lastActivity = -1;
|
status = EnrolmentInfo.Status.UNREACHABLE;
|
||||||
if (lastActivities != null && lastActivities.containsKey(mapping.getEnrolmentId())) {
|
|
||||||
lastActivity = lastActivities.get(mapping.getEnrolmentId());
|
|
||||||
}
|
|
||||||
EnrolmentInfo.Status newStatus = this.determineDeviceStatus(mapping, lastActivity);
|
|
||||||
if (newStatus != mapping.getDeviceStatus()) {
|
|
||||||
deviceIdentifier = new DeviceIdentifier();
|
|
||||||
deviceIdentifier.setId(mapping.getDeviceId());
|
|
||||||
deviceIdentifier.setId(mapping.getDeviceType());
|
|
||||||
device = DeviceCacheManagerImpl.getInstance().getDeviceFromCache(deviceIdentifier, mapping.getTenantId());
|
|
||||||
if (device == null) {
|
|
||||||
enrolmentInfo = new EnrolmentInfo();
|
|
||||||
enrolmentInfo.setId(mapping.getEnrolmentId());
|
|
||||||
enrolmentInfo.setStatus(newStatus);
|
|
||||||
} else {
|
|
||||||
DeviceManagementProviderService dmps = DeviceManagementDataHolder.getInstance()
|
|
||||||
.getDeviceManagementProvider();
|
|
||||||
try {
|
|
||||||
Device updatedDevice = dmps
|
|
||||||
.getDevice(device.getDeviceIdentifier(), device.getDeviceInfo().getUpdatedTime(), true);
|
|
||||||
if (updatedDevice != null) {
|
|
||||||
device = updatedDevice;
|
|
||||||
}
|
|
||||||
} catch (DeviceManagementException e) {
|
|
||||||
log.error(
|
|
||||||
"Error occurred while getting the updated device information which has device identifier: "
|
|
||||||
+ device.getDeviceIdentifier());
|
|
||||||
}
|
|
||||||
enrolmentInfo = device.getEnrolmentInfo();
|
|
||||||
enrolmentInfo.setStatus(newStatus);
|
|
||||||
device.setEnrolmentInfo(enrolmentInfo);
|
|
||||||
DeviceCacheManagerImpl.getInstance().addDeviceToCache(deviceIdentifier, device, mapping.getTenantId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status != null) {
|
||||||
|
enrolmentInfo.setStatus(status);
|
||||||
enrolmentInfoTobeUpdated.add(enrolmentInfo);
|
enrolmentInfoTobeUpdated.add(enrolmentInfo);
|
||||||
if(log.isDebugEnabled()){
|
DeviceIdentifier deviceIdentifier =
|
||||||
log.debug("Enrollment Information updated for device ID : " + device.getDeviceIdentifier());
|
new DeviceIdentifier(monitoringData.getDevice()
|
||||||
}
|
.getDeviceIdentifier(), deviceType);
|
||||||
|
DeviceCacheManagerImpl.getInstance().removeDeviceFromCache(deviceIdentifier,
|
||||||
|
monitoringData.getTenantId());
|
||||||
|
DeviceCacheManagerImpl.getInstance().addDeviceToCache(deviceIdentifier,
|
||||||
|
monitoringData.getDevice(), monitoringData.getTenantId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,37 +127,18 @@ public class DeviceStatusMonitoringTask extends DynamicPartitionedScheduleTask {
|
|||||||
try {
|
try {
|
||||||
this.updateDeviceStatus(enrolmentInfoTobeUpdated);
|
this.updateDeviceStatus(enrolmentInfoTobeUpdated);
|
||||||
} catch (DeviceStatusTaskException e) {
|
} catch (DeviceStatusTaskException e) {
|
||||||
log.error("Error occurred while updating non-responsive device-status of devices of type '" + deviceType + "'", e);
|
log.error("Error occurred while updating non-responsive " +
|
||||||
}
|
"device-status of devices of type '" + deviceType + "'", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EnrolmentInfo.Status determineDeviceStatus(OperationEnrolmentMapping opMapping, long lastActivityTime) {
|
|
||||||
long lastPendingOpBefore = (System.currentTimeMillis() / 1000) - opMapping.getCreatedTime();
|
} catch (DeviceManagementException e) {
|
||||||
EnrolmentInfo.Status newStatus = null;
|
String msg = "Error occurred while retrieving devices list for monitoring.";
|
||||||
if (lastPendingOpBefore >= this.deviceStatusTaskPluginConfig.getIdleTimeToMarkInactive()) {
|
log.error(msg, e);
|
||||||
newStatus = EnrolmentInfo.Status.INACTIVE;
|
|
||||||
} else if (lastPendingOpBefore >= this.deviceStatusTaskPluginConfig.getIdleTimeToMarkUnreachable()) {
|
|
||||||
newStatus = EnrolmentInfo.Status.UNREACHABLE;
|
|
||||||
}
|
}
|
||||||
if (lastActivityTime != -1) {
|
|
||||||
long lastActivityBefore = (System.currentTimeMillis() / 1000) - lastActivityTime;
|
|
||||||
if (lastActivityBefore < lastPendingOpBefore) {
|
|
||||||
return opMapping.getDeviceStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getMinTimeWindow() {
|
|
||||||
return (System.currentTimeMillis() / 1000) - this.deviceStatusTaskPluginConfig.getIdleTimeToMarkUnreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getMaxTimeWindow() {
|
|
||||||
//Need to consider the frequency of the task as well
|
|
||||||
return (System.currentTimeMillis() / 1000) - this.deviceStatusTaskPluginConfig.getIdleTimeToMarkInactive() -
|
|
||||||
this.deviceStatusTaskPluginConfig.getFrequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean updateDeviceStatus(List<EnrolmentInfo> enrolmentInfos) throws
|
private boolean updateDeviceStatus(List<EnrolmentInfo> enrolmentInfos) throws
|
||||||
DeviceStatusTaskException {
|
DeviceStatusTaskException {
|
||||||
@ -184,56 +160,4 @@ public class DeviceStatusMonitoringTask extends DynamicPartitionedScheduleTask {
|
|||||||
return updateStatus;
|
return updateStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<OperationEnrolmentMapping> getOperationEnrolmentMappings(DynamicTaskContext ctx) throws DeviceStatusTaskException {
|
|
||||||
List<OperationEnrolmentMapping> operationEnrolmentMappings;
|
|
||||||
try {
|
|
||||||
OperationManagementDAOFactory.openConnection();
|
|
||||||
if(ctx != null && ctx.isPartitioningEnabled()){
|
|
||||||
operationEnrolmentMappings = OperationManagementDAOFactory.
|
|
||||||
getOperationMappingDAO().getFirstPendingOperationMappingsForActiveEnrolments(this.getMinTimeWindow(),
|
|
||||||
this.getMaxTimeWindow(), this.deviceTypeId,
|
|
||||||
ctx.getActiveServerCount(), ctx.getServerHashIndex());
|
|
||||||
} else {
|
|
||||||
operationEnrolmentMappings = OperationManagementDAOFactory.
|
|
||||||
getOperationMappingDAO().getFirstPendingOperationMappingsForActiveEnrolments(this.getMinTimeWindow(),
|
|
||||||
this.getMaxTimeWindow(), this.deviceTypeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DeviceStatusTaskException("Error occurred while getting Enrolment operation mappings for " +
|
|
||||||
"determining device status of deviceType '" + deviceType + "'", e);
|
|
||||||
} catch (OperationManagementDAOException e) {
|
|
||||||
throw new DeviceStatusTaskException("Error occurred obtaining a DB connection for fetching " +
|
|
||||||
"operation-enrolment mappings for status monitoring of deviceType '" + deviceType + "'", e);
|
|
||||||
} finally {
|
|
||||||
OperationManagementDAOFactory.closeConnection();
|
|
||||||
}
|
|
||||||
return operationEnrolmentMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Integer, Long> getLastDeviceActivities(DynamicTaskContext ctx) throws DeviceStatusTaskException {
|
|
||||||
Map<Integer, Long> lastActivities;
|
|
||||||
try {
|
|
||||||
OperationManagementDAOFactory.openConnection();
|
|
||||||
if(ctx != null && ctx.isPartitioningEnabled()) {
|
|
||||||
lastActivities = OperationManagementDAOFactory.
|
|
||||||
getOperationMappingDAO().getLastConnectedTimeForActiveEnrolments(this.getMaxTimeWindow(),
|
|
||||||
this.deviceTypeId,
|
|
||||||
ctx.getActiveServerCount(), ctx.getServerHashIndex());
|
|
||||||
} else {
|
|
||||||
lastActivities = OperationManagementDAOFactory.
|
|
||||||
getOperationMappingDAO().getLastConnectedTimeForActiveEnrolments(this.getMaxTimeWindow(),
|
|
||||||
this.deviceTypeId);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DeviceStatusTaskException("Error occurred while getting last activities for " +
|
|
||||||
"determining device status of deviceType '" + deviceType + "'", e);
|
|
||||||
} catch (OperationManagementDAOException e) {
|
|
||||||
throw new DeviceStatusTaskException("Error occurred obtaining a DB connection for fetching " +
|
|
||||||
"last activities for status monitoring of deviceType '" + deviceType + "'", e);
|
|
||||||
} finally {
|
|
||||||
OperationManagementDAOFactory.closeConnection();
|
|
||||||
}
|
|
||||||
return lastActivities;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user