/* * Copyright 2014-2016 CyberVision, Inc. * * 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. */ package org.kaaproject.kaa.server.common.dao.service; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.kaaproject.kaa.common.dto.UpdateStatus.ACTIVE; import static org.kaaproject.kaa.common.dto.UpdateStatus.INACTIVE; import static org.kaaproject.kaa.server.common.dao.impl.DaoUtil.convertDtoList; import static org.kaaproject.kaa.server.common.dao.impl.DaoUtil.getDto; import static org.kaaproject.kaa.server.common.dao.service.Validator.isValidId; import static org.kaaproject.kaa.server.common.dao.service.Validator.validateId; import static org.kaaproject.kaa.server.common.dao.service.Validator.validateSqlId; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.kaaproject.kaa.common.dto.ChangeDto; import org.kaaproject.kaa.common.dto.ChangeNotificationDto; import org.kaaproject.kaa.common.dto.ChangeProfileFilterNotification; import org.kaaproject.kaa.common.dto.ChangeType; import org.kaaproject.kaa.common.dto.EndpointProfileDto; import org.kaaproject.kaa.common.dto.EndpointProfileSchemaDto; import org.kaaproject.kaa.common.dto.HistoryDto; import org.kaaproject.kaa.common.dto.ProfileFilterDto; import org.kaaproject.kaa.common.dto.ProfileFilterRecordDto; import org.kaaproject.kaa.common.dto.ProfileVersionPairDto; import org.kaaproject.kaa.common.dto.ServerProfileSchemaDto; import org.kaaproject.kaa.common.dto.UpdateStatus; import org.kaaproject.kaa.common.dto.VersionDto; import org.kaaproject.kaa.server.common.dao.EndpointService; import org.kaaproject.kaa.server.common.dao.HistoryService; import org.kaaproject.kaa.server.common.dao.ProfileService; import org.kaaproject.kaa.server.common.dao.ServerProfileService; import org.kaaproject.kaa.server.common.dao.exception.DatabaseProcessingException; import org.kaaproject.kaa.server.common.dao.exception.IncorrectParameterException; import org.kaaproject.kaa.server.common.dao.exception.NotFoundException; import org.kaaproject.kaa.server.common.dao.exception.UpdateStatusConflictException; import org.kaaproject.kaa.server.common.dao.impl.EndpointGroupDao; import org.kaaproject.kaa.server.common.dao.impl.EndpointProfileDao; import org.kaaproject.kaa.server.common.dao.impl.ProfileFilterDao; import org.kaaproject.kaa.server.common.dao.impl.ProfileSchemaDao; import org.kaaproject.kaa.server.common.dao.model.EndpointProfile; import org.kaaproject.kaa.server.common.dao.model.sql.EndpointGroup; import org.kaaproject.kaa.server.common.dao.model.sql.EndpointProfileSchema; import org.kaaproject.kaa.server.common.dao.model.sql.ProfileFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @Service @Transactional public class ProfileServiceImpl implements ProfileService { private static final Logger LOG = LoggerFactory.getLogger(ProfileServiceImpl.class); @Autowired private ProfileSchemaDao<EndpointProfileSchema> profileSchemaDao; @Autowired private ProfileFilterDao<ProfileFilter> profileFilterDao; @Autowired private EndpointGroupDao<EndpointGroup> endpointGroupDao; @Autowired private HistoryService historyService; @Autowired private ServerProfileService serverProfileService; @Autowired private EndpointService endpointService; private EndpointProfileDao<EndpointProfile> endpointProfileDao; public void setEndpointProfileDao(EndpointProfileDao<EndpointProfile> endpointProfileDao) { this.endpointProfileDao = endpointProfileDao; } @Override public List<EndpointProfileSchemaDto> findProfileSchemasByAppId(String applicationId) { validateSqlId(applicationId, "Can't find profile schema. Invalid application id: " + applicationId); return convertDtoList(profileSchemaDao.findByApplicationId(applicationId)); } @Override public List<VersionDto> findProfileSchemaVersionsByAppId(String applicationId) { validateSqlId(applicationId, "Can't find profile schemas. Invalid application id: " + applicationId); List<EndpointProfileSchema> endpointProfileSchemas = profileSchemaDao.findByApplicationId(applicationId); List<VersionDto> schemas = new ArrayList<>(); for (EndpointProfileSchema endpointProfileSchema : endpointProfileSchemas) { schemas.add(endpointProfileSchema.toVersionDto()); } return schemas; } @Override public EndpointProfileSchemaDto findProfileSchemaById(String id) { validateSqlId(id, "Can't find profile schema. Invalid profile schema id: " + id); return getDto(profileSchemaDao.findById(id)); } @Override public EndpointProfileSchemaDto saveProfileSchema(EndpointProfileSchemaDto profileSchemaDto) { if (profileSchemaDto == null) { throw new IncorrectParameterException("Can't save profile schema. " + "Invalid profile schema object."); } String appId = profileSchemaDto.getApplicationId(); if (isNotBlank(appId)) { String id = profileSchemaDto.getId(); if (StringUtils.isBlank(id)) { EndpointProfileSchema endpointProfileSchema = profileSchemaDao.findLatestByAppId(appId); int version = -1; if (endpointProfileSchema != null) { version = endpointProfileSchema.getVersion(); } profileSchemaDto.setId(null); profileSchemaDto.setVersion(++version); profileSchemaDto.setCreatedTime(System.currentTimeMillis()); } else { EndpointProfileSchemaDto oldProfileSchemaDto = getDto(profileSchemaDao.findById(id)); if (oldProfileSchemaDto != null) { oldProfileSchemaDto.editFields(profileSchemaDto); profileSchemaDto = oldProfileSchemaDto; return getDto(profileSchemaDao.save(new EndpointProfileSchema(profileSchemaDto))); } else { LOG.error("Can't find profile schema with given id [{}].", id); throw new IncorrectParameterException("Invalid profile schema id: " + id); } } return getDto(profileSchemaDao.save(new EndpointProfileSchema(profileSchemaDto))); } else { throw new IncorrectParameterException("Invalid profile schema object. " + "Incorrect application id" + appId); } } @Override public void removeProfileSchemasByAppId(String applicationId) { validateSqlId(applicationId, "Can't remove profile schema. Invalid application id: " + applicationId); List<EndpointProfileSchema> schemas = profileSchemaDao.findByApplicationId(applicationId); if (schemas != null && !schemas.isEmpty()) { LOG.debug("Remove profile shemas by application id {}", applicationId); for (EndpointProfileSchema schema : schemas) { removeProfileSchemaById(schema.getId().toString()); } } } @Override public void removeProfileSchemaById(String id) { validateSqlId(id, "Can't remove profile schema. Invalid profile schema id: " + id); profileSchemaDao.removeById(id); LOG.debug("Removed profile schema [{}] with filters.", id); } @Override public Collection<ProfileFilterRecordDto> findAllProfileFilterRecordsByEndpointGroupId( String endpointGroupId, boolean includeDeprecated) { Collection<ProfileFilterDto> profileFilters = convertDtoList( profileFilterDao.findActualByEndpointGroupId(endpointGroupId)); List<ProfileFilterRecordDto> records = ProfileFilterRecordDto.convertToProfileFilterRecords( profileFilters); if (includeDeprecated) { List<ProfileVersionPairDto> versions = findVacantSchemasByEndpointGroupId(endpointGroupId); for (ProfileVersionPairDto version : versions) { ProfileFilterDto deprecatedProfileFilter = getDto(profileFilterDao.findLatestDeprecated( version.getEndpointProfileSchemaid(), version.getServerProfileSchemaid(), endpointGroupId)); if (deprecatedProfileFilter != null) { ProfileFilterRecordDto record = new ProfileFilterRecordDto(); record.setActiveStructureDto(deprecatedProfileFilter); records.add(record); } } } Collections.sort(records); return records; } @Override public ProfileFilterRecordDto findProfileFilterRecordBySchemaIdAndEndpointGroupId( String endpointProfileSchemaId, String serverProfileSchemaId, String endpointGroupId) { validateFilterSchemaIds(endpointProfileSchemaId, serverProfileSchemaId); ProfileFilterRecordDto record = new ProfileFilterRecordDto(); Collection<ProfileFilterDto> profileFilters = convertDtoList( profileFilterDao.findActualBySchemaIdAndGroupId(endpointProfileSchemaId, serverProfileSchemaId, endpointGroupId)); if (profileFilters != null) { for (ProfileFilterDto profileFilter : profileFilters) { if (profileFilter.getStatus() == UpdateStatus.ACTIVE) { record.setActiveStructureDto(profileFilter); } else if (profileFilter.getStatus() == UpdateStatus.INACTIVE) { record.setInactiveStructureDto(profileFilter); } } } if (!record.hasActive()) { ProfileFilterDto deprecatedProfileFilter = getDto( profileFilterDao.findLatestDeprecated(endpointProfileSchemaId, serverProfileSchemaId, endpointGroupId)); if (deprecatedProfileFilter != null) { record.setActiveStructureDto(deprecatedProfileFilter); } } if (record.isEmpty()) { LOG.debug("Can't find related profile filter record for endpoint schema {}, " + "server schema {} and group {}.", endpointProfileSchemaId, serverProfileSchemaId, endpointGroupId); throw new NotFoundException("Profile filter record not found, endpointProfileSchemaId: " + endpointProfileSchemaId + ", serverProfileSchemaId: " + serverProfileSchemaId + " endpointGroupId: " + endpointGroupId); } return record; } @Override public List<ProfileVersionPairDto> findVacantSchemasByEndpointGroupId(String endpointGroupId) { validateSqlId(endpointGroupId, "Can't find vacant schemas. Invalid endpoint group id: " + endpointGroupId); EndpointGroup group = endpointGroupDao.findById(endpointGroupId); String appId = group.getApplicationId(); List<ServerProfileSchemaDto> serverSchemas = serverProfileService .findServerProfileSchemasByAppId(appId); Collections.sort(serverSchemas); List<EndpointProfileSchemaDto> endpointProfileSchemas = findProfileSchemasByAppId(appId); Collections.sort(endpointProfileSchemas); Collection<ProfileVersionPairDto> pairVersionSet = new HashSet<>(); for (int i = 0; i < endpointProfileSchemas.size(); i++) { EndpointProfileSchemaDto endSchema = endpointProfileSchemas.get(i); for (ServerProfileSchemaDto serverSchema : serverSchemas) { if (i == 0) { pairVersionSet.add(new ProfileVersionPairDto(serverSchema.getId(), serverSchema.getVersion())); } pairVersionSet.add(new ProfileVersionPairDto(endSchema.getId(), endSchema.getVersion(), serverSchema.getId(), serverSchema.getVersion())); } pairVersionSet.add(new ProfileVersionPairDto(endSchema.getVersion(), endSchema.getId())); } List<ProfileFilter> profileFilters = profileFilterDao.findActualByEndpointGroupId( endpointGroupId); for (ProfileFilter pf : profileFilters) { pairVersionSet.remove(new ProfileVersionPairDto(pf.getEndpointProfileSchemaId(), pf.getEndpointProfileSchemaVersion(), pf.getServerProfileSchemaId(), pf.getServerProfileSchemaVersion())); } return new ArrayList<>(pairVersionSet); } @Override public ProfileFilterDto findProfileFilterById(String id) { validateSqlId(id, "Can't find profile filter. Invalid profile filter id: " + id); return getDto(profileFilterDao.findById(id)); } @Override public ProfileFilterDto saveProfileFilter(ProfileFilterDto profileFilterDto) { validateFilter(profileFilterDto); String id = profileFilterDto.getId(); if (isNotBlank(id)) { ProfileFilterDto oldProfileFilter = findProfileFilterById(id); if (oldProfileFilter != null && oldProfileFilter.getStatus() != INACTIVE) { throw new UpdateStatusConflictException("Can't update profile filter, " + "invalid old profile filter with id " + id); } } else { String endProfSchemaId = profileFilterDto.getEndpointProfileSchemaId(); String srvProfSchemaId = profileFilterDto.getServerProfileSchemaId(); String groupId = profileFilterDto.getEndpointGroupId(); EndpointGroup group = endpointGroupDao.findById(groupId); if (group.getWeight() == 0) { throw new UpdateStatusConflictException( "Add profile filter to default group is forbidden!"); } EndpointProfileSchemaDto endpointProfileSchemaDto = null; if (endProfSchemaId != null) { endpointProfileSchemaDto = findProfileSchemaById(endProfSchemaId); if (endpointProfileSchemaDto == null) { throw new IncorrectParameterException("Can't update profile filter, " + "endpoint profile schema not found!"); } } ServerProfileSchemaDto serverProfileSchemaDto = null; if (srvProfSchemaId != null) { serverProfileSchemaDto = serverProfileService.findServerProfileSchema(srvProfSchemaId); if (serverProfileSchemaDto == null) { throw new IncorrectParameterException("Can't update profile filter, " + "server profile schema not found!"); } } if (endpointProfileSchemaDto != null || serverProfileSchemaDto != null) { ProfileFilter inactiveFilter = profileFilterDao.findInactiveFilter(endProfSchemaId, srvProfSchemaId, groupId); ProfileFilter latestFilter = profileFilterDao.findLatestFilter(endProfSchemaId, srvProfSchemaId, groupId); if (inactiveFilter != null) { profileFilterDto.setId(inactiveFilter.getId().toString()); profileFilterDto.setSequenceNumber(inactiveFilter.getSequenceNumber()); } else if (latestFilter != null) { profileFilterDto.setSequenceNumber(latestFilter.getSequenceNumber()); } if (endpointProfileSchemaDto != null) { profileFilterDto.setApplicationId(endpointProfileSchemaDto.getApplicationId()); } else { profileFilterDto.setApplicationId(serverProfileSchemaDto.getApplicationId()); } profileFilterDto.setCreatedTime(System.currentTimeMillis()); } else { throw new IncorrectParameterException("Can't update profile filter, " + "profile schemas not set!"); } } profileFilterDto.setStatus(UpdateStatus.INACTIVE); profileFilterDto.setLastModifyTime(System.currentTimeMillis()); return getDto(profileFilterDao.save(new ProfileFilter(profileFilterDto))); } @Override public ChangeProfileFilterNotification activateProfileFilter(String id, String activatedUsername) { ChangeProfileFilterNotification profileNotification; ProfileFilterDto profileFilter; validateSqlId(id, "Can't activate profile filter. Invalid profile filter id: " + id); ProfileFilter oldProfileFilter = profileFilterDao.findById(id); if (oldProfileFilter != null) { UpdateStatus status = oldProfileFilter.getStatus(); if (status != null && status == INACTIVE) { String endProfSchemaId = oldProfileFilter.getEndpointProfileSchemaId(); String srvProfSchemaId = oldProfileFilter.getServerProfileSchemaId(); String groupId = oldProfileFilter.getGroupId(); if (groupId != null) { profileFilterDao.deactivateOldFilter(endProfSchemaId, srvProfSchemaId, groupId, activatedUsername); } else { throw new DatabaseProcessingException("Incorrect old profile filters. " + "Profile schema id is empty."); } profileFilter = getDto(profileFilterDao.activate(id, activatedUsername)); if (profileFilter != null) { HistoryDto history = addHistory(profileFilter, ChangeType.ADD_PROF); ChangeNotificationDto changeNotificationDto = createNotification(profileFilter, history); profileNotification = new ChangeProfileFilterNotification(); profileNotification.setProfileFilterDto(profileFilter); profileNotification.setChangeNotificationDto(changeNotificationDto); } else { throw new DatabaseProcessingException("Can't activate profile filter."); } } else { throw new UpdateStatusConflictException("Incorrect status for activating profile filter " + status); } } else { throw new IncorrectParameterException("Can't find profile filter with id " + id); } return profileNotification; } @Override public ChangeProfileFilterNotification deactivateProfileFilter( String id, String deactivatedUsername) { ChangeProfileFilterNotification profileNotification; validateSqlId(id, "Incorrect profile filter id. Can't deactivate profile filter with id " + id); ProfileFilter oldProfileFilter = profileFilterDao.findById(id); if (oldProfileFilter != null) { UpdateStatus status = oldProfileFilter.getStatus(); String oid = oldProfileFilter.getGroupId(); if (oid != null) { EndpointGroup group = endpointGroupDao.findById(oid); if (group != null && group.getWeight() == 0) { throw new IncorrectParameterException("Can't deactivate default profile filter"); } } if (status != null && status == ACTIVE) { ProfileFilterDto profileFilterDto = getDto(profileFilterDao.deactivate( id, deactivatedUsername)); HistoryDto historyDto = addHistory(profileFilterDto, ChangeType.REMOVE_PROF); ChangeNotificationDto changeNotificationDto = createNotification( profileFilterDto, historyDto); profileNotification = new ChangeProfileFilterNotification(); profileNotification.setProfileFilterDto(profileFilterDto); profileNotification.setChangeNotificationDto(changeNotificationDto); } else { throw new UpdateStatusConflictException("Incorrect status for activating profile filter " + status); } } else { throw new IncorrectParameterException("Can't find profile filter with id " + id); } return profileNotification; } @Override public ChangeProfileFilterNotification deleteProfileFilterRecord(String endpointProfileSchemaId, String serverProfileSchemaId, String groupId, String deactivatedUsername) { validateFilterSchemaIds(endpointProfileSchemaId, serverProfileSchemaId); validateSqlId(groupId, "Incorrect group id " + groupId + "."); ChangeProfileFilterNotification profileNotification = null; ProfileFilterDto profileFilterDto = getDto(profileFilterDao.deactivateOldFilter( endpointProfileSchemaId, serverProfileSchemaId, groupId, deactivatedUsername)); if (profileFilterDto != null) { HistoryDto historyDto = addHistory(profileFilterDto, ChangeType.REMOVE_PROF); ChangeNotificationDto changeNotificationDto = createNotification( profileFilterDto, historyDto); profileNotification = new ChangeProfileFilterNotification(); profileNotification.setProfileFilterDto(profileFilterDto); profileNotification.setChangeNotificationDto(changeNotificationDto); } ProfileFilter profileFilter = profileFilterDao.findInactiveFilter( endpointProfileSchemaId, serverProfileSchemaId, groupId); if (profileFilter != null) { profileFilterDao.removeById(profileFilter.getId().toString()); } return profileNotification; } private ChangeNotificationDto createNotification(ProfileFilterDto profileFilter, HistoryDto historyDto) { LOG.debug("Create notification after profile filter update."); ChangeNotificationDto changeNotificationDto = null; if (historyDto != null) { changeNotificationDto = new ChangeNotificationDto(); changeNotificationDto.setAppId(profileFilter.getApplicationId()); changeNotificationDto.setAppSeqNumber(historyDto.getSequenceNumber()); String endpointGroupId = profileFilter.getEndpointGroupId(); if (isValidId(endpointGroupId)) { EndpointGroup group = endpointGroupDao.findById(endpointGroupId); if (group != null) { changeNotificationDto.setGroupId(group.getId().toString()); changeNotificationDto.setGroupSeqNumber(group.getSequenceNumber()); } else { LOG.debug("Can't find endpoint group by id [{}].", endpointGroupId); } } else { LOG.debug("Incorrect endpoint group id [{}].", endpointGroupId); } } else { LOG.debug("Can't save history information."); } return changeNotificationDto; } @Override public List<ProfileFilterDto> findProfileFiltersByAppIdAndVersionsCombination( String appId, int endpointSchemaVersion, int serverSchemaVersion) { validateId(appId, "Can't find profile filter. Invalid application id: " + appId); return convertDtoList(profileFilterDao.findByAppIdAndSchemaVersionsCombination( appId, endpointSchemaVersion, serverSchemaVersion)); } @Override public EndpointProfileSchemaDto findProfileSchemaByAppIdAndVersion( String appId, int schemaVersion) { validateId(appId, "Can't find profile schema. Invalid application id: " + appId); return getDto(profileSchemaDao.findByAppIdAndVersion(appId, schemaVersion)); } @Override public ProfileFilterDto findLatestFilterBySchemaIdsAndGroupId( String endpointProfileSchemaId, String serverProfileSchemaId, String groupId) { validateFilterSchemaIds(endpointProfileSchemaId, serverProfileSchemaId); validateId(groupId, "Can't find profile filter. Invalid group id: " + groupId); return getDto(profileFilterDao.findLatestFilter( endpointProfileSchemaId, serverProfileSchemaId, groupId)); } @Override public EndpointProfileDto findEndpointProfileByEndpointKeyHash(String endpointKeyHash) { byte[] hash = Base64.decodeBase64(endpointKeyHash); EndpointProfileDto endpointProfile = endpointService.findEndpointProfileByKeyHash(hash); return endpointProfile; } private HistoryDto addHistory(ProfileFilterDto dto, ChangeType type) { LOG.debug("Add history information about profile filter update with change type {} ", type); HistoryDto history = new HistoryDto(); history.setApplicationId(dto.getApplicationId()); ChangeDto change = new ChangeDto(); change.setProfileFilterId(dto.getId()); change.setProfileFilterId(dto.getId()); change.setEndpointGroupId(dto.getEndpointGroupId()); change.setType(type); history.setChange(change); return historyService.saveHistory(history); } private void validateFilterSchemaIds(String endpointProfileSchemaId, String serverProfileSchemaId) { if (isBlank(endpointProfileSchemaId) && isBlank(serverProfileSchemaId)) { throw new IncorrectParameterException("Both profile schema ids can't be empty"); } } private void validateFilter(ProfileFilterDto dto) { if (dto == null) { throw new IncorrectParameterException("Can't save profile filter. Incorrect object."); } if (dto.getEndpointProfileSchemaId() == null && dto.getServerProfileSchemaId() == null) { throw new IncorrectParameterException( "Profile Filter object invalid. Both schemas are empty."); } if (StringUtils.isBlank(dto.getEndpointGroupId())) { throw new IncorrectParameterException( "Profile Filter object invalid. Endpoint Group id invalid:" + dto.getEndpointGroupId()); } } }