/*
* 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.admin.services;
import static org.kaaproject.kaa.server.admin.services.util.Utils.getCurrentUser;
import static org.kaaproject.kaa.server.admin.shared.util.Utils.isEmpty;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericRecord;
import org.kaaproject.kaa.common.avro.GenericAvroConverter;
import org.kaaproject.kaa.common.dto.EndpointGroupDto;
import org.kaaproject.kaa.common.dto.EndpointProfileSchemaDto;
import org.kaaproject.kaa.common.dto.EndpointProfilesBodyDto;
import org.kaaproject.kaa.common.dto.EndpointProfilesPageDto;
import org.kaaproject.kaa.common.dto.KaaAuthorityDto;
import org.kaaproject.kaa.common.dto.PageLinkDto;
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.ctl.CTLSchemaDto;
import org.kaaproject.kaa.server.admin.services.util.Utils;
import org.kaaproject.kaa.server.admin.shared.services.GroupService;
import org.kaaproject.kaa.server.admin.shared.services.KaaAdminServiceException;
import org.kaaproject.kaa.server.admin.shared.services.ProfileService;
import org.kaaproject.kaa.server.admin.shared.services.ServiceErrorCode;
import org.kaaproject.kaa.server.operations.service.filter.DefaultFilterEvaluator;
import org.kaaproject.kaa.server.operations.service.filter.el.GenericRecordPropertyAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("groupService")
public class GroupServiceImpl extends AbstractAdminService implements GroupService {
/**
* The Constant MAX_LIMIT.
*/
private static final int MAX_LIMIT = 500;
@Autowired
ProfileService profileService;
@Override
public List<EndpointGroupDto> getEndpointGroupsByApplicationToken(String applicationToken)
throws KaaAdminServiceException {
return getEndpointGroupsByApplicationId(checkApplicationToken(applicationToken));
}
@Override
public List<EndpointGroupDto> getEndpointGroupsByApplicationId(String applicationId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(applicationId);
return controlService.getEndpointGroupsByApplicationId(applicationId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointGroupDto getEndpointGroup(String endpointGroupId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
return checkEndpointGroupId(endpointGroupId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointGroupDto editEndpointGroup(EndpointGroupDto endpointGroup)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupWeight(endpointGroup.getWeight());
if (isEmpty(endpointGroup.getId())) {
endpointGroup.setCreatedUsername(getCurrentUser().getUsername());
checkApplicationId(endpointGroup.getApplicationId());
} else {
checkEndpointGroupId(endpointGroup.getId());
}
return controlService.editEndpointGroup(endpointGroup);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void deleteEndpointGroup(String endpointGroupId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
controlService.deleteEndpointGroup(endpointGroupId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<ProfileFilterRecordDto> getProfileFilterRecordsByEndpointGroupId(
String endpointGroupId, boolean includeDeprecated) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
return controlService.getProfileFilterRecordsByEndpointGroupId(
endpointGroupId, includeDeprecated);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public ProfileFilterRecordDto getProfileFilterRecord(String endpointProfileSchemaId,
String serverProfileSchemaId,
String endpointGroupId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
ProfileFilterRecordDto record = controlService.getProfileFilterRecord(
endpointProfileSchemaId,
serverProfileSchemaId,
endpointGroupId);
return record;
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<ProfileVersionPairDto> getVacantProfileSchemasByEndpointGroupId(
String endpointGroupId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
return controlService.getVacantProfileSchemasByEndpointGroupId(endpointGroupId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public ProfileFilterDto editProfileFilter(ProfileFilterDto profileFilter)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
String username = getCurrentUser().getUsername();
if (isEmpty(profileFilter.getId())) {
profileFilter.setCreatedUsername(username);
checkEndpointGroupId(profileFilter.getEndpointGroupId());
} else {
profileFilter.setModifiedUsername(username);
ProfileFilterDto storedProfileFilter = controlService.getProfileFilter(
profileFilter.getId());
Utils.checkNotNull(storedProfileFilter);
checkEndpointGroupId(storedProfileFilter.getEndpointGroupId());
}
validateProfileFilterBody(profileFilter.getEndpointProfileSchemaId(),
profileFilter.getServerProfileSchemaId(),
profileFilter.getBody());
return controlService.editProfileFilter(profileFilter);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public ProfileFilterDto activateProfileFilter(String profileFilterId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
ProfileFilterDto storedProfileFilter = controlService.getProfileFilter(profileFilterId);
Utils.checkNotNull(storedProfileFilter);
checkEndpointGroupId(storedProfileFilter.getEndpointGroupId());
String username = getCurrentUser().getUsername();
return controlService.activateProfileFilter(profileFilterId, username);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public ProfileFilterDto deactivateProfileFilter(String profileFilterId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
ProfileFilterDto storedProfileFilter = controlService.getProfileFilter(profileFilterId);
Utils.checkNotNull(storedProfileFilter);
checkEndpointGroupId(storedProfileFilter.getEndpointGroupId());
String username = getCurrentUser().getUsername();
return controlService.deactivateProfileFilter(profileFilterId, username);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void deleteProfileFilterRecord(String endpointProfileSchemaId,
String serverProfileSchemaId,
String endpointGroupId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
ProfileFilterRecordDto record = controlService.getProfileFilterRecord(
endpointProfileSchemaId, serverProfileSchemaId, endpointGroupId);
checkEndpointGroupId(record.getEndpointGroupId());
String username = getCurrentUser().getUsername();
controlService.deleteProfileFilterRecord(
endpointProfileSchemaId, serverProfileSchemaId, endpointGroupId, username);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointProfilesPageDto getEndpointProfileByEndpointGroupId(String endpointGroupId,
String limit,
String offset)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
if (Integer.valueOf(limit) > MAX_LIMIT) {
throw new IllegalArgumentException(
"Incorrect limit parameter. You must enter value not more than " + MAX_LIMIT);
}
EndpointGroupDto endpointGroupDto = getEndpointGroup(endpointGroupId);
PageLinkDto pageLinkDto = new PageLinkDto(endpointGroupId, limit, offset);
if (isGroupAll(endpointGroupDto)) {
pageLinkDto.setApplicationId(endpointGroupDto.getApplicationId());
}
return controlService.getEndpointProfileByEndpointGroupId(pageLinkDto);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointProfilesBodyDto getEndpointProfileBodyByEndpointGroupId(String endpointGroupId,
String limit,
String offset)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
if (Integer.valueOf(limit) > MAX_LIMIT) {
throw new IllegalArgumentException(
"Incorrect limit parameter. You must enter value not more than " + MAX_LIMIT);
}
EndpointGroupDto endpointGroupDto = getEndpointGroup(endpointGroupId);
PageLinkDto pageLinkDto = new PageLinkDto(endpointGroupId, limit, offset);
if (isGroupAll(endpointGroupDto)) {
pageLinkDto.setApplicationId(endpointGroupDto.getApplicationId());
}
return controlService.getEndpointProfileBodyByEndpointGroupId(pageLinkDto);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
private void checkEndpointGroupWeight(int weight) throws KaaAdminServiceException {
if (weight < 0) {
throw new IllegalArgumentException("The weight can't be negative number!");
}
}
private void validateProfileFilterBody(String endpointProfileSchemaId,
String serverProfileSchemaId,
String filterBody) throws KaaAdminServiceException {
GenericRecord endpointProfileRecord = null;
GenericRecord serverProfileRecord = null;
try {
if (endpointProfileSchemaId != null) {
EndpointProfileSchemaDto endpointProfileSchema = profileService.getProfileSchema(
endpointProfileSchemaId);
endpointProfileRecord = getDefaultRecordFromCtlSchema(
endpointProfileSchema.getCtlSchemaId());
}
if (serverProfileSchemaId != null) {
ServerProfileSchemaDto serverProfileSchema = profileService.getServerProfileSchema(
serverProfileSchemaId);
serverProfileRecord = getDefaultRecordFromCtlSchema(serverProfileSchema.getCtlSchemaId());
}
} catch (Exception ex) {
throw Utils.handleException(ex);
}
try {
StandardEvaluationContext evaluationContext;
if (endpointProfileRecord != null) {
evaluationContext = new StandardEvaluationContext(endpointProfileRecord);
evaluationContext.setVariable(
DefaultFilterEvaluator.CLIENT_PROFILE_VARIABLE_NAME, endpointProfileRecord);
} else {
evaluationContext = new StandardEvaluationContext();
}
evaluationContext.addPropertyAccessor(new GenericRecordPropertyAccessor());
evaluationContext.setVariable(DefaultFilterEvaluator.EP_KEYHASH_VARIABLE_NAME, "test");
if (serverProfileRecord != null) {
evaluationContext.setVariable(
DefaultFilterEvaluator.SERVER_PROFILE_VARIABLE_NAME, serverProfileRecord);
}
Expression expression = new SpelExpressionParser().parseExpression(filterBody);
expression.getValue(evaluationContext, Boolean.class);
} catch (Exception ex) {
throw new KaaAdminServiceException(
"Invalid profile filter body!", ex, ServiceErrorCode.BAD_REQUEST_PARAMS);
}
}
private GenericRecord getDefaultRecordFromCtlSchema(String ctlSchemaId) throws Exception {
CTLSchemaDto ctlSchema = controlService.getCtlSchemaById(ctlSchemaId);
Schema schema = controlService.exportCtlSchemaFlatAsSchema(ctlSchema);
GenericAvroConverter<GenericRecord> converter = new GenericAvroConverter<>(schema);
GenericRecord defaultRecord = converter.decodeJson(ctlSchema.getDefaultRecord());
return defaultRecord;
}
}