package com.devicehive.dao.rdbms;
/*
* #%L
* DeviceHive Dao RDBMS Implementation
* %%
* Copyright (C) 2016 DataArt
* %%
* Licensed 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.
* #L%
*/
import com.devicehive.auth.HivePrincipal;
import com.devicehive.dao.DeviceDao;
import com.devicehive.model.Device;
import com.devicehive.model.DeviceClass;
import com.devicehive.model.Network;
import com.devicehive.vo.DeviceVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
@Repository
public class DeviceDaoRdbmsImpl extends RdbmsGenericDao implements DeviceDao {
private static final String GET_DEVICES_GUIDS_AND_OFFLINE_TIMEOUT = "SELECT d.guid, dc.offline_timeout FROM device d " +
"LEFT JOIN device_class dc " +
"ON dc.id = d.device_class_id " +
"WHERE d.guid IN (:guids)";
private static final String UPDATE_DEVICES_STATUSES = "UPDATE device SET status =:status WHERE guid IN (:guids)";
private NamedParameterJdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
/**
* Method change statuses for devices with guids that consists in the list
*
* @param status new status
* @param guids list of guids
*/
public void changeStatusForDevices(String status, List<String> guids) {
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("status", status);
parameters.addValue("guids", guids);
jdbcTemplate.update(UPDATE_DEVICES_STATUSES, parameters);
}
/**
* Method return a Map where KEY is a device guid from guids list and
* VALUE is OfflineTimeout from deviceClass for device with current guid.
*
* @param guids list of guids
*/
public Map<String, Integer> getOfflineTimeForDevices(List<String> guids) {
final Map<String, Integer> deviceInfo = new HashMap<>();
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("guids", guids);
List<Map<String, Object>> results = jdbcTemplate.queryForList(GET_DEVICES_GUIDS_AND_OFFLINE_TIMEOUT, parameters);
results.stream().forEach(map -> deviceInfo.put((String) map.get("guid"), (Integer) map.get("offline_timeout")));
return deviceInfo;
}
@Override
public DeviceVO findByUUID(String uuid) {
Device deviceEntity = createNamedQuery(Device.class, "Device.findByUUID", Optional.of(CacheConfig.refresh()))
.setParameter("guid", uuid)
.getResultList()
.stream().findFirst().orElse(null);
return Device.convertToVo(deviceEntity);
}
@Override
public void persist(DeviceVO vo) {
Device device = Device.convertToEntity(vo);
device.setDeviceClass(reference(DeviceClass.class, device.getDeviceClass().getId()));
if (device.getNetwork() != null) {
device.setNetwork(reference(Network.class, device.getNetwork().getId()));
}
super.persist(device);
vo.setId(device.getId());
}
@Override
public DeviceVO merge(DeviceVO vo) {
Device device = Device.convertToEntity(vo);
device.setDeviceClass(reference(DeviceClass.class, device.getDeviceClass().getId()));
if (device.getNetwork() != null) {
device.setNetwork(reference(Network.class, device.getNetwork().getId()));
}
Device merged = super.merge(device);
return Device.convertToVo(merged);
}
@Override
public int deleteByUUID(String guid) {
return createNamedQuery("Device.deleteByUUID", Optional.<CacheConfig>empty())
.setParameter("guid", guid)
.executeUpdate();
}
@Override
public List<DeviceVO> getDeviceList(List<String> guids, HivePrincipal principal) {
final CriteriaBuilder cb = criteriaBuilder();
final CriteriaQuery<Device> criteria = cb.createQuery(Device.class);
final Root<Device> from = criteria.from(Device.class);
final Predicate[] predicates = CriteriaHelper.deviceListPredicates(cb, from, guids, Optional.ofNullable(principal));
criteria.where(predicates);
final TypedQuery<Device> query = createQuery(criteria);
CacheHelper.cacheable(query);
return query.getResultList().stream().map(Device::convertToVo).collect(Collectors.toList());
}
@Override
public long getAllowedDeviceCount(HivePrincipal principal, List<String> guids) {
final CriteriaBuilder cb = criteriaBuilder();
final CriteriaQuery<Device> criteria = cb.createQuery(Device.class);
final Root<Device> from = criteria.from(Device.class);
final Predicate[] predicates = CriteriaHelper.deviceListPredicates(cb, from, guids, Optional.ofNullable(principal));
criteria.where(predicates);
final TypedQuery<Device> query = createQuery(criteria);
return query.getResultList().size();
}
@Override
public List<DeviceVO> list(String name, String namePattern, Long networkId, String networkName,
Long deviceClassId, String deviceClassName, String sortField, @NotNull Boolean sortOrderAsc, Integer take,
Integer skip, HivePrincipal principal) {
final CriteriaBuilder cb = criteriaBuilder();
final CriteriaQuery<Device> criteria = cb.createQuery(Device.class);
final Root<Device> from = criteria.from(Device.class);
final Predicate [] predicates = CriteriaHelper.deviceListPredicates(cb, from, ofNullable(name), ofNullable(namePattern), ofNullable(networkId), ofNullable(networkName),
ofNullable(deviceClassId), ofNullable(deviceClassName), ofNullable(principal));
criteria.where(predicates);
CriteriaHelper.order(cb, criteria, from, ofNullable(sortField), sortOrderAsc);
final TypedQuery<Device> query = createQuery(criteria);
cacheQuery(query, of(CacheConfig.refresh()));
ofNullable(take).ifPresent(query::setMaxResults);
ofNullable(skip).ifPresent(query::setFirstResult);
List<Device> resultList = query.getResultList();
return resultList.stream().map(Device::convertToVo).collect(Collectors.toList());
}
}