/*
* 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 com.google.common.base.Charsets;
import net.iharder.Base64;
import org.apache.avro.generic.GenericRecord;
import org.kaaproject.avro.ui.converter.FormAvroConverter;
import org.kaaproject.avro.ui.shared.RecordField;
import org.kaaproject.kaa.common.avro.GenericAvroConverter;
import org.kaaproject.kaa.common.dto.EndpointNotificationDto;
import org.kaaproject.kaa.common.dto.KaaAuthorityDto;
import org.kaaproject.kaa.common.dto.NotificationDto;
import org.kaaproject.kaa.common.dto.NotificationSchemaDto;
import org.kaaproject.kaa.common.dto.NotificationTypeDto;
import org.kaaproject.kaa.common.dto.TopicDto;
import org.kaaproject.kaa.common.dto.VersionDto;
import org.kaaproject.kaa.common.dto.ctl.CTLSchemaDto;
import org.kaaproject.kaa.server.admin.services.util.Utils;
import org.kaaproject.kaa.server.admin.shared.schema.ConverterType;
import org.kaaproject.kaa.server.admin.shared.schema.CtlSchemaFormDto;
import org.kaaproject.kaa.server.admin.shared.schema.CtlSchemaReferenceDto;
import org.kaaproject.kaa.server.admin.shared.schema.NotificationSchemaViewDto;
import org.kaaproject.kaa.server.admin.shared.schema.SchemaInfoDto;
import org.kaaproject.kaa.server.admin.shared.services.CtlService;
import org.kaaproject.kaa.server.admin.shared.services.KaaAdminServiceException;
import org.kaaproject.kaa.server.admin.shared.services.NotificationService;
import org.kaaproject.kaa.server.admin.shared.services.ServiceErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Service("notificationService")
public class NotificationServiceImpl extends AbstractAdminService implements NotificationService {
/**
* The Constant LOG.
*/
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationServiceImpl.class);
@Autowired
CtlService ctlService;
@Override
public List<NotificationSchemaDto> getNotificationSchemasByApplicationToken(
String applicationToken) throws KaaAdminServiceException {
return getNotificationSchemasByApplicationId(checkApplicationToken(applicationToken));
}
@Override
public List<NotificationSchemaDto> getNotificationSchemasByApplicationId(
String applicationId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(applicationId);
return controlService.findNotificationSchemasByAppIdAndType(
applicationId, NotificationTypeDto.USER);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<VersionDto> getUserNotificationSchemasByApplicationToken(String applicationToken)
throws KaaAdminServiceException {
return getUserNotificationSchemasByApplicationId(checkApplicationToken(applicationToken));
}
@Override
public List<VersionDto> getUserNotificationSchemasByApplicationId(String applicationId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(applicationId);
return controlService.getUserNotificationSchemasByAppId(applicationId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
/**
* Get notification schema.
*
* @param notificationSchemaId the id of notification schema
* @return notification schema
*/
public NotificationSchemaDto getNotificationSchema(String notificationSchemaId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
NotificationSchemaDto notificationSchema = controlService.getNotificationSchema(
notificationSchemaId);
Utils.checkNotNull(notificationSchema);
checkApplicationId(notificationSchema.getApplicationId());
return notificationSchema;
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public NotificationSchemaDto saveNotificationSchema(NotificationSchemaDto notificationSchema)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
if (isEmpty(notificationSchema.getId())) {
notificationSchema.setCreatedUsername(getCurrentUser().getUsername());
checkApplicationId(notificationSchema.getApplicationId());
} else {
NotificationSchemaDto storedNotificationSchema = controlService.getNotificationSchema(
notificationSchema.getId());
Utils.checkNotNull(storedNotificationSchema);
checkApplicationId(storedNotificationSchema.getApplicationId());
}
notificationSchema.setType(NotificationTypeDto.USER);
return controlService.saveNotificationSchema(notificationSchema);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<TopicDto> getTopicsByApplicationToken(String applicationToken)
throws KaaAdminServiceException {
return getTopicsByApplicationId(checkApplicationToken(applicationToken));
}
@Override
public List<TopicDto> getTopicsByApplicationId(String applicationId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(applicationId);
return controlService.getTopicByAppId(applicationId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<TopicDto> getTopicsByEndpointGroupId(String endpointGroupId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
return controlService.getTopicByEndpointGroupId(endpointGroupId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public List<TopicDto> getVacantTopicsByEndpointGroupId(String endpointGroupId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
return controlService.getVacantTopicByEndpointGroupId(endpointGroupId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public TopicDto getTopic(String topicId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
TopicDto topic = controlService.getTopic(topicId);
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
return topic;
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public TopicDto editTopic(TopicDto topic) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
if (isEmpty(topic.getId())) {
topic.setCreatedUsername(getCurrentUser().getUsername());
checkApplicationId(topic.getApplicationId());
} else {
throw new KaaAdminServiceException(
"Unable to edit existing topic!", ServiceErrorCode.INVALID_ARGUMENTS);
}
return controlService.editTopic(topic);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void deleteTopic(String topicId) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkTopicId(topicId);
TopicDto topic = controlService.getTopic(topicId);
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
controlService.deleteTopicById(topicId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void addTopicToEndpointGroup(String endpointGroupId, String topicId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
checkTopicId(topicId);
TopicDto topic = controlService.getTopic(topicId);
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
controlService.addTopicsToEndpointGroup(endpointGroupId, topicId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void removeTopicFromEndpointGroup(String endpointGroupId, String topicId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkEndpointGroupId(endpointGroupId);
checkTopicId(topicId);
TopicDto topic = controlService.getTopic(topicId);
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
controlService.removeTopicsFromEndpointGroup(endpointGroupId, topicId);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public NotificationDto sendNotification(NotificationDto notification, byte[] body)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkExpiredDate(notification);
notification.setBody(body);
checkApplicationId(notification.getApplicationId());
TopicDto topic = controlService.getTopic(notification.getTopicId());
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
return controlService.editNotification(notification);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public void sendNotification(NotificationDto notification, RecordField notificationData)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkExpiredDate(notification);
GenericRecord record = FormAvroConverter.createGenericRecordFromRecordField(
notificationData);
GenericAvroConverter<GenericRecord> converter = new GenericAvroConverter<>(
record.getSchema());
byte[] body = converter.encodeToJsonBytes(record);
notification.setBody(body);
checkApplicationId(notification.getApplicationId());
TopicDto topic = controlService.getTopic(notification.getTopicId());
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
controlService.editNotification(notification);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointNotificationDto sendUnicastNotification(NotificationDto notification,
String clientKeyHash,
byte[] body)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkExpiredDate(notification);
notification.setBody(body);
checkApplicationId(notification.getApplicationId());
TopicDto topic = controlService.getTopic(notification.getTopicId());
Utils.checkNotNull(topic);
checkApplicationId(topic.getApplicationId());
EndpointNotificationDto unicastNotification = new EndpointNotificationDto();
unicastNotification.setEndpointKeyHash(
Base64.decode(clientKeyHash.getBytes(Charsets.UTF_8)));
unicastNotification.setNotificationDto(notification);
return controlService.editUnicastNotification(unicastNotification);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public EndpointNotificationDto sendUnicastNotification(NotificationDto notification,
String clientKeyHash,
RecordField notificationData)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
GenericRecord record = FormAvroConverter.createGenericRecordFromRecordField(
notificationData);
GenericAvroConverter<GenericRecord> converter = new GenericAvroConverter<>(
record.getSchema());
byte[] body = converter.encodeToJsonBytes(record);
return sendUnicastNotification(notification, clientKeyHash, body);
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
private void checkTopicId(String topicId) throws IllegalArgumentException {
if (isEmpty(topicId)) {
throw new IllegalArgumentException("The topicId parameter is empty.");
}
}
private void checkExpiredDate(NotificationDto notification) throws KaaAdminServiceException {
if (null != notification.getExpiredAt() && notification.getExpiredAt().before(new Date())) {
throw new IllegalArgumentException("Overdue expiry time for notification!");
}
}
@Override
public List<SchemaInfoDto> getUserNotificationSchemaInfosByApplicationId(String applicationId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(applicationId);
List<NotificationSchemaDto> notificationSchemas =
controlService.findNotificationSchemasByAppIdAndType(
applicationId, NotificationTypeDto.USER);
List<SchemaInfoDto> schemaInfos = new ArrayList<>(notificationSchemas.size());
for (NotificationSchemaDto notificationSchema : notificationSchemas) {
SchemaInfoDto schemaInfo = new SchemaInfoDto(notificationSchema);
RecordField schemaForm = createRecordFieldFromCtlSchemaAndBody(
notificationSchema.getCtlSchemaId(), null);
schemaInfo.setSchemaForm(schemaForm);
schemaInfos.add(schemaInfo);
}
return schemaInfos;
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public NotificationSchemaViewDto getNotificationSchemaView(String notificationSchemaId)
throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
NotificationSchemaDto notificationSchema = getNotificationSchema(notificationSchemaId);
CTLSchemaDto ctlSchemaDto =
controlService.getCtlSchemaById(notificationSchema.getCtlSchemaId());
NotificationSchemaViewDto notificationSchemaViewDto = new NotificationSchemaViewDto(
notificationSchema, toCtlSchemaForm(ctlSchemaDto,
ConverterType.FORM_AVRO_CONVERTER));
return notificationSchemaViewDto;
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public NotificationSchemaViewDto saveNotificationSchemaView(
NotificationSchemaViewDto notificationSchemaView) throws KaaAdminServiceException {
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
NotificationSchemaDto notificationSchema = notificationSchemaView.getSchema();
String applicationId = notificationSchema.getApplicationId();
checkApplicationId(applicationId);
String ctlSchemaId = notificationSchema.getCtlSchemaId();
if (isEmpty(ctlSchemaId)) {
if (notificationSchemaView.useExistingCtlSchema()) {
CtlSchemaReferenceDto metaInfo = notificationSchemaView.getExistingMetaInfo();
CTLSchemaDto schema = ctlService.getCtlSchemaByFqnVersionTenantIdAndApplicationId(
metaInfo.getMetaInfo().getFqn(),
metaInfo.getVersion(),
metaInfo.getMetaInfo().getTenantId(),
metaInfo.getMetaInfo().getApplicationId());
notificationSchema.setCtlSchemaId(schema.getId());
} else {
CtlSchemaFormDto ctlSchemaForm = ctlService.saveCtlSchemaForm(
notificationSchemaView.getCtlSchemaForm(), ConverterType.FORM_AVRO_CONVERTER);
notificationSchema.setCtlSchemaId(ctlSchemaForm.getId());
}
}
NotificationSchemaDto savedNotificationSchema = saveNotificationSchema(notificationSchema);
return getNotificationSchemaView(savedNotificationSchema.getId());
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
@Override
public NotificationSchemaViewDto createNotificationSchemaFormCtlSchema(
CtlSchemaFormDto ctlSchemaForm) throws KaaAdminServiceException {
LOG.error("createNotificationSchemaFormCtlSchema [{}]",
ctlSchemaForm.getSchema().getDisplayString());
checkAuthority(KaaAuthorityDto.TENANT_DEVELOPER, KaaAuthorityDto.TENANT_USER);
try {
checkApplicationId(ctlSchemaForm.getMetaInfo().getApplicationId());
NotificationSchemaDto notificationSchema = new NotificationSchemaDto();
notificationSchema.setApplicationId(ctlSchemaForm.getMetaInfo().getApplicationId());
notificationSchema.setName(ctlSchemaForm.getSchema().getDisplayNameFieldValue());
notificationSchema.setDescription(ctlSchemaForm.getSchema().getDescriptionFieldValue());
CtlSchemaFormDto savedCtlSchemaForm = ctlService.saveCtlSchemaForm(
ctlSchemaForm, ConverterType.FORM_AVRO_CONVERTER);
notificationSchema.setCtlSchemaId(savedCtlSchemaForm.getId());
NotificationSchemaDto savedNotificationSchema = saveNotificationSchema(notificationSchema);
return getNotificationSchemaView(savedNotificationSchema.getId());
} catch (Exception ex) {
throw Utils.handleException(ex);
}
}
}