From 97c8cce5b132d92775dc7052e7eddc5146c0234d Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Fri, 8 Apr 2022 17:09:03 +0100 Subject: [PATCH 01/11] Rename .java to .kt --- .../appserver/converter/{Converter.java => Converter.kt} | 0 .../{DataMessageConverter.java => DataMessageConverter.kt} | 0 .../{NotificationConverter.java => NotificationConverter.kt} | 0 .../appserver/entity/{DataMessage.java => DataMessage.kt} | 0 .../org/radarbase/appserver/entity/{Message.java => Message.kt} | 0 .../appserver/entity/{Notification.java => Notification.kt} | 0 .../radarbase/appserver/entity/{Scheduled.java => Scheduled.kt} | 0 ...essageSchedulerService.java => DataMessageSchedulerService.kt} | 0 ...ationSchedulerService.java => NotificationSchedulerService.kt} | 0 .../common/{ObjectMapperFactory.java => ObjectMapperFactory.kt} | 0 .../fcm/config/{FcmSenderConfig.java => FcmSenderConfig.kt} | 0 .../fcm/config/{FcmServerConfig.java => FcmServerConfig.kt} | 0 .../downstream/{AdminSdkFcmSender.java => AdminSdkFcmSender.kt} | 0 .../org/radarbase/fcm/downstream/{FcmSender.java => FcmSender.kt} | 0 .../fcm/model/{FcmDataMessage.java => FcmDataMessage.kt} | 0 .../model/{FcmDownstreamMessage.java => FcmDownstreamMessage.kt} | 0 .../org/radarbase/fcm/model/{FcmMessage.java => FcmMessage.kt} | 0 .../{FcmNotificationMessage.java => FcmNotificationMessage.kt} | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/appserver/converter/{Converter.java => Converter.kt} (100%) rename src/main/java/org/radarbase/appserver/converter/{DataMessageConverter.java => DataMessageConverter.kt} (100%) rename src/main/java/org/radarbase/appserver/converter/{NotificationConverter.java => NotificationConverter.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{DataMessage.java => DataMessage.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{Message.java => Message.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{Notification.java => Notification.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{Scheduled.java => Scheduled.kt} (100%) rename src/main/java/org/radarbase/appserver/service/scheduler/{DataMessageSchedulerService.java => DataMessageSchedulerService.kt} (100%) rename src/main/java/org/radarbase/appserver/service/scheduler/{NotificationSchedulerService.java => NotificationSchedulerService.kt} (100%) rename src/main/java/org/radarbase/fcm/common/{ObjectMapperFactory.java => ObjectMapperFactory.kt} (100%) rename src/main/java/org/radarbase/fcm/config/{FcmSenderConfig.java => FcmSenderConfig.kt} (100%) rename src/main/java/org/radarbase/fcm/config/{FcmServerConfig.java => FcmServerConfig.kt} (100%) rename src/main/java/org/radarbase/fcm/downstream/{AdminSdkFcmSender.java => AdminSdkFcmSender.kt} (100%) rename src/main/java/org/radarbase/fcm/downstream/{FcmSender.java => FcmSender.kt} (100%) rename src/main/java/org/radarbase/fcm/model/{FcmDataMessage.java => FcmDataMessage.kt} (100%) rename src/main/java/org/radarbase/fcm/model/{FcmDownstreamMessage.java => FcmDownstreamMessage.kt} (100%) rename src/main/java/org/radarbase/fcm/model/{FcmMessage.java => FcmMessage.kt} (100%) rename src/main/java/org/radarbase/fcm/model/{FcmNotificationMessage.java => FcmNotificationMessage.kt} (100%) diff --git a/src/main/java/org/radarbase/appserver/converter/Converter.java b/src/main/java/org/radarbase/appserver/converter/Converter.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/converter/Converter.java rename to src/main/java/org/radarbase/appserver/converter/Converter.kt diff --git a/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.java b/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/converter/DataMessageConverter.java rename to src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt diff --git a/src/main/java/org/radarbase/appserver/converter/NotificationConverter.java b/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/converter/NotificationConverter.java rename to src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessage.java b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/DataMessage.java rename to src/main/java/org/radarbase/appserver/entity/DataMessage.kt diff --git a/src/main/java/org/radarbase/appserver/entity/Message.java b/src/main/java/org/radarbase/appserver/entity/Message.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/Message.java rename to src/main/java/org/radarbase/appserver/entity/Message.kt diff --git a/src/main/java/org/radarbase/appserver/entity/Notification.java b/src/main/java/org/radarbase/appserver/entity/Notification.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/Notification.java rename to src/main/java/org/radarbase/appserver/entity/Notification.kt diff --git a/src/main/java/org/radarbase/appserver/entity/Scheduled.java b/src/main/java/org/radarbase/appserver/entity/Scheduled.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/Scheduled.java rename to src/main/java/org/radarbase/appserver/entity/Scheduled.kt diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.java b/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.java rename to src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.java b/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.java rename to src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt diff --git a/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.java b/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.java rename to src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt diff --git a/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.java b/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/config/FcmSenderConfig.java rename to src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt diff --git a/src/main/java/org/radarbase/fcm/config/FcmServerConfig.java b/src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/config/FcmServerConfig.java rename to src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt diff --git a/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.java b/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.java rename to src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt diff --git a/src/main/java/org/radarbase/fcm/downstream/FcmSender.java b/src/main/java/org/radarbase/fcm/downstream/FcmSender.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/downstream/FcmSender.java rename to src/main/java/org/radarbase/fcm/downstream/FcmSender.kt diff --git a/src/main/java/org/radarbase/fcm/model/FcmDataMessage.java b/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/model/FcmDataMessage.java rename to src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt diff --git a/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.java b/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.java rename to src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt diff --git a/src/main/java/org/radarbase/fcm/model/FcmMessage.java b/src/main/java/org/radarbase/fcm/model/FcmMessage.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/model/FcmMessage.java rename to src/main/java/org/radarbase/fcm/model/FcmMessage.kt diff --git a/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.java b/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt similarity index 100% rename from src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.java rename to src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt From c698ee72fdc61e9f8a2201ddb0d50be3407cbd26 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Fri, 8 Apr 2022 17:09:03 +0100 Subject: [PATCH 02/11] partial convert to kotlin (FCM package and any dependents) - Also makes the creation of messaged for FCM more streamlined. --- build.gradle | 24 + .../appserver/converter/Converter.kt | 39 +- .../converter/DataMessageConverter.kt | 54 ++- .../converter/NotificationConverter.kt | 84 ++-- .../appserver/dto/fcm/FcmDataMessageDto.java | 4 +- .../appserver/dto/fcm/FcmNotificationDto.java | 4 +- .../appserver/entity/AuditModel.java | 2 +- .../radarbase/appserver/entity/DataMessage.kt | 254 +++-------- .../org/radarbase/appserver/entity/Message.kt | 134 +++--- .../appserver/entity/Notification.kt | 423 ++++-------------- .../radarbase/appserver/entity/Scheduled.kt | 19 +- .../service/FcmDataMessageService.java | 10 +- .../service/FcmNotificationService.java | 2 +- .../scheduler/DataMessageSchedulerService.kt | 76 ++-- .../scheduler/NotificationSchedulerService.kt | 120 +++-- .../quartz/SimpleQuartzNamingStrategy.java | 11 +- .../org/radarbase/fcm/common/CcsClient.java | 29 -- .../fcm/common/ObjectMapperFactory.kt | 45 +- .../radarbase/fcm/config/FcmSenderConfig.kt | 32 +- .../radarbase/fcm/config/FcmServerConfig.kt | 19 +- .../fcm/downstream/AdminSdkFcmSender.kt | 279 +++--------- .../org/radarbase/fcm/downstream/FcmSender.kt | 17 +- .../org/radarbase/fcm/model/FcmDataMessage.kt | 89 +++- .../fcm/model/FcmDownstreamMessage.kt | 65 ++- .../org/radarbase/fcm/model/FcmMessage.kt | 8 +- .../fcm/model/FcmNotificationMessage.kt | 154 ++++++- 26 files changed, 773 insertions(+), 1224 deletions(-) delete mode 100644 src/main/java/org/radarbase/fcm/common/CcsClient.java diff --git a/build.gradle b/build.gradle index 99b1b83a..b20f28f1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,12 @@ +buildscript { + ext.kotlin_version = '1.6.20' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} plugins { id 'pmd' id "com.github.lkishalmi.gatling" version "3.3.4" @@ -6,6 +15,7 @@ plugins { } apply plugin: 'checkstyle' +apply plugin: 'kotlin' apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'io.spring.dependency-management' @@ -37,6 +47,8 @@ ext { } sourceSets { + main.kotlin.srcDirs += 'src/main/java' + integrationTest { java { compileClasspath += main.output + test.output + test.compileClasspath @@ -105,6 +117,8 @@ dependencies { testImplementation group: 'org.junit.platform', name: 'junit-platform-engine', version: '1.8.2' gatling('com.fasterxml.jackson.datatype:jackson-datatype-jsr310') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation('com.fasterxml.jackson.module:jackson-module-kotlin') } checkstyle { @@ -183,3 +197,13 @@ test { } } } +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/src/main/java/org/radarbase/appserver/converter/Converter.kt b/src/main/java/org/radarbase/appserver/converter/Converter.kt index b5a9d781..278f7b37 100644 --- a/src/main/java/org/radarbase/appserver/converter/Converter.kt +++ b/src/main/java/org/radarbase/appserver/converter/Converter.kt @@ -18,33 +18,28 @@ * * * */ +package org.radarbase.appserver.converter -package org.radarbase.appserver.converter; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; +import java.util.stream.Collectors /** - * Generic converter class for conversions between entity {@link org.radarbase.appserver.entity} and - * DTO {@link org.radarbase.appserver.dto} objects. + * Generic converter class for conversions between entity [org.radarbase.appserver.entity] and + * DTO [org.radarbase.appserver.dto] objects. * * @param the entity object class * @param the DTO object class * @author yatharthranjan - *

TODO - Use MapStruct for mapping entities and DTOs (http://mapstruct.org/) - */ -public interface Converter { - - T dtoToEntity(S s); - - S entityToDto(T t); - - default List dtosToEntities(Collection ss) { - return ss.parallelStream().map(this::dtoToEntity).collect(Collectors.toList()); - } + * + * TODO - Use MapStruct for mapping entities and DTOs (http://mapstruct.org/) + */ +interface Converter { + fun dtoToEntity(s: S): T + fun entityToDto(t: T): S + fun dtosToEntities(ss: Collection): List { + return ss.parallelStream().map { s: S -> dtoToEntity(s) }.collect(Collectors.toList()) + } - default List entitiesToDtos(Collection ts) { - return ts.parallelStream().map(this::entityToDto).collect(Collectors.toList()); - } -} + fun entitiesToDtos(ts: Collection): List { + return ts.parallelStream().map { t: T -> entityToDto(t) }.collect(Collectors.toList()) + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt b/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt index 440e0444..206a3dc9 100644 --- a/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt @@ -18,44 +18,40 @@ * * * */ +package org.radarbase.appserver.converter -package org.radarbase.appserver.converter; - -import org.radarbase.appserver.dto.fcm.FcmDataMessageDto; -import org.radarbase.appserver.entity.DataMessage; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; +import org.radarbase.appserver.dto.fcm.FcmDataMessageDto +import org.radarbase.appserver.entity.DataMessage +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component /** - * Converter {@link Converter} class for {@link DataMessage} entity. + * Converter [Converter] class for [DataMessage] entity. * * @author yatharthranjan */ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) -public class DataMessageConverter implements Converter { - - @Override - public DataMessage dtoToEntity(FcmDataMessageDto dataMessageDto) { +class DataMessageConverter : Converter { - return new DataMessage.DataMessageBuilder() - .mutableContent(dataMessageDto.isMutableContent()) - .priority(dataMessageDto.getPriority()) - .fcmCondition(dataMessageDto.getFcmCondition()) - .fcmTopic(dataMessageDto.getFcmTopic()) - .fcmMessageId(String.valueOf(dataMessageDto.hashCode())) - .appPackage(dataMessageDto.getAppPackage()) - .sourceType(dataMessageDto.getSourceType()) - .sourceId(dataMessageDto.getSourceId()) - .ttlSeconds(dataMessageDto.getTtlSeconds()) - .scheduledTime(dataMessageDto.getScheduledTime()) - .dataMap(dataMessageDto.getDataMap()) - .build(); + override fun dtoToEntity(dataMessageDto: FcmDataMessageDto): DataMessage { + return DataMessage( + mutableContent = dataMessageDto.isMutableContent, + priority = dataMessageDto.priority, + fcmCondition = dataMessageDto.fcmCondition, + fcmTopic = dataMessageDto.fcmTopic, + fcmMessageId = dataMessageDto.hashCode().toString(), + appPackage = dataMessageDto.appPackage, + sourceType = dataMessageDto.sourceType, + sourceId = dataMessageDto.sourceId, + ttlSeconds = dataMessageDto.ttlSeconds, + scheduledTime = dataMessageDto.scheduledTime, + dataMap = dataMessageDto.dataMap + ) } - @Override - public FcmDataMessageDto entityToDto(DataMessage dataMessage) { - return new FcmDataMessageDto(dataMessage); + override fun entityToDto(dataMessage: DataMessage): FcmDataMessageDto { + return FcmDataMessageDto(dataMessage) } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt b/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt index 9629d36c..af5495d5 100644 --- a/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt @@ -18,59 +18,55 @@ * * * */ +package org.radarbase.appserver.converter -package org.radarbase.appserver.converter; - -import org.radarbase.appserver.dto.fcm.FcmNotificationDto; -import org.radarbase.appserver.entity.Notification; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; +import org.radarbase.appserver.dto.fcm.FcmNotificationDto +import org.radarbase.appserver.entity.Notification +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component /** - * Converter {@link Converter} class for {@link Notification} entity. + * Converter [Converter] class for [Notification] entity. * * @author yatharthranjan */ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) -public class NotificationConverter implements Converter { - - @Override - public Notification dtoToEntity(FcmNotificationDto notificationDto) { +class NotificationConverter : Converter { - return new Notification.NotificationBuilder() - .body(notificationDto.getBody()) - .scheduledTime(notificationDto.getScheduledTime()) - .title(notificationDto.getTitle()) - .sourceId(notificationDto.getSourceId()) - .type(notificationDto.getType()) - .ttlSeconds(notificationDto.getTtlSeconds()) - .fcmMessageId(String.valueOf(notificationDto.hashCode())) - .appPackage(notificationDto.getAppPackage()) - .sourceType(notificationDto.getSourceType()) - .additionalData(notificationDto.getAdditionalData()) - .androidChannelId(notificationDto.getAndroidChannelId()) - .bodyLocArgs(notificationDto.getBodyLocArgs()) - .bodyLocKey(notificationDto.getBodyLocKey()) - .titleLocKey(notificationDto.getTitleLocKey()) - .titleLocArgs(notificationDto.getTitleLocArgs()) - .badge(notificationDto.getBadge()) - .clickAction(notificationDto.getClickAction()) - .color(notificationDto.getColor()) - .fcmCondition(notificationDto.getFcmCondition()) - .fcmTopic(notificationDto.getFcmTopic()) - .icon(notificationDto.getIcon()) - .mutableContent(notificationDto.isMutableContent()) - .priority(notificationDto.getPriority()) - .sound(notificationDto.getSound()) - .subtitle(notificationDto.getSubtitle()) - .tag(notificationDto.getTag()) - .build(); + override fun dtoToEntity(notificationDto: FcmNotificationDto): Notification { + return Notification( + body = notificationDto.body, + scheduledTime = notificationDto.scheduledTime, + title = notificationDto.title, + sourceId = notificationDto.sourceId, + type = notificationDto.type, + ttlSeconds = notificationDto.ttlSeconds, + fcmMessageId = notificationDto.hashCode().toString(), + appPackage = notificationDto.appPackage, + sourceType = notificationDto.sourceType, + additionalData = notificationDto.additionalData, + androidChannelId = notificationDto.androidChannelId, + bodyLocArgs = notificationDto.bodyLocArgs, + bodyLocKey = notificationDto.bodyLocKey, + titleLocArgs = notificationDto.titleLocArgs, + titleLocKey = notificationDto.titleLocKey, + badge = notificationDto.badge, + clickAction = notificationDto.clickAction, + color = notificationDto.color, + fcmCondition = notificationDto.fcmCondition, + fcmTopic = notificationDto.fcmTopic, + icon = notificationDto.icon, + mutableContent = notificationDto.isMutableContent, + priority = notificationDto.priority, + sound = notificationDto.sound, + subtitle = notificationDto.subtitle, + tag = notificationDto.tag, + ) } - @Override - public FcmNotificationDto entityToDto(Notification notification) { - return new FcmNotificationDto(notification); + override fun entityToDto(notification: Notification): FcmNotificationDto { + return FcmNotificationDto(notification) } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java b/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java index 22ee1474..0ecc840c 100644 --- a/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java +++ b/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java @@ -89,7 +89,7 @@ public class FcmDataMessageDto implements Serializable { public FcmDataMessageDto(DataMessage dataMessageEntity) { this.id = dataMessageEntity.getId(); this.scheduledTime = dataMessageEntity.getScheduledTime(); - this.delivered = dataMessageEntity.isDelivered(); + this.delivered = dataMessageEntity.getDelivered(); this.fcmMessageId = dataMessageEntity.getFcmMessageId(); this.sourceId = dataMessageEntity.getSourceId(); this.appPackage = dataMessageEntity.getAppPackage(); @@ -106,7 +106,7 @@ public FcmDataMessageDto(DataMessage dataMessageEntity) { this.fcmTopic = dataMessageEntity.getFcmTopic(); this.fcmCondition = dataMessageEntity.getFcmCondition(); this.priority = dataMessageEntity.getPriority(); - this.mutableContent = dataMessageEntity.isMutableContent(); + this.mutableContent = dataMessageEntity.getMutableContent(); } public FcmDataMessageDto setCreatedAt(Instant createdAt) { diff --git a/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java b/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java index f194e7e7..3828e780 100644 --- a/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java +++ b/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java @@ -122,7 +122,7 @@ public FcmNotificationDto(Notification notificationEntity) { this.scheduledTime = notificationEntity.getScheduledTime(); this.title = notificationEntity.getTitle(); this.body = notificationEntity.getBody(); - this.delivered = notificationEntity.isDelivered(); + this.delivered = notificationEntity.getDelivered(); this.fcmMessageId = notificationEntity.getFcmMessageId(); this.sourceId = notificationEntity.getSourceId(); this.type = notificationEntity.getType(); @@ -152,7 +152,7 @@ public FcmNotificationDto(Notification notificationEntity) { this.androidChannelId = notificationEntity.getAndroidChannelId(); this.tag = notificationEntity.getTag(); this.clickAction = notificationEntity.getClickAction(); - this.mutableContent = notificationEntity.isMutableContent(); + this.mutableContent = notificationEntity.getMutableContent(); } public FcmNotificationDto setCreatedAt(Instant createdAt) { diff --git a/src/main/java/org/radarbase/appserver/entity/AuditModel.java b/src/main/java/org/radarbase/appserver/entity/AuditModel.java index 88030f03..fa62f6c1 100644 --- a/src/main/java/org/radarbase/appserver/entity/AuditModel.java +++ b/src/main/java/org/radarbase/appserver/entity/AuditModel.java @@ -46,7 +46,7 @@ value = {"createdAt", "updatedAt"}, allowGetters = true) @Data -abstract class AuditModel { +public abstract class AuditModel { @Temporal(TemporalType.TIMESTAMP) @Column(name = "created_at", nullable = false, updatable = false) @CreatedDate diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt index ba567cd4..40941e11 100644 --- a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt +++ b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt @@ -18,220 +18,88 @@ * * * */ +package org.radarbase.appserver.entity -package org.radarbase.appserver.entity; - -import java.time.Instant; -import java.util.Map; -import java.util.Objects; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.MapKeyColumn; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import org.radarbase.appserver.dto.fcm.FcmDataMessageDto; -import org.springframework.lang.Nullable; +import org.springframework.lang.Nullable +import java.time.Instant +import java.util.* +import javax.persistence.* +import javax.validation.constraints.NotNull /** - * {@link Entity} for persisting data messages. The corresponding DTO is {@link FcmDataMessageDto}. + * [Entity] for persisting data messages. The corresponding DTO is [FcmDataMessageDto]. * This also includes information for scheduling the data message through the Firebase Cloud * Messaging(FCM) system. * * @author yatharthranjan * @see Scheduled + * * @see org.radarbase.appserver.service.scheduler.DataMessageSchedulerService */ @Entity @Table( - name = "data_messages", - uniqueConstraints = { - @UniqueConstraint( - columnNames = { - "user_id", - "source_id", - "scheduled_time", - "ttl_seconds", - "delivered", - "dry_run" - }) - }) + name = "data_messages", + uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "source_id", "scheduled_time", "ttl_seconds", "delivered", "dry_run"])] +) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -@Getter -@Setter -@ToString -@NoArgsConstructor -@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName") -public class DataMessage extends Message { - private static final long serialVersionUID = 4L; +class DataMessage( + id: Long? = null, + user: @NotNull User? = null, + sourceId: String? = null, + scheduledTime: @NotNull Instant, + ttlSeconds: Int = 0, + fcmMessageId: String? = null, + fcmTopic: String? = null, + fcmCondition: String? = null, + delivered: Boolean = false, + validated: Boolean = false, + appPackage: String? = null, + sourceType: String? = null, + dryRun: Boolean = false, + priority: String? = null, + mutableContent: Boolean = false, @Nullable @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "data_message_map") @MapKeyColumn(name = "key", nullable = true) @Column(name = "value") - private Map dataMap; - - @NoArgsConstructor - public static class DataMessageBuilder { - transient Long id; - transient User user; - transient String sourceId; - transient Instant scheduledTime; - transient int ttlSeconds; - transient String fcmMessageId; - transient String fcmTopic; - transient String fcmCondition; - transient boolean delivered; - transient boolean validated; - transient String appPackage; - transient String sourceType; - transient boolean dryRun; - transient String priority; - transient boolean mutableContent; - transient Map dataMap; - - public DataMessageBuilder(DataMessage dataMessage) { - this.id = dataMessage.getId(); - this.user = dataMessage.getUser(); - this.sourceId = dataMessage.getSourceId(); - this.scheduledTime = dataMessage.getScheduledTime(); - this.ttlSeconds = dataMessage.getTtlSeconds(); - this.fcmMessageId = dataMessage.getFcmMessageId(); - this.fcmTopic = dataMessage.getFcmTopic(); - this.fcmCondition = dataMessage.getFcmCondition(); - this.delivered = dataMessage.isDelivered(); - this.validated = dataMessage.isValidated(); - this.appPackage = dataMessage.getAppPackage(); - this.sourceType = dataMessage.getSourceType(); - this.dryRun = dataMessage.isDryRun(); - this.mutableContent = dataMessage.isMutableContent(); - this.dataMap = dataMessage.getDataMap(); - } - - public DataMessageBuilder id(Long id) { - this.id = id; - return this; - } - - public DataMessageBuilder user(User user) { - this.user = user; - return this; - } - - public DataMessageBuilder sourceId(String sourceId) { - this.sourceId = sourceId; - return this; - } - - public DataMessageBuilder scheduledTime(Instant scheduledTime) { - this.scheduledTime = scheduledTime; - return this; - } - - public DataMessageBuilder ttlSeconds(int ttlSeconds) { - this.ttlSeconds = ttlSeconds; - return this; - } - - public DataMessageBuilder fcmMessageId(String fcmMessageId) { - this.fcmMessageId = fcmMessageId; - return this; - } - - public DataMessageBuilder fcmTopic(String fcmTopic) { - this.fcmTopic = fcmTopic; - return this; - } - - public DataMessageBuilder fcmCondition(String fcmCondition) { - this.fcmCondition = fcmCondition; - return this; - } - - public DataMessageBuilder delivered(boolean delivered) { - this.delivered = delivered; - return this; - } - - public DataMessageBuilder appPackage(String appPackage) { - this.appPackage = appPackage; - return this; - } - - public DataMessageBuilder sourceType(String sourceType) { - this.sourceType = sourceType; - return this; - } - - public DataMessageBuilder dryRun(boolean dryRun) { - this.dryRun = dryRun; - return this; - } - - public DataMessageBuilder priority(String priority) { - this.priority = priority; - return this; - } - - public DataMessageBuilder mutableContent(boolean mutableContent) { - this.mutableContent = mutableContent; - return this; - } - - - public DataMessageBuilder dataMap(Map dataMap) { - this.dataMap = dataMap; - return this; - } - - public DataMessage build() { - DataMessage dataMessage = new DataMessage(); - dataMessage.setId(this.id); - dataMessage.setUser(this.user); - dataMessage.setSourceId(this.sourceId); - dataMessage.setScheduledTime(this.scheduledTime); - dataMessage.setTtlSeconds(this.ttlSeconds); - dataMessage.setFcmMessageId(this.fcmMessageId); - dataMessage.setFcmTopic(this.fcmTopic); - dataMessage.setFcmCondition(this.fcmCondition); - dataMessage.setDelivered(this.delivered); - dataMessage.setValidated(this.validated); - dataMessage.setAppPackage(this.appPackage); - dataMessage.setSourceType(this.sourceType); - dataMessage.setDryRun(this.dryRun); - dataMessage.setPriority(this.priority); - dataMessage.setMutableContent(this.mutableContent); - dataMessage.setDataMap(this.dataMap); - - return dataMessage; - } + val dataMap: Map? = null, +) : Message( + id, + user, + sourceId, + scheduledTime, + ttlSeconds, + fcmMessageId, + fcmTopic, + fcmCondition, + delivered, + validated, + appPackage, + sourceType, + dryRun, + priority, + mutableContent +) { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + return if (other !is DataMessage) { + false + } else super.equals(other) } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof DataMessage)) { - return false; - } - return super.equals(o); - } - - @Override - public int hashCode() { + override fun hashCode(): Int { return Objects.hash( - super.hashCode(), - getDataMap()); + super.hashCode(), + dataMap + ) } -} + companion object { + private const val serialVersionUID = 4L + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/Message.kt b/src/main/java/org/radarbase/appserver/entity/Message.kt index 1c3840c0..34512ea1 100644 --- a/src/main/java/org/radarbase/appserver/entity/Message.kt +++ b/src/main/java/org/radarbase/appserver/entity/Message.kt @@ -18,127 +18,105 @@ * * * */ - -package org.radarbase.appserver.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import java.io.Serializable; -import java.time.Instant; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MappedSuperclass; -import javax.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; -import org.springframework.lang.Nullable; +package org.radarbase.appserver.entity + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.OnDelete +import org.hibernate.annotations.OnDeleteAction +import org.springframework.lang.Nullable +import java.io.Serializable +import java.time.Instant +import java.util.* +import javax.persistence.* +import javax.validation.constraints.NotNull @MappedSuperclass -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName") -public class Message extends AuditModel implements Serializable, Scheduled { - - private static final long serialVersionUID = -367424816328519L; - +abstract class Message( @Id @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; + val id: Long? = null, - @NotNull @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore - private User user; + val user: @NotNull User?, @Nullable @Column(name = "source_id") - private String sourceId; + val sourceId: String? = null, - @NotNull @Column(name = "scheduled_time", nullable = false) - private Instant scheduledTime; + override val scheduledTime: @NotNull Instant, @Column(name = "ttl_seconds") - private int ttlSeconds; + val ttlSeconds: Int = 0, @Column(name = "fcm_message_id", unique = true) - private String fcmMessageId; + val fcmMessageId: String? = null, // for use with the FCM admin SDK @Column(name = "fcm_topic") @Nullable - private String fcmTopic; + val fcmTopic: String? = null, // for use with the FCM admin SDK @Column(name = "fcm_condition") @Nullable - private String fcmCondition; + val fcmCondition: String? = null, // TODO: REMOVE DELIVERED AND VALIDATED. These can be handled by state lifecycle. - private boolean delivered; - - private boolean validated; + val delivered: Boolean = false, + val validated: Boolean = false, @Nullable @Column(name = "app_package") - private String appPackage; + val appPackage: String? = null, // Source Type from the Management Portal @Nullable @Column(name = "source_type") - private String sourceType; - - @Column(name = "dry_run") + val sourceType: String? = null, - // for use with the FCM admin SDK - private boolean dryRun; + @Column(name = "dry_run") // for use with the FCM admin SDK + val dryRun: Boolean = false, - private String priority; + val priority: String? = null, @Column(name = "mutable_content") - private boolean mutableContent; + val mutableContent: Boolean = false, + + ) : AuditModel(), Serializable, Scheduled { + - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - if (!(o instanceof Message)) { - return false; + if (other !is Message) { + return false } - Message that = (Message) o; - return getTtlSeconds() == that.getTtlSeconds() - && isDelivered() == that.isDelivered() - && isDryRun() == that.isDryRun() - && Objects.equals(getUser(), that.getUser()) - && Objects.equals(getSourceId(), that.getSourceId()) - && Objects.equals(getScheduledTime(), that.getScheduledTime()) - && Objects.equals(getAppPackage(), that.getAppPackage()); + return (ttlSeconds == other.ttlSeconds && delivered == other.delivered + && dryRun == other.dryRun && user == other.user + && sourceId == other.sourceId + && scheduledTime == other.scheduledTime + && appPackage == other.appPackage) } - @Override - public int hashCode() { + override fun hashCode(): Int { return Objects.hash( - getUser(), - getSourceId(), - getScheduledTime(), - getTtlSeconds(), - isDelivered(), - isDryRun(), - getAppPackage(), - getSourceType()); + user, + sourceId, + scheduledTime, + ttlSeconds, + delivered, + dryRun, + appPackage, + sourceType + ) + } + + companion object { + private const val serialVersionUID = -367424816328519L } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/Notification.kt b/src/main/java/org/radarbase/appserver/entity/Notification.kt index 925a9e8e..b9238331 100644 --- a/src/main/java/org/radarbase/appserver/entity/Notification.kt +++ b/src/main/java/org/radarbase/appserver/entity/Notification.kt @@ -18,394 +18,137 @@ * * * */ +package org.radarbase.appserver.entity -package org.radarbase.appserver.entity; - -import java.time.Instant; -import java.util.Map; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.MapKeyColumn; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotNull; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import org.radarbase.appserver.dto.fcm.FcmNotificationDto; -import org.springframework.lang.Nullable; +import lombok.ToString +import org.springframework.lang.Nullable +import java.time.Instant +import java.util.* +import javax.persistence.* +import javax.validation.constraints.NotNull /** - * {@link Entity} for persisting notifications. The corresponding DTO is {@link FcmNotificationDto}. + * [Entity] for persisting notifications. The corresponding DTO is [FcmNotificationDto]. * This also includes information for scheduling the notification through the Firebase Cloud * Messaging(FCM) system. * * @author yatharthranjan * @see Scheduled + * * @see org.radarbase.appserver.service.scheduler.NotificationSchedulerService */ @Table( - name = "notifications", - uniqueConstraints = { - @UniqueConstraint( - columnNames = { - "user_id", - "source_id", - "scheduled_time", - "title", - "body", - "type", - "ttl_seconds", - "delivered", - "dry_run" - }) - }) + name = "notifications", + uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "source_id", "scheduled_time", "title", "body", "type", "ttl_seconds", "delivered", "dry_run"])] +) @Entity -@Getter @ToString -@NoArgsConstructor -@Setter -@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName") -public class Notification extends Message { - - private static final long serialVersionUID = 6L; +class Notification( + id: Long? = null, + user: @NotNull User? = null, + sourceId: String? = null, + scheduledTime: @NotNull Instant, + ttlSeconds: Int = 0, + fcmMessageId: String? = null, + fcmTopic: String? = null, + fcmCondition: String? = null, + delivered: Boolean = false, + validated: Boolean = false, + appPackage: String? = null, + sourceType: String? = null, + dryRun: Boolean = false, + priority: String? = null, + mutableContent: Boolean = false, - @NotNull @Column(nullable = false) - private String title; - - private String body; + val title: @NotNull String, + val body: String? = null, // Type of notification. In terms of aRMT - PHQ8, RSES, ESM, etc. @Nullable - private String type; - - private String sound; + val type: String? = null, + val sound: String? = null, // For IOS - private String badge; + val badge: String? = null, // For IOS - private String subtitle; + val subtitle: String? = null, // For android - private String icon; + val icon: String? = null, // For android. Color of the icon - private String color; + val color: String? = null, @Column(name = "body_loc_key") - private String bodyLocKey; + val bodyLocKey: String? = null, @Column(name = "body_loc_args") - private String bodyLocArgs; + val bodyLocArgs: String? = null, @Column(name = "title_loc_key") - private String titleLocKey; + val titleLocKey: String? = null, @Column(name = "title_loc_args") - private String titleLocArgs; + val titleLocArgs: String? = null, // For android @Column(name = "android_channel_id") - private String androidChannelId; + val androidChannelId: String? = null, // For android - private String tag; + val tag: String? = null, @Column(name = "click_action") - private String clickAction; + val clickAction: String? = null, @Nullable @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "additional_key", nullable = true) @Column(name = "additional_value") - private Map additionalData; - - @NoArgsConstructor - public static class NotificationBuilder { - transient Long id; - transient User user; - transient String sourceId; - transient Instant scheduledTime; - transient int ttlSeconds; - transient String fcmMessageId; - transient String fcmTopic; - transient String fcmCondition; - transient boolean delivered; - transient boolean validated; - transient String appPackage; - transient String sourceType; - transient boolean dryRun; - transient String priority; - transient boolean mutableContent; - transient String title; - transient String body; - transient String type; - transient String sound; - transient String badge; - transient String subtitle; - transient String icon; - transient String color; - transient String bodyLocKey; - transient String bodyLocArgs; - transient String titleLocKey; - transient String titleLocArgs; - transient String androidChannelId; - transient String tag; - transient String clickAction; - transient Map additionalData; - - - public NotificationBuilder(Notification notification) { - this.id = notification.getId(); - this.user = notification.getUser(); - this.sourceId = notification.getSourceId(); - this.scheduledTime = notification.getScheduledTime(); - this.ttlSeconds = notification.getTtlSeconds(); - this.fcmMessageId = notification.getFcmMessageId(); - this.fcmTopic = notification.getFcmTopic(); - this.fcmCondition = notification.getFcmCondition(); - this.delivered = notification.isDelivered(); - this.validated = notification.isValidated(); - this.appPackage = notification.getAppPackage(); - this.sourceType = notification.getSourceType(); - this.dryRun = notification.isDryRun(); - this.mutableContent = notification.isMutableContent(); - this.additionalData = notification.getAdditionalData(); - this.title = notification.getTitle(); - this.body = notification.getBody(); - this.type = notification.getType(); - this.sound = notification.getSound(); - this.badge = notification.getBadge(); - this.subtitle = notification.getSubtitle(); - this.icon = notification.getIcon(); - this.color = notification.getColor(); - this.bodyLocKey = notification.getBodyLocKey(); - this.bodyLocArgs = notification.getBodyLocArgs(); - this.titleLocKey = notification.getTitleLocKey(); - this.titleLocArgs = notification.getTitleLocArgs(); - this.androidChannelId = notification.getAndroidChannelId(); - this.tag = notification.getTag(); - this.clickAction = notification.getClickAction(); - this.additionalData = notification.getAdditionalData(); - } - - public NotificationBuilder id(Long id) { - this.id = id; - return this; - } - - public NotificationBuilder user(User user) { - this.user = user; - return this; - } - - public NotificationBuilder sourceId(String sourceId) { - this.sourceId = sourceId; - return this; - } - - public NotificationBuilder scheduledTime(Instant scheduledTime) { - this.scheduledTime = scheduledTime; - return this; - } - - public NotificationBuilder ttlSeconds(int ttlSeconds) { - this.ttlSeconds = ttlSeconds; - return this; - } - - public NotificationBuilder fcmMessageId(String fcmMessageId) { - this.fcmMessageId = fcmMessageId; - return this; - } - - public NotificationBuilder fcmTopic(String fcmTopic) { - this.fcmTopic = fcmTopic; - return this; - } - - public NotificationBuilder fcmCondition(String fcmCondition) { - this.fcmCondition = fcmCondition; - return this; - } - - public NotificationBuilder delivered(boolean delivered) { - this.delivered = delivered; - return this; - } - - public NotificationBuilder appPackage(String appPackage) { - this.appPackage = appPackage; - return this; - } - - public NotificationBuilder sourceType(String sourceType) { - this.sourceType = sourceType; - return this; - } - - public NotificationBuilder dryRun(boolean dryRun) { - this.dryRun = dryRun; - return this; - } - - public NotificationBuilder priority(String priority) { - this.priority = priority; - return this; - } - - public NotificationBuilder mutableContent(boolean mutableContent) { - this.mutableContent = mutableContent; - return this; - } - - - public NotificationBuilder title(String title) { - this.title = title; - return this; - } - - public NotificationBuilder body(String body) { - this.body = body; - return this; - } - - public NotificationBuilder type(String type) { - this.type = type; - return this; - } - - public NotificationBuilder sound(String sound) { - this.sound = sound; - return this; - } - - public NotificationBuilder badge(String badge) { - this.badge = badge; - return this; - } - - public NotificationBuilder subtitle(String subtitle) { - this.subtitle = subtitle; - return this; - } - - public NotificationBuilder icon(String icon) { - this.icon = icon; - return this; - } - - public NotificationBuilder color(String color) { - this.color = color; - return this; - } - - public NotificationBuilder bodyLocKey(String bodyLocKey) { - this.bodyLocKey = bodyLocKey; - return this; - } - - public NotificationBuilder bodyLocArgs(String bodyLocArgs) { - this.bodyLocArgs = bodyLocArgs; - return this; - } - - public NotificationBuilder titleLocKey(String titleLocKey) { - this.titleLocKey = titleLocKey; - return this; - } - - public NotificationBuilder titleLocArgs(String titleLocArgs) { - this.titleLocArgs = titleLocArgs; - return this; - } - - public NotificationBuilder androidChannelId(String androidChannelId) { - this.androidChannelId = androidChannelId; - return this; - } - - public NotificationBuilder tag(String tag) { - this.tag = tag; - return this; - } - - public NotificationBuilder clickAction(String clickAction) { - this.clickAction = clickAction; - return this; - } - - public NotificationBuilder additionalData(Map additionalData) { - this.additionalData = additionalData; - return this; - } - - public Notification build() { - Notification notification = new Notification(); - notification.setId(this.id); - notification.setUser(this.user); - notification.setSourceId(this.sourceId); - notification.setScheduledTime(this.scheduledTime); - notification.setTtlSeconds(this.ttlSeconds); - notification.setFcmMessageId(this.fcmMessageId); - notification.setFcmTopic(this.fcmTopic); - notification.setFcmCondition(this.fcmCondition); - notification.setDelivered(this.delivered); - notification.setValidated(this.validated); - notification.setAppPackage(this.appPackage); - notification.setSourceType(this.sourceType); - notification.setDryRun(this.dryRun); - notification.setPriority(this.priority); - notification.setMutableContent(this.mutableContent); - notification.setAdditionalData(this.additionalData); - notification.setTitle(this.title); - notification.setBody(this.body); - notification.setType(this.type); - notification.setSound(this.sound); - notification.setBadge(this.badge); - notification.setSubtitle(this.subtitle); - notification.setIcon(this.icon); - notification.setColor(this.color); - notification.setBodyLocKey(this.bodyLocKey); - notification.setBodyLocArgs(this.bodyLocArgs); - notification.setTitleLocKey(this.titleLocKey); - notification.setTitleLocArgs(this.titleLocArgs); - notification.setAndroidChannelId(this.androidChannelId); - notification.setTag(this.tag); - notification.setClickAction(this.clickAction); - notification.setAdditionalData(this.additionalData); - - return notification; - } + val additionalData: Map? = null, +) : Message( + id, + user, + sourceId, + scheduledTime, + ttlSeconds, + fcmMessageId, + fcmTopic, + fcmCondition, + delivered, + validated, + appPackage, + sourceType, + dryRun, + priority, + mutableContent +) { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other !is Notification) { + return false + } + return (super.equals(other) + && title == other.title + && body == other.body + && type == other.type) } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Notification)) { - return false; - } - Notification that = (Notification) o; - return super.equals(o) - && Objects.equals(getTitle(), that.getTitle()) - && Objects.equals(getBody(), that.getBody()) - && Objects.equals(getType(), that.getType()); + override fun hashCode(): Int { + return Objects.hash( + super.hashCode(), + title, + body, + type + ) } - @Override - public int hashCode() { - return Objects.hash( - super.hashCode(), - getTitle(), - getBody(), - getType()); + companion object { + private const val serialVersionUID = 6L } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/Scheduled.kt b/src/main/java/org/radarbase/appserver/entity/Scheduled.kt index d247af59..6dfc2ebd 100644 --- a/src/main/java/org/radarbase/appserver/entity/Scheduled.kt +++ b/src/main/java/org/radarbase/appserver/entity/Scheduled.kt @@ -18,22 +18,19 @@ * * * */ +package org.radarbase.appserver.entity -package org.radarbase.appserver.entity; - -import java.time.Instant; -import org.radarbase.appserver.service.scheduler.quartz.SchedulerServiceImpl; +import java.time.Instant /** - * Functional Interface to signify a class that can be scheduled using the {@link - * SchedulerServiceImpl}. + * Functional Interface to signify a class that can be scheduled using the [ ]. * * @see Notification + * * @see SchedulerServiceImpl + * * @author yatharthranjan */ -@FunctionalInterface -public interface Scheduled { - - Instant getScheduledTime(); -} +interface Scheduled { + val scheduledTime: Instant? +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java index a75a980d..0f051bd7 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java @@ -97,7 +97,9 @@ public FcmDataMessages getAllDataMessages() { @Transactional(readOnly = true) public FcmDataMessageDto getDataMessageById(long id) { Optional dataMessage = dataMessageRepository.findById(id); - return dataMessageConverter.entityToDto(dataMessage.orElseGet(DataMessage::new)); + return dataMessageConverter.entityToDto(dataMessage.orElseThrow(() -> { + throw new NotFoundException("Data Message with id " + id + "not found"); + })); } @Transactional(readOnly = true) @@ -190,7 +192,7 @@ public FcmDataMessageDto addDataMessage( private void addDataMessageStateEvent( DataMessage dataMessage, MessageState state, Instant time) { - if (dataMessageStateEventPublisher != null) { + if (dataMessageStateEventPublisher!=null) { DataMessageStateEventDto dataMessageStateEvent = new DataMessageStateEventDto(this, dataMessage, state, null, time); dataMessageStateEventPublisher.publishEvent(dataMessageStateEvent); @@ -201,7 +203,7 @@ private void addDataMessageStateEvent( public FcmDataMessageDto updateDataMessage( FcmDataMessageDto dataMessageDto, String subjectId, String projectId) { - if (dataMessageDto.getId() == null) { + if (dataMessageDto.getId()==null) { throw new InvalidNotificationDetailsException( "ID must be supplied for updating the data message"); } @@ -225,7 +227,7 @@ public FcmDataMessageDto updateDataMessage( DataMessage dataMessageSaved = this.dataMessageRepository.saveAndFlush(newDataMessage); addDataMessageStateEvent( dataMessageSaved, MessageState.UPDATED, dataMessageSaved.getUpdatedAt().toInstant()); - if (!dataMessage.get().isDelivered()) { + if (!dataMessage.get().getDelivered()) { this.schedulerService.updateScheduled(dataMessageSaved); } return dataMessageConverter.entityToDto(dataMessageSaved); diff --git a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java index 905066f0..fe0a51b6 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java @@ -269,7 +269,7 @@ public FcmNotificationDto updateNotification( Notification notificationSaved = this.notificationRepository.saveAndFlush(newNotification); addNotificationStateEvent( notificationSaved, MessageState.UPDATED, notificationSaved.getUpdatedAt().toInstant()); - if (!notification.get().isDelivered()) { + if (!notification.get().getDelivered()) { this.schedulerService.updateScheduled(notificationSaved); } return notificationConverter.entityToDto(notificationSaved); diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt b/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt index 57c4c396..c6223182 100644 --- a/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt +++ b/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt @@ -18,55 +18,51 @@ * * * */ +package org.radarbase.appserver.service.scheduler -package org.radarbase.appserver.service.scheduler; - -import java.util.Objects; -import lombok.extern.slf4j.Slf4j; -import org.radarbase.appserver.entity.DataMessage; -import org.radarbase.appserver.service.scheduler.quartz.SchedulerService; -import org.radarbase.fcm.downstream.FcmSender; -import org.radarbase.fcm.model.FcmDataMessage; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; +import org.radarbase.appserver.entity.DataMessage +import org.radarbase.appserver.service.scheduler.quartz.SchedulerService +import org.radarbase.fcm.downstream.FcmSender +import org.radarbase.fcm.model.FcmDataMessage +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.stereotype.Service +import kotlin.random.Random /** - * {@link Service} for scheduling Data Messages to be sent through FCM at the {@link - * org.radarbase.appserver.entity.Scheduled} time. It also provided functions for updating/ deleting + * [Service] for scheduling Data Messages to be sent through FCM at the [ ] time. It also provided functions for updating/ deleting * already scheduled Data Messsage Jobs. * * @author yatharthranjan */ @Service -@Slf4j -@SuppressWarnings("PMD.DataflowAnomalyAnalysis") -public class DataMessageSchedulerService extends MessageSchedulerService { - - public DataMessageSchedulerService( - @Autowired @Qualifier("fcmSenderProps") FcmSender fcmSender, - @Autowired SchedulerService schedulerService) { - super(fcmSender, schedulerService); +class DataMessageSchedulerService( + @Autowired @Qualifier("fcmSenderProps") fcmSender: FcmSender?, + @Autowired schedulerService: SchedulerService? +) : MessageSchedulerService(fcmSender, schedulerService) { + @Throws(Exception::class) + override fun send(dataMessage: DataMessage?) { + dataMessage?.let { + fcmSender.send(createMessageFromDataMessage(it)) + } } - private static FcmDataMessage createMessageFromDataMessage(DataMessage dataMessage) { - - String to = - Objects.requireNonNullElseGet( - dataMessage.getFcmTopic(), dataMessage.getUser()::getFcmToken); - return FcmDataMessage.builder() - .to(to) - .condition(dataMessage.getFcmCondition()) - .priority(dataMessage.getPriority()) - .mutableContent(dataMessage.isMutableContent()) - .deliveryReceiptRequested(IS_DELIVERY_RECEIPT_REQUESTED) - .messageId(String.valueOf(dataMessage.getFcmMessageId())) - .timeToLive(Objects.requireNonNullElse(dataMessage.getTtlSeconds(), 2_419_200)) - .data(dataMessage.getDataMap()) - .build(); - } + companion object { + private fun createMessageFromDataMessage(dataMessage: DataMessage): FcmDataMessage { + val to = dataMessage.fcmTopic ?: dataMessage.user?.fcmToken + ?: throw IllegalArgumentException("FCM Topic or User FCM Token is not set") - public void send(DataMessage dataMessage) throws Exception { - fcmSender.send(createMessageFromDataMessage(dataMessage)); + return FcmDataMessage( + to = to, + condition = dataMessage.fcmCondition, + priority = dataMessage.priority, + mutableContent = dataMessage.mutableContent, + deliveryReceiptRequested = IS_DELIVERY_RECEIPT_REQUESTED, + messageId = dataMessage.fcmMessageId + ?: Random(System.currentTimeMillis()).nextLong().toString(), + timeToLive = dataMessage.ttlSeconds, + data = dataMessage.dataMap, + ) + } } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt b/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt index 42688303..494f7d4e 100644 --- a/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt +++ b/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt @@ -18,80 +18,72 @@ * * * */ +package org.radarbase.appserver.service.scheduler -package org.radarbase.appserver.service.scheduler; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import lombok.extern.slf4j.Slf4j; -import org.radarbase.appserver.entity.Notification; -import org.radarbase.appserver.service.scheduler.quartz.SchedulerService; -import org.radarbase.fcm.downstream.FcmSender; -import org.radarbase.fcm.model.FcmNotificationMessage; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; +import org.radarbase.appserver.entity.Notification +import org.radarbase.appserver.service.scheduler.quartz.SchedulerService +import org.radarbase.fcm.downstream.FcmSender +import org.radarbase.fcm.model.FcmNotificationMessage +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.stereotype.Service +import kotlin.random.Random /** - * {@link Service} for scheduling Notifications to be sent through FCM at the {@link - * org.radarbase.appserver.entity.Scheduled} time. It also provided functions for updating/ deleting + * [Service] for scheduling Notifications to be sent through FCM at the [ ] time. It also provided functions for updating/ deleting * already scheduled Notification Jobs. * * @author yatharthranjan */ @Service -@Slf4j -public class NotificationSchedulerService extends MessageSchedulerService { - - public NotificationSchedulerService( - @Autowired @Qualifier("fcmSenderProps") FcmSender fcmSender, - @Autowired SchedulerService schedulerService) { - super(fcmSender, schedulerService); - } - - private static Map getNotificationMap(Notification notification) { - Map notificationMap = new HashMap<>(); - notificationMap.put("body", notification.getBody()); - notificationMap.put("title", notification.getTitle()); - notificationMap.put("sound", "default"); - - putIfNotNull(notificationMap, "sound", notification.getSound()); - putIfNotNull(notificationMap, "badge", notification.getBadge()); - putIfNotNull(notificationMap, "click_action", notification.getClickAction()); - putIfNotNull(notificationMap, "subtitle", notification.getSubtitle()); - putIfNotNull(notificationMap, "body_loc_key", notification.getBodyLocKey()); - putIfNotNull(notificationMap, "body_loc_args", notification.getBodyLocArgs()); - putIfNotNull(notificationMap, "title_loc_key", notification.getTitleLocKey()); - putIfNotNull(notificationMap, "title_loc_args", notification.getTitleLocArgs()); - putIfNotNull(notificationMap, "android_channel_id", notification.getAndroidChannelId()); - putIfNotNull(notificationMap, "icon", notification.getIcon()); - putIfNotNull(notificationMap, "tag", notification.getTag()); - putIfNotNull(notificationMap, "color", notification.getColor()); - - return notificationMap; +class NotificationSchedulerService( + @Autowired @Qualifier("fcmSenderProps") fcmSender: FcmSender?, + @Autowired schedulerService: SchedulerService? +) : MessageSchedulerService(fcmSender, schedulerService) { + @Throws(Exception::class) + override fun send(notification: Notification?) { + notification?.let { + fcmSender.send(createMessageFromNotification(it)) + } } - private static FcmNotificationMessage createMessageFromNotification(Notification notification) { - - String to = - Objects.requireNonNullElseGet( - notification.getFcmTopic(), notification.getUser()::getFcmToken); - return FcmNotificationMessage.builder() - .to(to) - .condition(notification.getFcmCondition()) - .priority(notification.getPriority()) - .mutableContent(notification.isMutableContent()) - .deliveryReceiptRequested(IS_DELIVERY_RECEIPT_REQUESTED) - .messageId(String.valueOf(notification.getFcmMessageId())) - .timeToLive(Objects.requireNonNullElse(notification.getTtlSeconds(), 2_419_200)) - .notification(getNotificationMap(notification)) - .data(notification.getAdditionalData()) - .build(); - } + companion object { + private fun getNotificationMap(notification: Notification): Map { + val notificationMap: MutableMap = HashMap() + notificationMap["body"] = notification.body ?: "" + notificationMap["title"] = notification.title + notificationMap["sound"] = "default" + putIfNotNull(notificationMap, "sound", notification.sound) + putIfNotNull(notificationMap, "badge", notification.badge) + putIfNotNull(notificationMap, "click_action", notification.clickAction) + putIfNotNull(notificationMap, "subtitle", notification.subtitle) + putIfNotNull(notificationMap, "body_loc_key", notification.bodyLocKey) + putIfNotNull(notificationMap, "body_loc_args", notification.bodyLocArgs) + putIfNotNull(notificationMap, "title_loc_key", notification.titleLocKey) + putIfNotNull(notificationMap, "title_loc_args", notification.titleLocArgs) + putIfNotNull(notificationMap, "android_channel_id", notification.androidChannelId) + putIfNotNull(notificationMap, "icon", notification.icon) + putIfNotNull(notificationMap, "tag", notification.tag) + putIfNotNull(notificationMap, "color", notification.color) + return notificationMap + } + private fun createMessageFromNotification(notification: Notification): FcmNotificationMessage { + val to = notification.fcmTopic ?: notification.user?.fcmToken + ?: throw IllegalArgumentException("FCM Topic or User FCM Token is not set") - public void send(Notification notification) throws Exception { - fcmSender.send(createMessageFromNotification(notification)); + return FcmNotificationMessage( + to = to, + condition = notification.fcmCondition, + priority = notification.priority, + mutableContent = notification.mutableContent, + deliveryReceiptRequested = IS_DELIVERY_RECEIPT_REQUESTED, + messageId = notification.fcmMessageId + ?: Random(System.currentTimeMillis()).nextLong().toString(), + timeToLive = notification.ttlSeconds, + notification = getNotificationMap(notification), + data = notification.additionalData, + ) + } } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/quartz/SimpleQuartzNamingStrategy.java b/src/main/java/org/radarbase/appserver/service/scheduler/quartz/SimpleQuartzNamingStrategy.java index 545439a8..ef30e06b 100644 --- a/src/main/java/org/radarbase/appserver/service/scheduler/quartz/SimpleQuartzNamingStrategy.java +++ b/src/main/java/org/radarbase/appserver/service/scheduler/quartz/SimpleQuartzNamingStrategy.java @@ -31,16 +31,15 @@ public class SimpleQuartzNamingStrategy implements QuartzNamingStrategy { @Override public String getTriggerName(String userName, String messageId) { - return new StringBuilder(TRIGGER_PREFIX) - .append(userName) - .append('-') - .append(messageId) - .toString(); + return TRIGGER_PREFIX + + userName + + '-' + + messageId; } @Override public String getJobKeyName(String userName, String messageId) { - return new StringBuilder(JOB_PREFIX).append(userName).append('-').append(messageId).toString(); + return JOB_PREFIX + userName + '-' + messageId; } @Override diff --git a/src/main/java/org/radarbase/fcm/common/CcsClient.java b/src/main/java/org/radarbase/fcm/common/CcsClient.java deleted file mode 100644 index 8e20ca12..00000000 --- a/src/main/java/org/radarbase/fcm/common/CcsClient.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * * - * * * Copyright 2018 King's College London - * * * - * * * 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.radarbase.fcm.common; - -/** - * A stereotype to specify if a class is a client of the FCM CCS server. - * - * @author yatharthranjan - */ -public interface CcsClient {} diff --git a/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt b/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt index cc9a5fd9..03d08eea 100644 --- a/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt +++ b/src/main/java/org/radarbase/fcm/common/ObjectMapperFactory.kt @@ -18,33 +18,36 @@ * * * */ +package org.radarbase.fcm.common -package org.radarbase.fcm.common; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.KotlinFeature +import com.fasterxml.jackson.module.kotlin.KotlinModule +import org.springframework.beans.factory.config.AbstractFactoryBean +import org.springframework.stereotype.Component /** - * A Factory Bean that provides {@link ObjectMapper} so that can be {@link - * org.springframework.beans.factory.annotation.Autowired} and same instance can be used everywhere. + * A Factory Bean that provides [ObjectMapper] so that can be [ ] and same instance can be used everywhere. * * @see AbstractFactoryBean for more details + * * @author yatharthranjan */ @Component -public class ObjectMapperFactory extends AbstractFactoryBean { - - // TODO Remove this if can directly autowire from Spring context - - @Override - public Class getObjectType() { - return ObjectMapper.class; - } +class ObjectMapperFactory : AbstractFactoryBean() { + // TODO Remove this if can directly autowire from Spring context + override fun getObjectType(): Class<*> { + return ObjectMapper::class.java + } - @Override - protected ObjectMapper createInstance() { - return new ObjectMapper().registerModule(new JavaTimeModule()); - } -} + override fun createInstance(): ObjectMapper { + return ObjectMapper() + .registerModule( + KotlinModule.Builder() + .configure(KotlinFeature.NullIsSameAsDefault, true) + .build() + ) + .registerModule(JavaTimeModule()) + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt b/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt index d0d8061c..2434c2e0 100644 --- a/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt +++ b/src/main/java/org/radarbase/fcm/config/FcmSenderConfig.kt @@ -1,23 +1,15 @@ -package org.radarbase.fcm.config; +package org.radarbase.fcm.config -import org.radarbase.fcm.downstream.FcmSender; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.radarbase.fcm.downstream.FcmSender +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration @Configuration -public class FcmSenderConfig { - - private final transient FcmServerConfig fcmServerConfig; - - public FcmSenderConfig(FcmServerConfig fcmServerConfig) { - this.fcmServerConfig = fcmServerConfig; - } - - @Bean("fcmSenderProps") - @SuppressWarnings("unchecked") - public FcmSender getFcmSender() throws Exception { - Class senderClass = - (Class) Class.forName(fcmServerConfig.getFcmsender()); - return senderClass.getConstructor().newInstance(); - } -} +open class FcmSenderConfig(private val fcmServerConfig: FcmServerConfig) { + @Throws(Exception::class) + @Bean("fcmSenderProps") + open fun fcmSender(): FcmSender { + val senderClass = Class.forName(fcmServerConfig.fcmsender) as Class + return senderClass.getConstructor().newInstance() + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt b/src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt index 122f30ea..56c7a5ae 100644 --- a/src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt +++ b/src/main/java/org/radarbase/fcm/config/FcmServerConfig.kt @@ -18,23 +18,18 @@ * * * */ +package org.radarbase.fcm.config -package org.radarbase.fcm.config; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; +import com.fasterxml.jackson.annotation.JsonProperty +import org.springframework.boot.context.properties.ConfigurationProperties /** * Loads Configuration required to connect to the FCM server. * * @author yatharthranjan */ -@Data @ConfigurationProperties(value = "fcmserver") -public class FcmServerConfig { - - @JsonProperty("fcmsender") - private String fcmsender; - -} +data class FcmServerConfig( + @JsonProperty("fcmsender") + val fcmsender: String = "org.radarbase.fcm.downstream.AdminSdkFcmSender" +) \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt b/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt index 27e3e89c..c52c5ec7 100644 --- a/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt +++ b/src/main/java/org/radarbase/fcm/downstream/AdminSdkFcmSender.kt @@ -18,32 +18,15 @@ * * * */ +package org.radarbase.fcm.downstream -package org.radarbase.fcm.downstream; - -import com.google.auth.oauth2.GoogleCredentials; -import com.google.firebase.FirebaseApp; -import com.google.firebase.FirebaseOptions; -import com.google.firebase.messaging.AndroidConfig; -import com.google.firebase.messaging.AndroidConfig.Priority; -import com.google.firebase.messaging.AndroidNotification; -import com.google.firebase.messaging.ApnsConfig; -import com.google.firebase.messaging.Aps; -import com.google.firebase.messaging.ApsAlert; -import com.google.firebase.messaging.FcmOptions; -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingException; -import com.google.firebase.messaging.Message; -import com.google.firebase.messaging.Notification; -import java.io.IOException; -import java.time.Duration; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.radarbase.fcm.model.FcmDataMessage; -import org.radarbase.fcm.model.FcmDownstreamMessage; -import org.radarbase.fcm.model.FcmNotificationMessage; +import com.google.auth.oauth2.GoogleCredentials +import com.google.firebase.FirebaseApp +import com.google.firebase.FirebaseOptions +import com.google.firebase.messaging.* +import org.radarbase.fcm.model.FcmDownstreamMessage +import org.radarbase.fcm.model.FcmNotificationMessage +import org.slf4j.LoggerFactory /** * When authorizing via a service account, you have to set the GOOGLE_APPLICATION_CREDENTIALS @@ -52,212 +35,58 @@ import org.radarbase.fcm.model.FcmNotificationMessage; * * @author yatharthranjan */ -@Slf4j -@SuppressWarnings({"PMD.DataflowAnomalyAnalysis", "PMD.AvoidDuplicateLiterals"}) -public class AdminSdkFcmSender implements FcmSender { - - public AdminSdkFcmSender() throws IOException { - // TODO also take config from application properties - FirebaseOptions options = - new FirebaseOptions.Builder() +class AdminSdkFcmSender : FcmSender { + init { + // TODO also take config from application properties + val options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.getApplicationDefault()) - .build(); - - try { - FirebaseApp.initializeApp(options); - } catch (IllegalStateException exc) { - log.warn("Firebase app was already initialised. {}", exc.getMessage()); + .build() + try { + FirebaseApp.initializeApp(options) + } catch (exc: IllegalStateException) { + logger.warn("Firebase app was already initialised. {}", exc.message) + } } - } - @Override - public void send(FcmDownstreamMessage downstreamMessage) throws FirebaseMessagingException { - // TODO Add support for WebPush as well - String priority = downstreamMessage.getPriority(); - - Message.Builder message = - Message.builder() - .setToken(downstreamMessage.getTo()) + @Throws(FirebaseMessagingException::class) + override fun send(downstreamMessage: FcmDownstreamMessage) { + // TODO Add support for WebPush as well + val message = Message.builder() + .setToken(downstreamMessage.to) .setFcmOptions(FcmOptions.builder().build()) - .setCondition(downstreamMessage.getCondition()); - - int ttl = downstreamMessage.getTimeToLive() * 1000; // Convert to milliseconds - - if (downstreamMessage instanceof FcmNotificationMessage) { - FcmNotificationMessage notificationMessage = (FcmNotificationMessage) downstreamMessage; - - message - .setAndroidConfig( - AndroidConfig.builder() - .setCollapseKey(downstreamMessage.getCollapseKey()) - .setPriority(priority == null ? Priority.HIGH : Priority.valueOf(priority)) - .setTtl(ttl) - .setNotification(getAndroidNotification(notificationMessage)) - .putAllData(notificationMessage.getData()) - .build()) - .setApnsConfig( - getApnsConfigBuilder(notificationMessage, ttl) - .putHeader("apns-push-type", "alert") - .build()) - .putAllData(notificationMessage.getData()) - .setCondition(notificationMessage.getCondition()) - .setNotification( - Notification.builder() - .setBody( - String.valueOf( - notificationMessage.getNotification().getOrDefault("body", ""))) - .setTitle( - String.valueOf( - notificationMessage.getNotification().getOrDefault("title", ""))) - .setImage( - String.valueOf( - notificationMessage.getNotification().getOrDefault("image_url", ""))) - .build()); - } else if (downstreamMessage instanceof FcmDataMessage) { - FcmDataMessage dataMessage = (FcmDataMessage) downstreamMessage; - message - .setAndroidConfig( - AndroidConfig.builder() - .setCollapseKey(downstreamMessage.getCollapseKey()) - .setPriority(priority == null ? Priority.NORMAL : Priority.valueOf(priority)) - .setTtl(ttl) - .putAllData(dataMessage.getData()) - .build()) - .setApnsConfig(getApnsConfigBuilder(dataMessage, ttl).build()) - .setCondition(dataMessage.getCondition()) - .putAllData(dataMessage.getData()); - } else { - throw new IllegalArgumentException( - "The Message type is not known." + downstreamMessage.getClass()); + .setCondition(downstreamMessage.condition) + .setAndroidConfig(downstreamMessage.getAndroidConfig()) + .setApnsConfig(downstreamMessage.getApnsConfig()) + .putAllData(downstreamMessage.data) + .setCondition(downstreamMessage.condition) + + if (downstreamMessage is FcmNotificationMessage) { + message + .setNotification( + Notification.builder() + .setBody( + downstreamMessage.notification.getOrDefault("body", "").toString() + ) + .setTitle( + downstreamMessage.notification.getOrDefault("title", "").toString() + ) + .setImage( + downstreamMessage.notification.getOrDefault("image_url", "") + .toString() + ) + .build() + ) + } + + val response = FirebaseMessaging.getInstance().send(message.build()) + logger.info("Message Sent with response : {}", response) } - String response = FirebaseMessaging.getInstance().send(message.build()); - log.info("Message Sent with response : {}", response); - } - - private AndroidNotification getAndroidNotification(FcmNotificationMessage notificationMessage) { - AndroidNotification.Builder builder = - AndroidNotification.builder() - .setBody(String.valueOf(notificationMessage.getNotification().getOrDefault("body", ""))) - .setTitle( - String.valueOf(notificationMessage.getNotification().getOrDefault("title", ""))) - .setChannelId( - getString(notificationMessage.getNotification().get("android_channel_id"))) - .setColor(getString(notificationMessage.getNotification().get("color"))) - .setTag(getString(notificationMessage.getNotification().get("tag"))) - .setIcon(getString(notificationMessage.getNotification().get("icon"))) - .setSound(getString(notificationMessage.getNotification().get("sound"))) - .setClickAction(getString(notificationMessage.getNotification().get("click_action"))); - - String bodyLocKey = getString(notificationMessage.getNotification().get("body_loc_key")); - String titleLocKey = getString(notificationMessage.getNotification().get("title_loc_key")); - - if (bodyLocKey != null) { - builder - .setBodyLocalizationKey( - getString(notificationMessage.getNotification().get("body_loc_key"))) - .addBodyLocalizationArg( - getString(notificationMessage.getNotification().get("body_loc_args"))); + override fun doesProvideDeliveryReceipt(): Boolean { + return false } - if (titleLocKey != null) { - builder - .addTitleLocalizationArg( - getString(notificationMessage.getNotification().get("title_loc_args"))) - .setTitleLocalizationKey( - getString(notificationMessage.getNotification().get("title_loc_key"))); + companion object { + private val logger = LoggerFactory.getLogger(AdminSdkFcmSender::class.java) } - - return builder.build(); - } - - /** - * Get the APNS config builder. More info on values and keys - - * https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns/ - * and - * https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification - */ - private ApnsConfig.Builder getApnsConfigBuilder(FcmDownstreamMessage message, int ttl) { - ApnsConfig.Builder config = ApnsConfig.builder(); - - if (message.getCollapseKey() != null) - config.putHeader("apns-collapse-id", message.getCollapseKey()); - - // The date at which the notification is no longer valid. This value is a UNIX epoch - // expressed in seconds (UTC). - config.putHeader( - "apns-expiration", - String.valueOf(Instant.now().plus(Duration.ofMillis(ttl)).toEpochMilli() / 1000)); - - if (message instanceof FcmNotificationMessage) { - FcmNotificationMessage notificationMessage = (FcmNotificationMessage) message; - Map apnsData = new HashMap<>(notificationMessage.getData()); - - ApsAlert.Builder apsAlertBuilder = ApsAlert.builder(); - String title = getString(notificationMessage.getNotification().get("title")); - if (title != null) apsAlertBuilder.setTitle(title); - - String body = getString(notificationMessage.getNotification().get("body")); - if (body != null) apsAlertBuilder.setBody(body); - - String titleLocKey = getString(notificationMessage.getNotification().get("title_loc_key")); - if (titleLocKey != null) apsAlertBuilder.setTitleLocalizationKey(titleLocKey); - - String titleLocArgs = getString(notificationMessage.getNotification().get("title_loc_args")); - if (titleLocKey != null && titleLocArgs != null) - apsAlertBuilder.addTitleLocalizationArg(titleLocArgs); - - String bodyLocKey = getString(notificationMessage.getNotification().get("body_loc_key")); - if (bodyLocKey != null) apsAlertBuilder.setLocalizationKey("body_loc_key"); - - String bodyLocArgs = getString(notificationMessage.getNotification().get("body_loc_args")); - if (bodyLocKey != null && bodyLocArgs != null) - apsAlertBuilder.addLocalizationArg(bodyLocArgs); - - Aps.Builder apsBuilder = Aps.builder(); - String sound = getString(notificationMessage.getNotification().get("sound")); - if (sound != null) apsBuilder.setSound(sound); - - String badge = getString(notificationMessage.getNotification().get("badge")); - if (badge != null) apsBuilder.setBadge(Integer.parseInt(badge)); - - String category = getString(notificationMessage.getNotification().get("category")); - if (category != null) apsBuilder.setCategory(category); - - String threadId = getString(notificationMessage.getNotification().get("thread_id")); - if (threadId != null) apsBuilder.setThreadId(threadId); - - if (notificationMessage.getContentAvailable() != null) - apsBuilder.setContentAvailable(notificationMessage.getContentAvailable()); - - if (notificationMessage.getMutableContent() != null) - apsBuilder.setMutableContent(notificationMessage.getMutableContent()); - - return config - .putAllCustomData(apnsData) - .setAps(apsBuilder.setAlert(apsAlertBuilder.build()).build()) - .putHeader("apns-push-type", "alert"); - - } else if (message instanceof FcmDataMessage) { - FcmDataMessage dataMessage = (FcmDataMessage) message; - Map apnsData = new HashMap<>(dataMessage.getData()); - - return config - .putAllCustomData(apnsData) - .setAps(Aps.builder().setContentAvailable(true).setSound("default").build()) - .putHeader("apns-push-type", "background") // No alert is shown - .putHeader("apns-priority", "5"); // 5 required in case of background type - } else { - throw new IllegalArgumentException("The Message type is not known." + message.getClass()); - } - } - - private String getString(Object obj) { - return obj == null ? null : String.valueOf(obj); - } - - @Override - public boolean doesProvideDeliveryReceipt() { - return false; - } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/downstream/FcmSender.kt b/src/main/java/org/radarbase/fcm/downstream/FcmSender.kt index 93aed68e..b2a833dc 100644 --- a/src/main/java/org/radarbase/fcm/downstream/FcmSender.kt +++ b/src/main/java/org/radarbase/fcm/downstream/FcmSender.kt @@ -18,19 +18,18 @@ * * * */ +package org.radarbase.fcm.downstream -package org.radarbase.fcm.downstream; - -import org.radarbase.fcm.model.FcmDownstreamMessage; +import org.radarbase.fcm.model.FcmDownstreamMessage /** * Generic contract for sending messages to devices via Firebase. * @see org.radarbase.fcm.downstream.AdminSdkFcmSender + * * @author yatharthranjan */ -public interface FcmSender { - - void send(FcmDownstreamMessage message) throws Exception; - - boolean doesProvideDeliveryReceipt(); -} +interface FcmSender { + @Throws(Exception::class) + fun send(downstreamMessage: FcmDownstreamMessage) + fun doesProvideDeliveryReceipt(): Boolean +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt index 84e445b4..a4bef34e 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt @@ -18,23 +18,88 @@ * * * */ +package org.radarbase.fcm.model -package org.radarbase.fcm.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Map; -import lombok.Getter; -import lombok.experimental.SuperBuilder; +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.google.firebase.messaging.AndroidConfig +import com.google.firebase.messaging.ApnsConfig +import com.google.firebase.messaging.Aps +import com.google.firebase.messaging.WebpushConfig +import java.time.Duration +import java.time.Instant +import javax.validation.constraints.NotEmpty /** * @author yatharthranjan */ @JsonInclude(JsonInclude.Include.NON_NULL) -@SuperBuilder -@Getter -public class FcmDataMessage extends FcmDownstreamMessage { +class FcmDataMessage( + @JsonProperty + override val to: @NotEmpty String, + + @JsonProperty + override val condition: String? = null, + + @JsonProperty("message_id") + override val messageId: @NotEmpty String, + + @JsonProperty("collapse_key") + override val collapseKey: String? = null, + + @JsonProperty + override val priority: String? = null, + + @JsonProperty("content_available") + override val contentAvailable: Boolean? = null, + + @JsonProperty("mutable_content") + override val mutableContent: Boolean? = null, + + @JsonProperty("time_to_live") + override val timeToLive: Int = 2419200, // 4 weeks + + @JsonProperty("delivery_receipt_requested") + override val deliveryReceiptRequested: Boolean = false, + + @JsonProperty("dry_run") + override val dryRun: Boolean = false, @JsonProperty - private Map data; -} + override val data: Map? = null, +) : FcmDownstreamMessage { + + private val ttl = timeToLive * 1000L + + override fun getAndroidConfig(): AndroidConfig = AndroidConfig.builder() + .setCollapseKey(collapseKey) + .setPriority(AndroidConfig.Priority.valueOf(priority ?: "HIGH")) + .setTtl(ttl) + .putAllData(data) + .build() + + override fun getApnsConfig(): ApnsConfig { + val config = ApnsConfig.builder() + collapseKey?.let { + config.putHeader("apns-collapse-id", collapseKey) + } + + // The date at which the notification is no longer valid. This value is a UNIX epoch + // expressed in seconds (UTC). + return config.putHeader( + "apns-expiration", ( + Instant.now() + .plus(Duration.ofSeconds(timeToLive.toLong())) + .toEpochMilli() / 1000).toString() + ) + .putAllCustomData(data) + .setAps(Aps.builder().setContentAvailable(true).setSound("default").build()) + .putHeader("apns-push-type", "background") // No alert is shown + .putHeader("apns-priority", "5") // 5 required in case of background type + .build() + } + + override fun getWebPushConfig(): WebpushConfig { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt index 440dfc1b..628c6b3c 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt @@ -18,46 +18,31 @@ * * * */ +package org.radarbase.fcm.model -package org.radarbase.fcm.model; +import com.fasterxml.jackson.annotation.JsonInclude +import com.google.firebase.messaging.AndroidConfig +import com.google.firebase.messaging.ApnsConfig +import com.google.firebase.messaging.WebpushConfig +import javax.validation.constraints.NotEmpty -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import javax.validation.constraints.NotEmpty; -import lombok.Getter; -import lombok.experimental.SuperBuilder; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @JsonInclude(JsonInclude.Include.NON_NULL) -@SuperBuilder -@Getter -public abstract class FcmDownstreamMessage implements FcmMessage { - - @JsonProperty @NotEmpty private String to; - - @JsonProperty private String condition; - - @NotEmpty - @JsonProperty("message_id") - private String messageId; - - @JsonProperty("collapse_key") - private String collapseKey; - - @JsonProperty private String priority; - - @JsonProperty("content_available") - private Boolean contentAvailable; - - @JsonProperty("mutable_content") - private Boolean mutableContent; - - @JsonProperty("time_to_live") - private Integer timeToLive; - - @JsonProperty("delivery_receipt_requested") - private Boolean deliveryReceiptRequested; - - @JsonProperty("dry_run") - private Boolean dryRun; -} +interface FcmDownstreamMessage : FcmMessage { + val to: @NotEmpty String? + val condition: String? + val messageId: @NotEmpty String? + val collapseKey: String? + val priority: String? + val contentAvailable: Boolean? + val mutableContent: Boolean? + val timeToLive: Int + val deliveryReceiptRequested: Boolean + val dryRun: Boolean + val data: Map? + + fun getAndroidConfig(): AndroidConfig + fun getApnsConfig(): ApnsConfig + fun getWebPushConfig(): WebpushConfig +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/model/FcmMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmMessage.kt index 3fa908a2..2105819f 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmMessage.kt @@ -18,8 +18,8 @@ * * * */ +package org.radarbase.fcm.model -package org.radarbase.fcm.model; - -/** @author yatharthranjan */ -public interface FcmMessage {} +/** @author yatharthranjan + */ +interface FcmMessage \ No newline at end of file diff --git a/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt index 2be62b78..8f6807f6 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt @@ -18,24 +18,148 @@ * * * */ +package org.radarbase.fcm.model -package org.radarbase.fcm.model; +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.google.firebase.messaging.* +import java.time.Duration +import java.time.Instant +import javax.validation.constraints.NotEmpty -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Map; -import lombok.Getter; -import lombok.experimental.SuperBuilder; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @JsonInclude(JsonInclude.Include.NON_NULL) -@SuperBuilder -@Getter -public class FcmNotificationMessage extends FcmDownstreamMessage { +class FcmNotificationMessage( + @JsonProperty + override val to: @NotEmpty String, + + @JsonProperty + override val condition: String? = null, + + @JsonProperty("message_id") + override val messageId: @NotEmpty String, + + @JsonProperty("collapse_key") + override val collapseKey: String? = null, + + @JsonProperty + override val priority: String? = null, + + @JsonProperty("content_available") + override val contentAvailable: Boolean? = null, + + @JsonProperty("mutable_content") + override val mutableContent: Boolean? = null, + + @JsonProperty("time_to_live") + override val timeToLive: Int = 2419200, // 4 weeks + + @JsonProperty("delivery_receipt_requested") + override val deliveryReceiptRequested: Boolean = false, + + @JsonProperty("dry_run") + override val dryRun: Boolean = false, + + @JsonProperty + override val data: Map? = null, + + // TODO Add specific Notification model and data model classes instead of using Maps. + @JsonProperty + val notification: Map, + + ) : FcmDownstreamMessage { + override fun getAndroidConfig(): AndroidConfig = AndroidConfig.builder() + .setCollapseKey(collapseKey) + .setPriority(AndroidConfig.Priority.valueOf(priority ?: "HIGH")) + .setTtl((timeToLive * 1000).toLong()) + .setNotification(getAndroidNotification()) + .putAllData(data) + .build() + + override fun getApnsConfig(): ApnsConfig { + val config = ApnsConfig.builder() + collapseKey?.let { + config.putHeader("apns-collapse-id", collapseKey) + } + + // The date at which the notification is no longer valid. This value is a UNIX epoch + // expressed in seconds (UTC). + config.putHeader( + "apns-expiration", ( + Instant.now() + .plus(Duration.ofSeconds(timeToLive.toLong())) + .toEpochMilli() / 1000).toString() + ) + + val apsAlertBuilder = ApsAlert.builder() + notification["title"]?.let { apsAlertBuilder.setTitle(it.toString()) } + notification["body"]?.let { apsAlertBuilder.setBody(it.toString()) } + notification["title_loc_key"]?.let { apsAlertBuilder.setTitleLocalizationKey(it.toString()) } + notification["title_loc_key"]?.let { + notification["title_loc_args"]?.let { + apsAlertBuilder.addTitleLocalizationArg( + it.toString() + ) + } + } + notification["body_loc_key"]?.let { apsAlertBuilder.setLocalizationKey(it.toString()) } + notification["body_loc_key"]?.let { + notification["body_loc_args"]?.let { + apsAlertBuilder + .addLocalizationArg( + it + .toString() + ) + } + } + + val apsBuilder = Aps.builder() + notification["sound"]?.let { apsBuilder.setSound(it.toString()) } + notification["badge"]?.let { apsBuilder.setBadge(it.toString().toInt()) } + + notification["category"]?.let { apsBuilder.setCategory(it.toString()) } + notification["thread_id"]?.let { apsBuilder.setThreadId(it.toString()) } + + contentAvailable?.let { + apsBuilder.setContentAvailable(contentAvailable) + } + mutableContent?.let { + apsBuilder.setMutableContent(mutableContent) + } + return config + .putAllCustomData(data) + .setAps(apsBuilder.setAlert(apsAlertBuilder.build()).build()) + .putHeader("apns-push-type", "alert") + .build() + - // TODO Add specific Notification model and data model classes instead of using Maps. + } - @JsonProperty private Map notification; + override fun getWebPushConfig(): WebpushConfig { + TODO("Not yet implemented") + } - @JsonProperty private Map data; -} + private fun getAndroidNotification(): AndroidNotification { + val builder = AndroidNotification.builder() + .setBody(notification.getOrDefault("body", "").toString()) + .setTitle(notification.getOrDefault("title", "").toString()) + .setChannelId(notification["android_channel_id"].toString()) + .setColor(notification["color"].toString()) + .setTag(notification["tag"].toString()) + .setIcon(notification["icon"].toString()) + .setSound(notification["sound"].toString()) + .setClickAction(notification["click_action"].toString()) + notification["body_loc_key"]?.let { + builder + .setBodyLocalizationKey(notification["body_loc_key"].toString()) + .addBodyLocalizationArg(notification["body_loc_args"].toString()) + } + notification["title_loc_key"]?.let { + builder + .addTitleLocalizationArg(notification["title_loc_args"].toString()) + .setTitleLocalizationKey(notification["title_loc_key"].toString()) + } + return builder.build() + } +} \ No newline at end of file From 450e26b4a5500bce15fe186fc18994a91e405f2f Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Mon, 11 Apr 2022 16:41:20 +0100 Subject: [PATCH 03/11] Rename .java to .kt --- .../converter/{ProjectConverter.java => ProjectConverter.kt} | 0 .../appserver/converter/{UserConverter.java => UserConverter.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/appserver/converter/{ProjectConverter.java => ProjectConverter.kt} (100%) rename src/main/java/org/radarbase/appserver/converter/{UserConverter.java => UserConverter.kt} (100%) diff --git a/src/main/java/org/radarbase/appserver/converter/ProjectConverter.java b/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/converter/ProjectConverter.java rename to src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt diff --git a/src/main/java/org/radarbase/appserver/converter/UserConverter.java b/src/main/java/org/radarbase/appserver/converter/UserConverter.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/converter/UserConverter.java rename to src/main/java/org/radarbase/appserver/converter/UserConverter.kt From 448f97334c8eb342a0502d5037b906c4e88e067a Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Mon, 11 Apr 2022 16:41:20 +0100 Subject: [PATCH 04/11] Fix all compile time errors --- build.gradle | 16 +- .../appserver/config/ApplicationConfig.java | 3 +- .../appserver/converter/Converter.kt | 1 + .../converter/DataMessageConverter.kt | 24 +-- .../converter/NotificationConverter.kt | 56 +++---- .../appserver/converter/ProjectConverter.kt | 44 +++-- .../appserver/converter/UserConverter.kt | 86 +++++----- .../appserver/dto/fcm/FcmDataMessageDto.java | 61 ++++++- .../appserver/dto/fcm/FcmNotificationDto.java | 121 +++++++++++++- .../appserver/dto/fcm/FcmUserDto.java | 45 +++++- .../appserver/entity/AuditModel.java | 16 ++ .../radarbase/appserver/entity/DataMessage.kt | 83 ++++++---- .../org/radarbase/appserver/entity/Message.kt | 37 ++--- .../appserver/entity/Notification.kt | 150 ++++++++++++------ .../radarbase/appserver/entity/Project.java | 9 +- .../org/radarbase/appserver/entity/User.java | 33 +++- .../service/FcmDataMessageService.java | 29 ++-- .../service/FcmNotificationService.java | 52 +++--- .../scheduler/NotificationSchedulerService.kt | 2 +- .../repository/DataMessageRepositoryTest.java | 64 ++++---- .../NotificationRepositoryTest.java | 81 +++++----- .../service/FcmNotificationServiceTest.java | 107 ++++++------- .../NotificationSchedulerServiceTest.java | 38 ++--- 23 files changed, 737 insertions(+), 421 deletions(-) diff --git a/build.gradle b/build.gradle index b20f28f1..4d3a216f 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,9 @@ plugins { id "com.github.lkishalmi.gatling" version "3.3.4" id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.springframework.boot' version "2.6.6" + id "org.jetbrains.kotlin.plugin.spring" version "1.6.20" + id "org.jetbrains.kotlin.plugin.allopen" version "1.6.20" + id "org.jetbrains.kotlin.plugin.jpa" version "1.6.20" } apply plugin: 'checkstyle' @@ -59,6 +62,11 @@ sourceSets { } } +allOpen { + annotation("javax.persistence.Entity") + annotation("javax.persistence.Embeddable") + annotation("javax.persistence.MappedSuperclass") +} dependencies { implementation('org.springframework.boot:spring-boot-starter-data-jpa') @@ -69,6 +77,11 @@ dependencies { implementation('org.springframework.boot:spring-boot-starter-actuator') implementation('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:' + springBootVersion) implementation('org.springframework.security.oauth:spring-security-oauth2:' + springOauth2Version) + + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation group: 'com.pivovarit', name: 'throwing-function', version: throwingFunctionVersion implementation(group: 'de.codecentric', name: 'spring-boot-admin-starter-client', version: bootAdminVersion) @@ -117,8 +130,7 @@ dependencies { testImplementation group: 'org.junit.platform', name: 'junit-platform-engine', version: '1.8.2' gatling('com.fasterxml.jackson.datatype:jackson-datatype-jsr310') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation('com.fasterxml.jackson.module:jackson-module-kotlin') + } checkstyle { diff --git a/src/main/java/org/radarbase/appserver/config/ApplicationConfig.java b/src/main/java/org/radarbase/appserver/config/ApplicationConfig.java index a3ccd963..06a4077d 100644 --- a/src/main/java/org/radarbase/appserver/config/ApplicationConfig.java +++ b/src/main/java/org/radarbase/appserver/config/ApplicationConfig.java @@ -33,4 +33,5 @@ @EnableConfigurationProperties({FcmServerConfig.class}) @EnableTransactionManagement @EnableAsync -public class ApplicationConfig {} +public class ApplicationConfig { +} diff --git a/src/main/java/org/radarbase/appserver/converter/Converter.kt b/src/main/java/org/radarbase/appserver/converter/Converter.kt index 278f7b37..122960b3 100644 --- a/src/main/java/org/radarbase/appserver/converter/Converter.kt +++ b/src/main/java/org/radarbase/appserver/converter/Converter.kt @@ -35,6 +35,7 @@ import java.util.stream.Collectors interface Converter { fun dtoToEntity(s: S): T fun entityToDto(t: T): S + fun dtosToEntities(ss: Collection): List { return ss.parallelStream().map { s: S -> dtoToEntity(s) }.collect(Collectors.toList()) } diff --git a/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt b/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt index 206a3dc9..8365312f 100644 --- a/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/DataMessageConverter.kt @@ -36,19 +36,19 @@ import org.springframework.stereotype.Component class DataMessageConverter : Converter { override fun dtoToEntity(dataMessageDto: FcmDataMessageDto): DataMessage { - return DataMessage( - mutableContent = dataMessageDto.isMutableContent, - priority = dataMessageDto.priority, - fcmCondition = dataMessageDto.fcmCondition, - fcmTopic = dataMessageDto.fcmTopic, - fcmMessageId = dataMessageDto.hashCode().toString(), - appPackage = dataMessageDto.appPackage, - sourceType = dataMessageDto.sourceType, - sourceId = dataMessageDto.sourceId, - ttlSeconds = dataMessageDto.ttlSeconds, - scheduledTime = dataMessageDto.scheduledTime, + return DataMessage().apply { + mutableContent = dataMessageDto.isMutableContent + priority = dataMessageDto.priority + fcmCondition = dataMessageDto.fcmCondition + fcmTopic = dataMessageDto.fcmTopic + fcmMessageId = dataMessageDto.hashCode().toString() + appPackage = dataMessageDto.appPackage + sourceType = dataMessageDto.sourceType + sourceId = dataMessageDto.sourceId + ttlSeconds = dataMessageDto.ttlSeconds + scheduledTime = dataMessageDto.scheduledTime dataMap = dataMessageDto.dataMap - ) + } } override fun entityToDto(dataMessage: DataMessage): FcmDataMessageDto { diff --git a/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt b/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt index af5495d5..97252983 100644 --- a/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/NotificationConverter.kt @@ -36,34 +36,34 @@ import org.springframework.stereotype.Component class NotificationConverter : Converter { override fun dtoToEntity(notificationDto: FcmNotificationDto): Notification { - return Notification( - body = notificationDto.body, - scheduledTime = notificationDto.scheduledTime, - title = notificationDto.title, - sourceId = notificationDto.sourceId, - type = notificationDto.type, - ttlSeconds = notificationDto.ttlSeconds, - fcmMessageId = notificationDto.hashCode().toString(), - appPackage = notificationDto.appPackage, - sourceType = notificationDto.sourceType, - additionalData = notificationDto.additionalData, - androidChannelId = notificationDto.androidChannelId, - bodyLocArgs = notificationDto.bodyLocArgs, - bodyLocKey = notificationDto.bodyLocKey, - titleLocArgs = notificationDto.titleLocArgs, - titleLocKey = notificationDto.titleLocKey, - badge = notificationDto.badge, - clickAction = notificationDto.clickAction, - color = notificationDto.color, - fcmCondition = notificationDto.fcmCondition, - fcmTopic = notificationDto.fcmTopic, - icon = notificationDto.icon, - mutableContent = notificationDto.isMutableContent, - priority = notificationDto.priority, - sound = notificationDto.sound, - subtitle = notificationDto.subtitle, - tag = notificationDto.tag, - ) + return Notification().apply { + body = notificationDto.body + scheduledTime = notificationDto.scheduledTime + title = notificationDto.title + sourceId = notificationDto.sourceId + type = notificationDto.type + ttlSeconds = notificationDto.ttlSeconds + fcmMessageId = notificationDto.hashCode().toString() + appPackage = notificationDto.appPackage + sourceType = notificationDto.sourceType + additionalData = notificationDto.additionalData + androidChannelId = notificationDto.androidChannelId + bodyLocArgs = notificationDto.bodyLocArgs + bodyLocKey = notificationDto.bodyLocKey + titleLocArgs = notificationDto.titleLocArgs + titleLocKey = notificationDto.titleLocKey + badge = notificationDto.badge + clickAction = notificationDto.clickAction + color = notificationDto.color + fcmCondition = notificationDto.fcmCondition + fcmTopic = notificationDto.fcmTopic + icon = notificationDto.icon + mutableContent = notificationDto.isMutableContent + priority = notificationDto.priority + sound = notificationDto.sound + subtitle = notificationDto.subtitle + tag = notificationDto.tag + } } override fun entityToDto(notification: Notification): FcmNotificationDto { diff --git a/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt b/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt index ab7f00ba..b0536b0d 100644 --- a/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt @@ -18,37 +18,31 @@ * * * */ +package org.radarbase.appserver.converter -package org.radarbase.appserver.converter; - -import org.radarbase.appserver.dto.ProjectDto; -import org.radarbase.appserver.entity.Project; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.radarbase.appserver.dto.ProjectDto +import org.radarbase.appserver.entity.Project +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component /** - * Converter {@link Converter} class for {@link Project} entity. + * Converter [Converter] class for [Project] entity. * * @author yatharthranjan */ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) -public class ProjectConverter implements Converter { - - @Override - public Project dtoToEntity(ProjectDto projectDto) { - - return new Project().setProjectId(projectDto.getProjectId()); - } - - @Override - public ProjectDto entityToDto(Project project) { +class ProjectConverter : Converter { + override fun dtoToEntity(projectDto: ProjectDto): Project { + return Project().setProjectId(projectDto.projectId) + } - return new ProjectDto() - .setId(project.getId()) - .setProjectId(project.getProjectId()) - .setCreatedAt(project.getCreatedAt().toInstant()) - .setUpdatedAt(project.getUpdatedAt().toInstant()); - } -} + override fun entityToDto(project: Project): ProjectDto { + return ProjectDto() + .setId(project.id) + .setProjectId(project.projectId) + .setCreatedAt(project.createdAt.toInstant()) + .setUpdatedAt(project.updatedAt.toInstant()) + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/UserConverter.kt b/src/main/java/org/radarbase/appserver/converter/UserConverter.kt index aa930799..95bd584c 100644 --- a/src/main/java/org/radarbase/appserver/converter/UserConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/UserConverter.kt @@ -18,58 +18,56 @@ * * * */ +package org.radarbase.appserver.converter -package org.radarbase.appserver.converter; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import org.radarbase.appserver.dto.fcm.FcmUserDto; -import org.radarbase.appserver.entity.User; -import org.radarbase.appserver.entity.UserMetrics; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; +import org.radarbase.appserver.dto.fcm.FcmUserDto +import org.radarbase.appserver.entity.User +import org.radarbase.appserver.entity.UserMetrics +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component +import java.time.LocalDateTime +import java.time.ZoneOffset /** - * Converter {@link Converter} class for {@link User} entity and {@link FcmUserDto} DTO. + * Converter [Converter] class for [User] entity and [FcmUserDto] DTO. * * @author yatharthranjan */ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) -public class UserConverter implements Converter { - - public static UserMetrics getValidUserMetrics(FcmUserDto fcmUserDto) { - UserMetrics userMetrics; - if (fcmUserDto.getLastOpened() == null && fcmUserDto.getLastDelivered() == null) { - userMetrics = new UserMetrics(LocalDateTime.now().toInstant(ZoneOffset.UTC), null); - } else if (fcmUserDto.getLastDelivered() == null) { - userMetrics = new UserMetrics(fcmUserDto.getLastOpened(), null); - } else if (fcmUserDto.getLastOpened() == null) { - userMetrics = - new UserMetrics( - LocalDateTime.now().toInstant(ZoneOffset.UTC), fcmUserDto.getLastDelivered()); - } else { - userMetrics = new UserMetrics(fcmUserDto.getLastOpened(), fcmUserDto.getLastDelivered()); +class UserConverter : Converter { + override fun dtoToEntity(fcmUserDto: FcmUserDto): User { + return User() + .setFcmToken(fcmUserDto.fcmToken) + .setSubjectId(fcmUserDto.subjectId) + .setUserMetrics(getValidUserMetrics(fcmUserDto)) + .setEnrolmentDate(fcmUserDto.enrolmentDate) + .setTimezone(fcmUserDto.timezone) + .setLanguage(fcmUserDto.language) } - return userMetrics; - } - - @Override - public User dtoToEntity(FcmUserDto fcmUserDto) { - - return new User() - .setFcmToken(fcmUserDto.getFcmToken()) - .setSubjectId(fcmUserDto.getSubjectId()) - .setUserMetrics(getValidUserMetrics(fcmUserDto)) - .setEnrolmentDate(fcmUserDto.getEnrolmentDate()) - .setTimezone(fcmUserDto.getTimezone()) - .setLanguage(fcmUserDto.getLanguage()); - } + override fun entityToDto(user: User): FcmUserDto { + return FcmUserDto(user) + } - @Override - public FcmUserDto entityToDto(User user) { - return new FcmUserDto(user); - } -} + companion object { + @JvmStatic + fun getValidUserMetrics(fcmUserDto: FcmUserDto): UserMetrics { + val userMetrics: UserMetrics = + if (fcmUserDto.lastOpened == null && fcmUserDto.lastDelivered == null) { + UserMetrics(LocalDateTime.now().toInstant(ZoneOffset.UTC), null) + } else if (fcmUserDto.lastDelivered == null) { + UserMetrics(fcmUserDto.lastOpened, null) + } else if (fcmUserDto.lastOpened == null) { + UserMetrics( + LocalDateTime.now().toInstant(ZoneOffset.UTC), + fcmUserDto.lastDelivered + ) + } else { + UserMetrics(fcmUserDto.lastOpened, fcmUserDto.lastDelivered) + } + return userMetrics + } + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java b/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java index 0ecc840c..6b976662 100644 --- a/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java +++ b/src/main/java/org/radarbase/appserver/dto/fcm/FcmDataMessageDto.java @@ -39,7 +39,6 @@ /** * @author yatharthranjan */ -@Getter @ToString @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @@ -86,6 +85,66 @@ public class FcmDataMessageDto implements Serializable { @DateTimeFormat(iso = ISO.DATE_TIME) private Instant updatedAt; + public Long getId() { + return id; + } + + public Instant getScheduledTime() { + return scheduledTime; + } + + public boolean isDelivered() { + return delivered; + } + + public int getTtlSeconds() { + return ttlSeconds; + } + + public String getSourceId() { + return sourceId; + } + + public String getFcmMessageId() { + return fcmMessageId; + } + + public String getFcmTopic() { + return fcmTopic; + } + + public String getFcmCondition() { + return fcmCondition; + } + + public String getAppPackage() { + return appPackage; + } + + public String getSourceType() { + return sourceType; + } + + public Map getDataMap() { + return dataMap; + } + + public String getPriority() { + return priority; + } + + public boolean isMutableContent() { + return mutableContent; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + public FcmDataMessageDto(DataMessage dataMessageEntity) { this.id = dataMessageEntity.getId(); this.scheduledTime = dataMessageEntity.getScheduledTime(); diff --git a/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java b/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java index 3828e780..97444549 100644 --- a/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java +++ b/src/main/java/org/radarbase/appserver/dto/fcm/FcmNotificationDto.java @@ -37,7 +37,6 @@ import org.springframework.format.annotation.DateTimeFormat.ISO; /** @author yatharthranjan */ -@Getter @ToString @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @@ -117,6 +116,126 @@ public class FcmNotificationDto implements Serializable { @DateTimeFormat(iso = ISO.DATE_TIME) private Instant updatedAt; + public Long getId() { + return id; + } + + public Instant getScheduledTime() { + return scheduledTime; + } + + public boolean isDelivered() { + return delivered; + } + + public String getTitle() { + return title; + } + + public String getBody() { + return body; + } + + public int getTtlSeconds() { + return ttlSeconds; + } + + public String getSourceId() { + return sourceId; + } + + public String getFcmMessageId() { + return fcmMessageId; + } + + public String getFcmTopic() { + return fcmTopic; + } + + public String getFcmCondition() { + return fcmCondition; + } + + public String getType() { + return type; + } + + public String getAppPackage() { + return appPackage; + } + + public String getSourceType() { + return sourceType; + } + + public Map getAdditionalData() { + return additionalData; + } + + public String getPriority() { + return priority; + } + + public String getSound() { + return sound; + } + + public String getBadge() { + return badge; + } + + public String getSubtitle() { + return subtitle; + } + + public String getIcon() { + return icon; + } + + public String getColor() { + return color; + } + + public String getBodyLocKey() { + return bodyLocKey; + } + + public String getBodyLocArgs() { + return bodyLocArgs; + } + + public String getTitleLocKey() { + return titleLocKey; + } + + public String getTitleLocArgs() { + return titleLocArgs; + } + + public String getAndroidChannelId() { + return androidChannelId; + } + + public String getTag() { + return tag; + } + + public String getClickAction() { + return clickAction; + } + + public boolean isMutableContent() { + return mutableContent; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + public FcmNotificationDto(Notification notificationEntity) { this.id = notificationEntity.getId(); this.scheduledTime = notificationEntity.getScheduledTime(); diff --git a/src/main/java/org/radarbase/appserver/dto/fcm/FcmUserDto.java b/src/main/java/org/radarbase/appserver/dto/fcm/FcmUserDto.java index 751463d3..e59a7dd7 100644 --- a/src/main/java/org/radarbase/appserver/dto/fcm/FcmUserDto.java +++ b/src/main/java/org/radarbase/appserver/dto/fcm/FcmUserDto.java @@ -34,7 +34,6 @@ import org.springframework.format.annotation.DateTimeFormat; /** @author yatharthranjan */ -@Getter @EqualsAndHashCode @ToString @NoArgsConstructor @@ -151,4 +150,48 @@ public FcmUserDto setLanguage(String language) { this.language = language; return this; } + + public Long getId() { + return id; + } + + public String getProjectId() { + return projectId; + } + + public String getSubjectId() { + return subjectId; + } + + public Instant getLastOpened() { + return lastOpened; + } + + public Instant getLastDelivered() { + return lastDelivered; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public Instant getEnrolmentDate() { + return enrolmentDate; + } + + public String getTimezone() { + return timezone; + } + + public String getFcmToken() { + return fcmToken; + } + + public String getLanguage() { + return language; + } } diff --git a/src/main/java/org/radarbase/appserver/entity/AuditModel.java b/src/main/java/org/radarbase/appserver/entity/AuditModel.java index fa62f6c1..402f7c5b 100644 --- a/src/main/java/org/radarbase/appserver/entity/AuditModel.java +++ b/src/main/java/org/radarbase/appserver/entity/AuditModel.java @@ -56,4 +56,20 @@ public abstract class AuditModel { @Column(name = "updated_at", nullable = false) @LastModifiedDate private Date updatedAt; + + public Date getCreatedAt() { + return createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } } diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt index 40941e11..d6a6f303 100644 --- a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt +++ b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt @@ -24,7 +24,6 @@ import org.springframework.lang.Nullable import java.time.Instant import java.util.* import javax.persistence.* -import javax.validation.constraints.NotNull /** * [Entity] for persisting data messages. The corresponding DTO is [FcmDataMessageDto]. @@ -42,46 +41,14 @@ import javax.validation.constraints.NotNull uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "source_id", "scheduled_time", "ttl_seconds", "delivered", "dry_run"])] ) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -class DataMessage( - id: Long? = null, - user: @NotNull User? = null, - sourceId: String? = null, - scheduledTime: @NotNull Instant, - ttlSeconds: Int = 0, - fcmMessageId: String? = null, - fcmTopic: String? = null, - fcmCondition: String? = null, - delivered: Boolean = false, - validated: Boolean = false, - appPackage: String? = null, - sourceType: String? = null, - dryRun: Boolean = false, - priority: String? = null, - mutableContent: Boolean = false, +class DataMessage : Message() { @Nullable @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "data_message_map") @MapKeyColumn(name = "key", nullable = true) @Column(name = "value") - val dataMap: Map? = null, -) : Message( - id, - user, - sourceId, - scheduledTime, - ttlSeconds, - fcmMessageId, - fcmTopic, - fcmCondition, - delivered, - validated, - appPackage, - sourceType, - dryRun, - priority, - mutableContent -) { + var dataMap: Map? = null override fun equals(other: Any?): Boolean { if (this === other) { @@ -99,6 +66,52 @@ class DataMessage( ) } + @JvmOverloads + fun copy( + id: Long? = this.id, + user: User? = this.user, + scheduledTime: Instant? = this.scheduledTime, + sourceId: String? = this.sourceId, + sourceType: String? = this.sourceType, + ttlSeconds: Int = this.ttlSeconds, + fcmMessageId: String? = this.fcmMessageId, + fcmTopic: String? = this.fcmTopic, + fcmCondition: String? = this.fcmCondition, + appPackage: String? = this.appPackage, + dryRun: Boolean = this.dryRun, + delivered: Boolean = this.delivered, + validated: Boolean = this.validated, + priority: String? = this.priority, + mutableContent: Boolean = this.mutableContent, + createdAt: Date = this.createdAt, + updatedAt: Date = this.updatedAt, + ): DataMessage { + return DataMessage().apply { + this.id = id + this.user = user + this.scheduledTime = scheduledTime + this.sourceId = sourceId + this.sourceType = sourceType + this.ttlSeconds = ttlSeconds + this.fcmMessageId = fcmMessageId + this.fcmTopic = fcmTopic + this.fcmCondition = fcmCondition + this.appPackage = appPackage + this.dryRun = dryRun + this.delivered = delivered + this.validated = validated + this.priority = priority + this.mutableContent = mutableContent + this.createdAt = createdAt + this.updatedAt = updatedAt + } + } + + override fun toString(): String { + return "DataMessage(id=$id, dataMap=$dataMap)" + } + + companion object { private const val serialVersionUID = 4L } diff --git a/src/main/java/org/radarbase/appserver/entity/Message.kt b/src/main/java/org/radarbase/appserver/entity/Message.kt index 34512ea1..32fb24a6 100644 --- a/src/main/java/org/radarbase/appserver/entity/Message.kt +++ b/src/main/java/org/radarbase/appserver/entity/Message.kt @@ -28,66 +28,63 @@ import java.io.Serializable import java.time.Instant import java.util.* import javax.persistence.* -import javax.validation.constraints.NotNull @MappedSuperclass -abstract class Message( +abstract class Message : AuditModel(), Serializable, Scheduled { + @Id @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long? = null, + var id: Long? = null @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore - val user: @NotNull User?, + var user: User? = null @Nullable @Column(name = "source_id") - val sourceId: String? = null, + var sourceId: String? = null @Column(name = "scheduled_time", nullable = false) - override val scheduledTime: @NotNull Instant, + override var scheduledTime: Instant? = null @Column(name = "ttl_seconds") - val ttlSeconds: Int = 0, + var ttlSeconds: Int = 0 @Column(name = "fcm_message_id", unique = true) - val fcmMessageId: String? = null, + var fcmMessageId: String? = null // for use with the FCM admin SDK @Column(name = "fcm_topic") @Nullable - val fcmTopic: String? = null, + var fcmTopic: String? = null // for use with the FCM admin SDK @Column(name = "fcm_condition") @Nullable - val fcmCondition: String? = null, + var fcmCondition: String? = null // TODO: REMOVE DELIVERED AND VALIDATED. These can be handled by state lifecycle. - val delivered: Boolean = false, - val validated: Boolean = false, + var delivered: Boolean = false + var validated: Boolean = false @Nullable @Column(name = "app_package") - val appPackage: String? = null, + var appPackage: String? = null // Source Type from the Management Portal @Nullable @Column(name = "source_type") - val sourceType: String? = null, + var sourceType: String? = null @Column(name = "dry_run") // for use with the FCM admin SDK - val dryRun: Boolean = false, + var dryRun: Boolean = false - val priority: String? = null, + var priority: String? = null @Column(name = "mutable_content") - val mutableContent: Boolean = false, - - ) : AuditModel(), Serializable, Scheduled { - + var mutableContent: Boolean = false override fun equals(other: Any?): Boolean { if (this === other) { diff --git a/src/main/java/org/radarbase/appserver/entity/Notification.kt b/src/main/java/org/radarbase/appserver/entity/Notification.kt index b9238331..4319ad4e 100644 --- a/src/main/java/org/radarbase/appserver/entity/Notification.kt +++ b/src/main/java/org/radarbase/appserver/entity/Notification.kt @@ -20,12 +20,10 @@ */ package org.radarbase.appserver.entity -import lombok.ToString import org.springframework.lang.Nullable import java.time.Instant import java.util.* import javax.persistence.* -import javax.validation.constraints.NotNull /** * [Entity] for persisting notifications. The corresponding DTO is [FcmNotificationDto]. @@ -42,89 +40,56 @@ import javax.validation.constraints.NotNull uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "source_id", "scheduled_time", "title", "body", "type", "ttl_seconds", "delivered", "dry_run"])] ) @Entity -@ToString -class Notification( - id: Long? = null, - user: @NotNull User? = null, - sourceId: String? = null, - scheduledTime: @NotNull Instant, - ttlSeconds: Int = 0, - fcmMessageId: String? = null, - fcmTopic: String? = null, - fcmCondition: String? = null, - delivered: Boolean = false, - validated: Boolean = false, - appPackage: String? = null, - sourceType: String? = null, - dryRun: Boolean = false, - priority: String? = null, - mutableContent: Boolean = false, +class Notification : Message() { @Column(nullable = false) - val title: @NotNull String, - val body: String? = null, + var title: String? = null + var body: String? = null // Type of notification. In terms of aRMT - PHQ8, RSES, ESM, etc. @Nullable - val type: String? = null, - val sound: String? = null, + var type: String? = null + var sound: String? = null // For IOS - val badge: String? = null, + var badge: String? = null // For IOS - val subtitle: String? = null, + var subtitle: String? = null // For android - val icon: String? = null, + var icon: String? = null // For android. Color of the icon - val color: String? = null, + var color: String? = null @Column(name = "body_loc_key") - val bodyLocKey: String? = null, + var bodyLocKey: String? = null @Column(name = "body_loc_args") - val bodyLocArgs: String? = null, + var bodyLocArgs: String? = null @Column(name = "title_loc_key") - val titleLocKey: String? = null, + var titleLocKey: String? = null @Column(name = "title_loc_args") - val titleLocArgs: String? = null, + var titleLocArgs: String? = null // For android @Column(name = "android_channel_id") - val androidChannelId: String? = null, + var androidChannelId: String? = null // For android - val tag: String? = null, + var tag: String? = null @Column(name = "click_action") - val clickAction: String? = null, + var clickAction: String? = null @Nullable @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "additional_key", nullable = true) @Column(name = "additional_value") - val additionalData: Map? = null, -) : Message( - id, - user, - sourceId, - scheduledTime, - ttlSeconds, - fcmMessageId, - fcmTopic, - fcmCondition, - delivered, - validated, - appPackage, - sourceType, - dryRun, - priority, - mutableContent -) { + var additionalData: Map? = null override fun equals(other: Any?): Boolean { if (this === other) { @@ -148,6 +113,87 @@ class Notification( ) } + @JvmOverloads + fun copy( + id: Long? = this.id, + user: User? = this.user, + scheduledTime: Instant? = this.scheduledTime, + sourceId: String? = this.sourceId, + sourceType: String? = this.sourceType, + ttlSeconds: Int = this.ttlSeconds, + fcmMessageId: String? = this.fcmMessageId, + fcmTopic: String? = this.fcmTopic, + fcmCondition: String? = this.fcmCondition, + appPackage: String? = this.appPackage, + title: String? = this.title, + body: String? = this.body, + type: String? = this.type, + sound: String? = this.sound, + badge: String? = this.badge, + subtitle: String? = this.subtitle, + icon: String? = this.icon, + color: String? = this.color, + bodyLocKey: String? = this.bodyLocKey, + bodyLocArgs: String? = this.bodyLocArgs, + titleLocKey: String? = this.titleLocKey, + titleLocArgs: String? = this.titleLocArgs, + androidChannelId: String? = this.androidChannelId, + tag: String? = this.tag, + clickAction: String? = this.clickAction, + additionalData: Map? = this.additionalData, + dryRun: Boolean = this.dryRun, + delivered: Boolean = this.delivered, + validated: Boolean = this.validated, + priority: String? = this.priority, + mutableContent: Boolean = this.mutableContent, + createdAt: Date = this.createdAt, + updatedAt: Date = this.updatedAt, + ): Notification { + return Notification().apply { + this.id = id + this.user = user + this.scheduledTime = scheduledTime + this.sourceId = sourceId + this.sourceType = sourceType + this.ttlSeconds = ttlSeconds + this.fcmMessageId = fcmMessageId + this.fcmTopic = fcmTopic + this.fcmCondition = fcmCondition + this.appPackage = appPackage + this.title = title + this.body = body + this.type = type + this.sound = sound + this.badge = badge + this.subtitle = subtitle + this.icon = icon + this.color = color + this.bodyLocKey = bodyLocKey + this.bodyLocArgs = bodyLocArgs + this.titleLocKey = titleLocKey + this.titleLocArgs = titleLocArgs + this.androidChannelId = androidChannelId + this.tag = tag + this.clickAction = clickAction + this.additionalData = additionalData + this.dryRun = dryRun + this.delivered = delivered + this.validated = validated + this.priority = priority + this.mutableContent = mutableContent + this.createdAt = createdAt + this.updatedAt = updatedAt + } + } + + override fun toString(): String { + return "Notification(id=$id, title=$title, body=$body, type=$type, sound=$sound, " + + "badge=$badge, subtitle=$subtitle, icon=$icon, color=$color, " + + "bodyLocKey=$bodyLocKey, bodyLocArgs=$bodyLocArgs, titleLocKey=$titleLocKey," + + " titleLocArgs=$titleLocArgs, androidChannelId=$androidChannelId, tag=$tag," + + " clickAction=$clickAction, additionalData=$additionalData)" + } + companion object { private const val serialVersionUID = 6L } diff --git a/src/main/java/org/radarbase/appserver/entity/Project.java b/src/main/java/org/radarbase/appserver/entity/Project.java index c94b391b..5ea5d338 100644 --- a/src/main/java/org/radarbase/appserver/entity/Project.java +++ b/src/main/java/org/radarbase/appserver/entity/Project.java @@ -41,7 +41,6 @@ */ @Table(name = "projects") @Entity -@Getter @ToString @NoArgsConstructor public class Project extends AuditModel implements Serializable { @@ -66,6 +65,14 @@ public Project setProjectId(String projectId) { return this; } + public Long getId() { + return id; + } + + public String getProjectId() { + return projectId; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/main/java/org/radarbase/appserver/entity/User.java b/src/main/java/org/radarbase/appserver/entity/User.java index 61567a0c..648406ea 100644 --- a/src/main/java/org/radarbase/appserver/entity/User.java +++ b/src/main/java/org/radarbase/appserver/entity/User.java @@ -59,7 +59,6 @@ @UniqueConstraint(columnNames = {"subject_id", "fcm_token", "project_id"}) }) @Entity -@Getter @ToString public class User extends AuditModel implements Serializable { @@ -100,6 +99,38 @@ public class User extends AuditModel implements Serializable { @Column(name = "language") private String language; + public Long getId() { + return id; + } + + public String getSubjectId() { + return subjectId; + } + + public String getFcmToken() { + return fcmToken; + } + + public Project getProject() { + return project; + } + + public Instant getEnrolmentDate() { + return enrolmentDate; + } + + public UserMetrics getUsermetrics() { + return usermetrics; + } + + public String getTimezone() { + return timezone; + } + + public String getLanguage() { + return language; + } + public User setSubjectId(String subjectId) { this.subjectId = subjectId; return this; diff --git a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java index 0f051bd7..7a266369 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java @@ -145,7 +145,8 @@ public boolean checkIfDataMessageExists(FcmDataMessageDto dataMessageDto, String if (user.isEmpty()) { throw new NotFoundException(INVALID_SUBJECT_ID_MESSAGE); } - DataMessage dataMessage = new DataMessage.DataMessageBuilder(dataMessageConverter.dtoToEntity(dataMessageDto)).user(user.get()).build(); + DataMessage dataMessage = + dataMessageConverter.dtoToEntity(dataMessageDto).copy(null, user.get()); List dataMessages = this.dataMessageRepository.findByUserId(user.get().getId()); return dataMessages.contains(dataMessage); @@ -175,9 +176,9 @@ public FcmDataMessageDto addDataMessage( dataMessageDto.getScheduledTime(), dataMessageDto.getTtlSeconds())) { - DataMessage dataMessageSaved = - this.dataMessageRepository.saveAndFlush( - new DataMessage.DataMessageBuilder(dataMessageConverter.dtoToEntity(dataMessageDto)).user(user).build()); + DataMessage dataMessage = dataMessageConverter.dtoToEntity(dataMessageDto).copy(null, user); + + DataMessage dataMessageSaved = this.dataMessageRepository.saveAndFlush(dataMessage); user.getUsermetrics().setLastOpened(Instant.now()); this.userRepository.save(user); addDataMessageStateEvent( @@ -217,13 +218,12 @@ public FcmDataMessageDto updateDataMessage( throw new NotFoundException("Data message does not exist. Please create first"); } - DataMessage newDataMessage = new DataMessage.DataMessageBuilder(dataMessage.get()) - .scheduledTime(dataMessageDto.getScheduledTime()) - .sourceId(dataMessageDto.getSourceId()) - .ttlSeconds(dataMessageDto.getTtlSeconds()) - .user(user) - .fcmMessageId(String.valueOf(dataMessageDto.hashCode())) - .build(); + DataMessage newDataMessage = dataMessage.get().copy(dataMessage.get().getId(), user); + newDataMessage.setSourceId(dataMessageDto.getSourceId()); + newDataMessage.setScheduledTime(dataMessageDto.getScheduledTime()); + newDataMessage.setTtlSeconds(dataMessageDto.getTtlSeconds()); + newDataMessage.setFcmMessageId(String.valueOf(dataMessageDto.hashCode())); + DataMessage dataMessageSaved = this.dataMessageRepository.saveAndFlush(newDataMessage); addDataMessageStateEvent( dataMessageSaved, MessageState.UPDATED, dataMessageSaved.getUpdatedAt().toInstant()); @@ -251,7 +251,8 @@ public void updateDeliveryStatus(String fcmMessageId, boolean isDelivered) { dataMessage.ifPresentOrElse( (DataMessage d) -> { - DataMessage newDataMessage = new DataMessage.DataMessageBuilder(d).delivered(isDelivered).build(); + DataMessage newDataMessage = d.copy(); + newDataMessage.setDelivered(isDelivered); this.dataMessageRepository.save(newDataMessage); }, () -> { @@ -296,8 +297,8 @@ public FcmDataMessages addDataMessages( List newDataMessages = dataMessageDtos.getDataMessages().stream() .map(dataMessageConverter::dtoToEntity) - .map(d -> new DataMessage.DataMessageBuilder(d).user(user).build()) - .filter(dataMessage -> !dataMessages.contains(dataMessage)) + .map(d -> d.copy(d.getId(), user)) + .filter((DataMessage dataMessage) -> !dataMessages.contains(dataMessage)) .collect(Collectors.toList()); List savedDataMessages = this.dataMessageRepository.saveAll(newDataMessages); diff --git a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java index fe0a51b6..97313377 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java @@ -28,7 +28,6 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import org.radarbase.appserver.converter.NotificationConverter; import org.radarbase.appserver.dto.fcm.FcmNotificationDto; import org.radarbase.appserver.dto.fcm.FcmNotifications; @@ -98,7 +97,9 @@ public FcmNotifications getAllNotifications() { @Transactional(readOnly = true) public FcmNotificationDto getNotificationById(long id) { Optional notification = notificationRepository.findById(id); - return notificationConverter.entityToDto(notification.orElseGet(Notification::new)); + return notificationConverter.entityToDto(notification.orElseThrow(() -> { + throw new NotFoundException("Notification with id " + id + "not found"); + })); } @Transactional(readOnly = true) @@ -144,7 +145,9 @@ public boolean checkIfNotificationExists(FcmNotificationDto notificationDto, Str if (user.isEmpty()) { throw new NotFoundException(INVALID_SUBJECT_ID_MESSAGE); } - Notification notification = new Notification.NotificationBuilder(notificationConverter.dtoToEntity(notificationDto)).user(user.get()).build(); + + Notification notification = notificationConverter.dtoToEntity(notificationDto).copy(); + notification.setUser(user.get()); List notifications = this.notificationRepository.findByUserId(user.get().getId()); return notifications.contains(notification); @@ -180,7 +183,9 @@ public FcmNotificationDto addNotification( if (notification.isEmpty()) { Notification notificationSaved = this.notificationRepository.saveAndFlush( - new Notification.NotificationBuilder(notificationConverter.dtoToEntity(notificationDto)).user(user).build()); + notificationConverter.dtoToEntity(notificationDto) + .copy(notificationDto.getId(), user) + ); user.getUsermetrics().setLastOpened(Instant.now()); this.userRepository.save(user); addNotificationStateEvent( @@ -214,7 +219,9 @@ public FcmNotificationDto addNotification( if (notification.isEmpty()) { Notification notificationSaved = this.notificationRepository.saveAndFlush( - new Notification.NotificationBuilder(notificationConverter.dtoToEntity(notificationDto)).user(user).build()); + notificationConverter.dtoToEntity(notificationDto) + .copy(null, user) + ); user.getUsermetrics().setLastOpened(Instant.now()); this.userRepository.save(user); addNotificationStateEvent( @@ -230,7 +237,7 @@ public FcmNotificationDto addNotification( private void addNotificationStateEvent( Notification notification, MessageState state, Instant time) { - if (notificationStateEventPublisher != null) { + if (notificationStateEventPublisher!=null) { NotificationStateEventDto notificationStateEvent = new NotificationStateEventDto(this, notification, state, null, time); notificationStateEventPublisher.publishEvent(notificationStateEvent); @@ -242,7 +249,7 @@ private void addNotificationStateEvent( public FcmNotificationDto updateNotification( FcmNotificationDto notificationDto, String subjectId, String projectId) { - if (notificationDto.getId() == null) { + if (notificationDto.getId()==null) { throw new InvalidNotificationDetailsException( "ID must be supplied for updating the notification"); } @@ -256,16 +263,20 @@ public FcmNotificationDto updateNotification( throw new NotFoundException("Notification does not exist. Please create first"); } - Notification newNotification = new Notification.NotificationBuilder(notification.get()) - .body(notificationDto.getBody()) - .scheduledTime(notificationDto.getScheduledTime()) - .sourceId(notificationDto.getSourceId()) - .title(notificationDto.getTitle()) - .ttlSeconds(notificationDto.getTtlSeconds()) - .type(notificationDto.getType()) - .user(user) - .fcmMessageId(String.valueOf(notificationDto.hashCode())) - .build(); + Notification newNotification = notification.get().copy( + notification.get().getId(), + user, + notificationDto.getScheduledTime(), + notificationDto.getSourceId(), + notificationDto.getSourceType(), + notificationDto.getTtlSeconds(), + String.valueOf(notificationDto.hashCode()) + ); + newNotification.setType(notificationDto.getType()); + newNotification.setTitle(notificationDto.getTitle()); + newNotification.setBody(notificationDto.getBody()); + newNotification.setAdditionalData(notificationDto.getAdditionalData()); + Notification notificationSaved = this.notificationRepository.saveAndFlush(newNotification); addNotificationStateEvent( notificationSaved, MessageState.UPDATED, notificationSaved.getUpdatedAt().toInstant()); @@ -321,7 +332,8 @@ public void updateDeliveryStatus(String fcmMessageId, boolean isDelivered) { notification.ifPresentOrElse( (Notification n) -> { - Notification newNotif = new Notification.NotificationBuilder(n).delivered(isDelivered).build(); + Notification newNotif = n.copy(); + n.setDelivered(isDelivered); this.notificationRepository.save(newNotif); }, () -> { @@ -370,7 +382,7 @@ public FcmNotifications addNotifications( List newNotifications = notificationDtos.getNotifications().stream() .map(notificationConverter::dtoToEntity) - .map(n -> new Notification.NotificationBuilder(n).user(user).build()) + .map(n -> n.copy(n.getId(), user)) .filter(notification -> !notifications.contains(notification)) .collect(Collectors.toList()); @@ -394,7 +406,7 @@ public FcmNotifications addNotifications( List newNotifications = notificationDtos.getNotifications().stream() .map(notificationConverter::dtoToEntity) - .map(n -> new Notification.NotificationBuilder(n).user(user).build()) + .map(n -> n.copy(n.getId(), user)) .filter(notification -> !notifications.contains(notification)) .collect(Collectors.toList()); diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt b/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt index 494f7d4e..8a60efa6 100644 --- a/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt +++ b/src/main/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerService.kt @@ -51,7 +51,7 @@ class NotificationSchedulerService( private fun getNotificationMap(notification: Notification): Map { val notificationMap: MutableMap = HashMap() notificationMap["body"] = notification.body ?: "" - notificationMap["title"] = notification.title + notificationMap["title"] = notification.title ?: "Alert from RADAR-Base" notificationMap["sound"] = "default" putIfNotNull(notificationMap, "sound", notification.sound) putIfNotNull(notificationMap, "badge", notification.badge) diff --git a/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java b/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java index 491a3bdb..04fa867a 100644 --- a/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java +++ b/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java @@ -29,8 +29,6 @@ import java.time.Duration; import java.time.Instant; import javax.persistence.PersistenceException; -import javax.validation.ConstraintViolationException; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -78,15 +76,13 @@ public void initDataMessage() { this.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)); - DataMessage dataMessage = - new DataMessage.DataMessageBuilder() - .user(user) - .fcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID) - .scheduledTime(this.scheduledTime) - .sourceId(DATA_MESSAGE_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + DataMessage dataMessage = new DataMessage(); + dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); + dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); + dataMessage.setScheduledTime(this.scheduledTime); + dataMessage.setUser(this.user); + dataMessage.setTtlSeconds(86400); + dataMessage.setDelivered(false); this.id = (Long) entityManager.persistAndGetId(dataMessage); entityManager.flush(); @@ -95,15 +91,13 @@ public void initDataMessage() { @Test public void whenInsertWithTransientUser_thenThrowException() { // given - DataMessage dataMessage = - new DataMessage.DataMessageBuilder() - .user(new User()) - .fcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(DATA_MESSAGE_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + DataMessage dataMessage = new DataMessage(); + dataMessage.setUser(new User()); + dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); + dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + dataMessage.setTtlSeconds(86400); + dataMessage.setDelivered(false); + dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); IllegalStateException ex = assertThrows( @@ -119,14 +113,12 @@ public void whenInsertWithTransientUser_thenThrowException() { @Test public void whenInsertWithoutUser_thenThrowException() { // given - DataMessage dataMessage = - new DataMessage.DataMessageBuilder() - .fcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(DATA_MESSAGE_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + DataMessage dataMessage = new DataMessage(); + dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); + dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + dataMessage.setTtlSeconds(86400); + dataMessage.setDelivered(false); + dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); assertThrows( PersistenceException.class, @@ -158,15 +150,13 @@ public void whenInsertWithUserButTransientProject_thenThrowException() { assertTrue(ex.getMessage().contains("Not-null property references a transient value")); - DataMessage dataMessage = - new DataMessage.DataMessageBuilder() - .user(user) - .fcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(DATA_MESSAGE_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + DataMessage dataMessage = new DataMessage(); + dataMessage.setUser(user); + dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); + dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + dataMessage.setTtlSeconds(86400); + dataMessage.setDelivered(false); + dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); ex = assertThrows( diff --git a/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java b/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java index 7d7d7ce0..6e59fb00 100644 --- a/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java +++ b/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java @@ -29,7 +29,6 @@ import java.time.Duration; import java.time.Instant; import javax.persistence.PersistenceException; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -79,17 +78,15 @@ public void initNotification() { this.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)); - Notification notification = - new Notification.NotificationBuilder() - .user(user) - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE) - .fcmMessageId(NOTIFICATION_FCM_MESSAGE_ID) - .scheduledTime(this.scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + Notification notification = new Notification(); + notification.setBody(NOTIFICATION_BODY); + notification.setTitle(NOTIFICATION_TITLE); + notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); + notification.setSourceId(NOTIFICATION_SOURCE_ID); + notification.setScheduledTime(this.scheduledTime); + notification.setUser(this.user); + notification.setTtlSeconds(86400); + notification.setDelivered(false); this.id = (Long) entityManager.persistAndGetId(notification); entityManager.flush(); @@ -98,17 +95,17 @@ public void initNotification() { @Test public void whenInsertWithTransientUser_thenThrowException() { // given - Notification notification = - new Notification.NotificationBuilder() - .user(new User()) - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE) - .fcmMessageId(NOTIFICATION_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(NOTIFICATION_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + Notification notification = new Notification(); + notification.setBody(NOTIFICATION_BODY); + notification.setTitle(NOTIFICATION_TITLE); + notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); + notification.setSourceId(NOTIFICATION_SOURCE_ID); + notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + notification.setUser(new User()); + notification.setTtlSeconds(86400); + notification.setDelivered(false); + + IllegalStateException ex = assertThrows( @@ -124,16 +121,14 @@ public void whenInsertWithTransientUser_thenThrowException() { @Test public void whenInsertWithoutUser_thenThrowException() { // given - Notification notification = - new Notification.NotificationBuilder() - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE) - .fcmMessageId(NOTIFICATION_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(NOTIFICATION_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + Notification notification = new Notification(); + notification.setBody(NOTIFICATION_BODY); + notification.setTitle(NOTIFICATION_TITLE); + notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); + notification.setSourceId(NOTIFICATION_SOURCE_ID); + notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + notification.setTtlSeconds(86400); + notification.setDelivered(false); assertThrows( PersistenceException.class, @@ -165,17 +160,15 @@ public void whenInsertWithUserButTransientProject_thenThrowException() { assertTrue(ex.getMessage().contains("Not-null property references a transient value")); - Notification notification = - new Notification.NotificationBuilder() - .user(user) - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE) - .fcmMessageId(NOTIFICATION_FCM_MESSAGE_ID) - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .sourceId(NOTIFICATION_SOURCE_ID) - .ttlSeconds(86400) - .delivered(false) - .build(); + Notification notification = new Notification(); + notification.setBody(NOTIFICATION_BODY); + notification.setTitle(NOTIFICATION_TITLE); + notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); + notification.setSourceId(NOTIFICATION_SOURCE_ID); + notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); + notification.setUser(user); + notification.setTtlSeconds(86400); + notification.setDelivered(false); ex = assertThrows( diff --git a/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java b/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java index 089812ac..53a99db6 100644 --- a/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java @@ -112,18 +112,15 @@ void setUp() { Mockito.when(userRepository.save(Mockito.any())).thenReturn(userNew); - Notification notification3 = - new Notification.NotificationBuilder() - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE_3) - .scheduledTime(scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .fcmMessageId("1234567") - .ttlSeconds(86400) - .delivered(false) - .user(user) - .id(3L) - .build(); + Notification notification3 = new Notification(); + notification3.setUser(user); + notification3.setId(3L); + notification3.setTitle(NOTIFICATION_TITLE_3); + notification3.setScheduledTime(scheduledTime); + notification3.setSourceId(NOTIFICATION_SOURCE_ID); + notification3.setFcmMessageId("1234567"); + notification3.setTtlSeconds(86400); + notification3.setCreatedAt(new Date()); Mockito.when(notificationRepository.save(notification3)).thenReturn(notification3); @@ -143,18 +140,15 @@ void setUp() { 86400)) .thenReturn(false); - Notification notification4 = - new Notification.NotificationBuilder() - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE_4) - .scheduledTime(scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .fcmMessageId("12345678") - .ttlSeconds(86400) - .delivered(false) - .user(userNew) - .id(4L) - .build(); + Notification notification4 = new Notification(); + notification4.setId(4L); + notification4.setUser(userNew); + notification4.setSourceId(NOTIFICATION_SOURCE_ID); + notification4.setScheduledTime(scheduledTime); + notification4.setTitle(NOTIFICATION_TITLE_4); + notification4.setBody(NOTIFICATION_BODY); + notification4.setFcmMessageId("12345678"); + notification4.setTtlSeconds(86400); notification4.setCreatedAt(new Date()); notification4.setUpdatedAt(new Date()); @@ -175,18 +169,16 @@ void setUp() { 86400)) .thenReturn(false); - Notification notification5 = - new Notification.NotificationBuilder() - .body(NOTIFICATION_BODY + " Updated") - .title("Testing 2 Updated") - .user(user) - .scheduledTime(scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .fcmMessageId(FCM_MESSAGE_ID) - .ttlSeconds(86400) - .delivered(false) - .id(5L) - .build(); + Notification notification5 = new Notification(); + notification5.setId(5L); + notification5.setUser(user); + notification5.setSourceId(NOTIFICATION_SOURCE_ID); + notification5.setScheduledTime(scheduledTime); + notification5.setTitle("Testing 2 Updated"); + notification5.setBody(NOTIFICATION_BODY + " Updated"); + notification5.setDelivered(false); + notification5.setFcmMessageId(FCM_MESSAGE_ID); + notification5.setCreatedAt(new Date()); notification5.setUpdatedAt(new Date()); @@ -224,33 +216,28 @@ private void setUpProjectAndUser() { } private void setUpNotification1And2() { - Notification notification1 = - new Notification.NotificationBuilder() - .user(user) - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE) - .scheduledTime(scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .fcmMessageId(NOTIFICATION_FCM_MESSAGE_ID) - .ttlSeconds(86400) - .delivered(false) - .id(1L) - .build(); + Notification notification1 = new Notification(); + notification1.setId(1L); + notification1.setUser(user); + notification1.setSourceId(NOTIFICATION_SOURCE_ID); + notification1.setScheduledTime(scheduledTime); + notification1.setTitle(NOTIFICATION_TITLE); + notification1.setBody(NOTIFICATION_BODY); + notification1.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); + notification1.setTtlSeconds(86400); + notification1.setUpdatedAt(new Date()); notification1.setCreatedAt(new Date()); - Notification notification2 = - new Notification.NotificationBuilder() - .user(user) - .body(NOTIFICATION_BODY) - .title(NOTIFICATION_TITLE_2) - .scheduledTime(scheduledTime) - .sourceId(NOTIFICATION_SOURCE_ID) - .fcmMessageId(FCM_MESSAGE_ID) - .ttlSeconds(86400) - .delivered(false) - .id(2L) - .build(); + Notification notification2 = new Notification(); + notification2.setId(2L); + notification2.setUser(user); + notification2.setSourceId(NOTIFICATION_SOURCE_ID); + notification2.setScheduledTime(scheduledTime); + notification2.setTitle(NOTIFICATION_TITLE_2); + notification2.setBody(NOTIFICATION_BODY); + notification2.setFcmMessageId(FCM_MESSAGE_ID); + notification2.setTtlSeconds(86400); notification2.setCreatedAt(new Date()); notification2.setUpdatedAt(new Date()); diff --git a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java index 5c6225ab..db3dec8a 100644 --- a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java @@ -96,20 +96,17 @@ void setUp() throws SchedulerException { .setEnrolmentDate(Instant.now()) .setFcmToken("xxxx"); - notification = - new Notification.NotificationBuilder() - .delivered(false) - .ttlSeconds(900) - .sourceId("aRMT") - .scheduledTime(Instant.now().plus(Duration.ofSeconds(3))) - .fcmMessageId("xxxx") - .title("Testing") - .body("Testing") - .user(user) - .type("ESM") - .appPackage("aRMT") - .id(1L) - .build(); + notification = new Notification(); + notification.setId(1L); + notification.setUser(user); + notification.setSourceId("aRMT"); + notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(3))); + notification.setTtlSeconds(900); + notification.setFcmMessageId("xxxx"); + notification.setAppPackage("aRMT"); + notification.setTitle("Testing"); + notification.setBody("Testing"); + notification.setType("ESM"); } @Test @@ -144,13 +141,12 @@ void updateScheduledNotification() throws SchedulerException { NotificationSchedulerService.getTriggerForMessage(notification, jobDetail.getObject()); scheduler.scheduleJob(jobDetail.getObject(), triggerFactoryBean.getObject()); - Notification notification2 = - new Notification.NotificationBuilder(notification) - .fcmMessageId("yyyy") - .body("New body") - .title("New Title") - .scheduledTime(Instant.now().plus(Duration.ofSeconds(100))) - .build(); + Notification notification2 = notification.copy(); + notification2.setScheduledTime(Instant.now().plus(Duration.ofSeconds(3))); + notification2.setTtlSeconds(900); + notification2.setFcmMessageId("yyyy"); + notification2.setTitle("Testing"); + notification2.setBody("Testing"); // when notificationSchedulerService.updateScheduled(notification2); From 3b70cef5ac7fef30fe38ffecb10172b0f7bb8510 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Thu, 14 Apr 2022 19:24:20 +0100 Subject: [PATCH 05/11] Rename .java to .kt --- .../{AppserverApplication.java => AppserverApplication.kt} | 0 .../config/{ApplicationConfig.java => ApplicationConfig.kt} | 0 .../radarbase/appserver/entity/{AuditModel.java => AuditModel.kt} | 0 .../entity/{MessageStateEvent.java => MessageStateEvent.kt} | 0 .../{DataMessageRepository.java => DataMessageRepository.kt} | 0 ...ateEventRepository.java => DataMessageStateEventRepository.kt} | 0 .../{NotificationRepository.java => NotificationRepository.kt} | 0 ...teEventRepository.java => NotificationStateEventRepository.kt} | 0 .../repository/{ProjectRepository.java => ProjectRepository.kt} | 0 .../repository/{UserRepository.java => UserRepository.kt} | 0 ...ataMessageRepositoryTest.java => DataMessageRepositoryTest.kt} | 0 ...ificationRepositoryTest.java => NotificationRepositoryTest.kt} | 0 .../repository/{UserRepositoryTest.java => UserRepositoryTest.kt} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/appserver/{AppserverApplication.java => AppserverApplication.kt} (100%) rename src/main/java/org/radarbase/appserver/config/{ApplicationConfig.java => ApplicationConfig.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{AuditModel.java => AuditModel.kt} (100%) rename src/main/java/org/radarbase/appserver/entity/{MessageStateEvent.java => MessageStateEvent.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{DataMessageRepository.java => DataMessageRepository.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{DataMessageStateEventRepository.java => DataMessageStateEventRepository.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{NotificationRepository.java => NotificationRepository.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{NotificationStateEventRepository.java => NotificationStateEventRepository.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{ProjectRepository.java => ProjectRepository.kt} (100%) rename src/main/java/org/radarbase/appserver/repository/{UserRepository.java => UserRepository.kt} (100%) rename src/test/java/org/radarbase/appserver/repository/{DataMessageRepositoryTest.java => DataMessageRepositoryTest.kt} (100%) rename src/test/java/org/radarbase/appserver/repository/{NotificationRepositoryTest.java => NotificationRepositoryTest.kt} (100%) rename src/test/java/org/radarbase/appserver/repository/{UserRepositoryTest.java => UserRepositoryTest.kt} (100%) diff --git a/src/main/java/org/radarbase/appserver/AppserverApplication.java b/src/main/java/org/radarbase/appserver/AppserverApplication.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/AppserverApplication.java rename to src/main/java/org/radarbase/appserver/AppserverApplication.kt diff --git a/src/main/java/org/radarbase/appserver/config/ApplicationConfig.java b/src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/config/ApplicationConfig.java rename to src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt diff --git a/src/main/java/org/radarbase/appserver/entity/AuditModel.java b/src/main/java/org/radarbase/appserver/entity/AuditModel.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/AuditModel.java rename to src/main/java/org/radarbase/appserver/entity/AuditModel.kt diff --git a/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.java b/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/entity/MessageStateEvent.java rename to src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt diff --git a/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.java b/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/DataMessageRepository.java rename to src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt diff --git a/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.java b/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.java rename to src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt diff --git a/src/main/java/org/radarbase/appserver/repository/NotificationRepository.java b/src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/NotificationRepository.java rename to src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt diff --git a/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.java b/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.java rename to src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt diff --git a/src/main/java/org/radarbase/appserver/repository/ProjectRepository.java b/src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/ProjectRepository.java rename to src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt diff --git a/src/main/java/org/radarbase/appserver/repository/UserRepository.java b/src/main/java/org/radarbase/appserver/repository/UserRepository.kt similarity index 100% rename from src/main/java/org/radarbase/appserver/repository/UserRepository.java rename to src/main/java/org/radarbase/appserver/repository/UserRepository.kt diff --git a/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java b/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt similarity index 100% rename from src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.java rename to src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt diff --git a/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java b/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt similarity index 100% rename from src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.java rename to src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt diff --git a/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.java b/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt similarity index 100% rename from src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.java rename to src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt From 3855f68cb1d8835c227c142b5ae3481738186662 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Thu, 14 Apr 2022 19:24:22 +0100 Subject: [PATCH 06/11] convert further classes to kt and fix tests - Adds kotlin annotation processing - More idiomatic kt in some places --- build.gradle | 30 +- .../appserver/AppserverApplication.kt | 29 +- .../appserver/config/ApplicationConfig.kt | 22 +- .../appserver/converter/Converter.kt | 9 +- .../appserver/converter/ProjectConverter.kt | 4 +- .../appserver/converter/UserConverter.kt | 2 +- .../radarbase/appserver/entity/AuditModel.kt | 67 ++-- .../radarbase/appserver/entity/DataMessage.kt | 10 +- .../entity/DataMessageStateEvent.java | 67 ---- .../appserver/entity/DataMessageStateEvent.kt | 41 +++ .../org/radarbase/appserver/entity/Message.kt | 2 +- .../appserver/entity/MessageStateEvent.kt | 56 +--- .../appserver/entity/Notification.kt | 10 +- .../entity/NotificationStateEvent.java | 67 ---- .../entity/NotificationStateEvent.kt | 41 +++ .../org/radarbase/appserver/entity/User.java | 3 +- .../appserver/entity/UserMetrics.java | 25 +- .../state/MessageStateEventListener.java | 16 +- .../repository/DataMessageRepository.kt | 54 ++- .../DataMessageStateEventRepository.kt | 23 +- .../repository/NotificationRepository.kt | 83 +++-- .../NotificationStateEventRepository.kt | 23 +- .../appserver/repository/ProjectRepository.kt | 26 +- .../appserver/repository/UserRepository.kt | 38 +-- .../service/FcmDataMessageService.java | 7 +- .../service/FcmNotificationService.java | 9 +- .../appserver/service/UserService.java | 2 +- .../scheduler/DataMessageSchedulerService.kt | 8 +- .../org/radarbase/fcm/model/FcmDataMessage.kt | 38 ++- .../fcm/model/FcmDownstreamMessage.kt | 2 +- .../fcm/model/FcmNotificationMessage.kt | 56 ++-- .../repository/DataMessageRepositoryTest.kt | 285 ++++++++-------- .../repository/NotificationRepositoryTest.kt | 317 +++++++++--------- .../repository/UserRepositoryTest.kt | 202 ++++++----- .../service/FcmNotificationServiceTest.java | 104 +++--- .../appserver/service/UserServiceTest.java | 4 +- .../NotificationSchedulerServiceTest.java | 9 +- 37 files changed, 850 insertions(+), 941 deletions(-) delete mode 100644 src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.java create mode 100644 src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.kt delete mode 100644 src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.java create mode 100644 src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.kt diff --git a/build.gradle b/build.gradle index 4d3a216f..08f5e184 100644 --- a/build.gradle +++ b/build.gradle @@ -1,20 +1,12 @@ -buildscript { - ext.kotlin_version = '1.6.20' - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} plugins { id 'pmd' id "com.github.lkishalmi.gatling" version "3.3.4" id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.springframework.boot' version "2.6.6" id "org.jetbrains.kotlin.plugin.spring" version "1.6.20" - id "org.jetbrains.kotlin.plugin.allopen" version "1.6.20" id "org.jetbrains.kotlin.plugin.jpa" version "1.6.20" + id "org.jetbrains.kotlin.jvm" version "1.6.20" + id "org.jetbrains.kotlin.kapt" version "1.6.20" } apply plugin: 'checkstyle' @@ -62,6 +54,10 @@ sourceSets { } } +kapt { + keepJavacAnnotationProcessors = true +} + allOpen { annotation("javax.persistence.Entity") annotation("javax.persistence.Embeddable") @@ -82,6 +78,10 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + kapt("org.springframework.boot:spring-boot-configuration-processor") + kapt("org.springframework:spring-context-indexer:5.3.18") + kapt("org.projectlombok:lombok:" + lombokVersion) + implementation group: 'com.pivovarit', name: 'throwing-function', version: throwingFunctionVersion implementation(group: 'de.codecentric', name: 'spring-boot-admin-starter-client', version: bootAdminVersion) @@ -120,7 +120,9 @@ dependencies { testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit', module: 'junit' + //exclude group: 'org.mockito', module: 'mockito-core' } + //testImplementation("com.ninja-squad:springmockk:3.1.1") testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: junit5Version testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit5Version @@ -140,6 +142,10 @@ checkstyle { sourceSets = [it.sourceSets.main] } +pmd { + toolVersion = "6.44.0" +} + javadoc { options.addBooleanOption('html5', true) destinationDir = new File("${project.rootDir}/src/main/resources/static/java-docs".toString()) @@ -211,11 +217,11 @@ test { } compileKotlin { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } } compileTestKotlin { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } } diff --git a/src/main/java/org/radarbase/appserver/AppserverApplication.kt b/src/main/java/org/radarbase/appserver/AppserverApplication.kt index cb893625..2e29b209 100644 --- a/src/main/java/org/radarbase/appserver/AppserverApplication.kt +++ b/src/main/java/org/radarbase/appserver/AppserverApplication.kt @@ -18,20 +18,23 @@ * * * */ +package org.radarbase.appserver -package org.radarbase.appserver; +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration +import org.springframework.boot.runApplication -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @SpringBootApplication( - exclude = {SolrAutoConfiguration.class}, - scanBasePackages = {"org.radarbase.appserver", "org.radarbase.fcm"}) -public class AppserverApplication { + exclude = [SolrAutoConfiguration::class], + scanBasePackages = [ + "org.radarbase.appserver", + "org.radarbase.fcm", + ], +) +class AppserverApplication - public static void main(String[] args) { - SpringApplication.run(AppserverApplication.class, args); - } -} +fun main(args: Array) { + runApplication(*args) +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt b/src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt index 06a4077d..c143ca1a 100644 --- a/src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt +++ b/src/main/java/org/radarbase/appserver/config/ApplicationConfig.kt @@ -18,20 +18,20 @@ * * * */ +package org.radarbase.appserver.config -package org.radarbase.appserver.config; - -import org.radarbase.fcm.config.FcmServerConfig; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.radarbase.fcm.config.FcmServerConfig +import org.springframework.context.annotation.Configuration +import org.springframework.transaction.annotation.EnableTransactionManagement +import org.springframework.scheduling.annotation.EnableAsync @Configuration @EnableJpaAuditing -@EnableConfigurationProperties({FcmServerConfig.class}) +@EnableConfigurationProperties( + FcmServerConfig::class +) @EnableTransactionManagement @EnableAsync -public class ApplicationConfig { -} +class ApplicationConfig \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/Converter.kt b/src/main/java/org/radarbase/appserver/converter/Converter.kt index 122960b3..699d0c0c 100644 --- a/src/main/java/org/radarbase/appserver/converter/Converter.kt +++ b/src/main/java/org/radarbase/appserver/converter/Converter.kt @@ -20,7 +20,6 @@ */ package org.radarbase.appserver.converter -import java.util.stream.Collectors /** * Generic converter class for conversions between entity [org.radarbase.appserver.entity] and @@ -36,11 +35,11 @@ interface Converter { fun dtoToEntity(s: S): T fun entityToDto(t: T): S - fun dtosToEntities(ss: Collection): List { - return ss.parallelStream().map { s: S -> dtoToEntity(s) }.collect(Collectors.toList()) + fun dtosToEntities(ss: MutableCollection): MutableList { + return ss.map { s: S -> dtoToEntity(s) }.toMutableList() } - fun entitiesToDtos(ts: Collection): List { - return ts.parallelStream().map { t: T -> entityToDto(t) }.collect(Collectors.toList()) + fun entitiesToDtos(ts: MutableCollection): MutableList { + return ts.map { t: T -> entityToDto(t) }.toMutableList() } } \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt b/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt index b0536b0d..b29b77eb 100644 --- a/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/ProjectConverter.kt @@ -42,7 +42,7 @@ class ProjectConverter : Converter { return ProjectDto() .setId(project.id) .setProjectId(project.projectId) - .setCreatedAt(project.createdAt.toInstant()) - .setUpdatedAt(project.updatedAt.toInstant()) + .setCreatedAt(project.createdAt?.toInstant()) + .setUpdatedAt(project.updatedAt?.toInstant()) } } \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/converter/UserConverter.kt b/src/main/java/org/radarbase/appserver/converter/UserConverter.kt index 95bd584c..a06f2cb4 100644 --- a/src/main/java/org/radarbase/appserver/converter/UserConverter.kt +++ b/src/main/java/org/radarbase/appserver/converter/UserConverter.kt @@ -41,7 +41,7 @@ class UserConverter : Converter { return User() .setFcmToken(fcmUserDto.fcmToken) .setSubjectId(fcmUserDto.subjectId) - .setUserMetrics(getValidUserMetrics(fcmUserDto)) + .setUsermetrics(getValidUserMetrics(fcmUserDto)) .setEnrolmentDate(fcmUserDto.enrolmentDate) .setTimezone(fcmUserDto.timezone) .setLanguage(fcmUserDto.language) diff --git a/src/main/java/org/radarbase/appserver/entity/AuditModel.kt b/src/main/java/org/radarbase/appserver/entity/AuditModel.kt index 402f7c5b..faa8efaf 100644 --- a/src/main/java/org/radarbase/appserver/entity/AuditModel.kt +++ b/src/main/java/org/radarbase/appserver/entity/AuditModel.kt @@ -18,58 +18,35 @@ * * * */ +package org.radarbase.appserver.entity -package org.radarbase.appserver.entity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import lombok.Data; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import org.springframework.data.annotation.CreatedDate +import org.springframework.data.annotation.LastModifiedDate +import org.springframework.data.jpa.domain.support.AuditingEntityListener +import java.util.* +import javax.persistence.* /** * Enables Auditing on various JPA entities. This automatically adds and updates the `create at` and * `updated at` attributes for any entity that extends this class. * * @see AuditingEntityListener + * * @author yatharthranjan */ @MappedSuperclass -@EntityListeners(AuditingEntityListener.class) -@JsonIgnoreProperties( - value = {"createdAt", "updatedAt"}, - allowGetters = true) -@Data -public abstract class AuditModel { - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "created_at", nullable = false, updatable = false) - @CreatedDate - private Date createdAt; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "updated_at", nullable = false) - @LastModifiedDate - private Date updatedAt; - - public Date getCreatedAt() { - return createdAt; - } - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } -} +@EntityListeners(AuditingEntityListener::class) +@JsonIgnoreProperties(value = ["createdAt", "updatedAt"], allowGetters = true) +abstract class AuditModel { + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_at", nullable = false, updatable = false) + @CreatedDate + var createdAt: Date? = null + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updated_at", nullable = false) + @LastModifiedDate + var updatedAt: Date? = null + +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt index d6a6f303..0fc58c83 100644 --- a/src/main/java/org/radarbase/appserver/entity/DataMessage.kt +++ b/src/main/java/org/radarbase/appserver/entity/DataMessage.kt @@ -20,7 +20,6 @@ */ package org.radarbase.appserver.entity -import org.springframework.lang.Nullable import java.time.Instant import java.util.* import javax.persistence.* @@ -43,12 +42,11 @@ import javax.persistence.* @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) class DataMessage : Message() { - @Nullable @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "data_message_map") @MapKeyColumn(name = "key", nullable = true) @Column(name = "value") - var dataMap: Map? = null + var dataMap: Map? = null override fun equals(other: Any?): Boolean { if (this === other) { @@ -74,7 +72,7 @@ class DataMessage : Message() { sourceId: String? = this.sourceId, sourceType: String? = this.sourceType, ttlSeconds: Int = this.ttlSeconds, - fcmMessageId: String? = this.fcmMessageId, + fcmMessageId: String = this.fcmMessageId, fcmTopic: String? = this.fcmTopic, fcmCondition: String? = this.fcmCondition, appPackage: String? = this.appPackage, @@ -83,8 +81,6 @@ class DataMessage : Message() { validated: Boolean = this.validated, priority: String? = this.priority, mutableContent: Boolean = this.mutableContent, - createdAt: Date = this.createdAt, - updatedAt: Date = this.updatedAt, ): DataMessage { return DataMessage().apply { this.id = id @@ -102,8 +98,6 @@ class DataMessage : Message() { this.validated = validated this.priority = priority this.mutableContent = mutableContent - this.createdAt = createdAt - this.updatedAt = updatedAt } } diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.java b/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.java deleted file mode 100644 index 2bac04a0..00000000 --- a/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * * - * * * Copyright 2018 King's College London - * * * - * * * 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.radarbase.appserver.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import java.time.Instant; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; -import org.radarbase.appserver.event.state.MessageState; - -@Entity -@Getter -@Table(name = "data_message_state_events") -@NoArgsConstructor -public class DataMessageStateEvent extends MessageStateEvent { - private static final long serialVersionUID = 876253616328520L; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @NotNull - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "data_message_id", nullable = false) - @OnDelete(action = OnDeleteAction.CASCADE) - @JsonIgnore - private DataMessage dataMessage; - - public DataMessageStateEvent( - @NotNull DataMessage dataMessage, - @NotNull MessageState state, - @NotNull Instant time, - String associatedInfo) { - super(state, time, associatedInfo); - this.dataMessage = dataMessage; - } -} diff --git a/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.kt b/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.kt new file mode 100644 index 00000000..ccd7b912 --- /dev/null +++ b/src/main/java/org/radarbase/appserver/entity/DataMessageStateEvent.kt @@ -0,0 +1,41 @@ +/* + * + * * + * * * Copyright 2018 King's College London + * * * + * * * 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.radarbase.appserver.entity + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.OnDelete +import org.hibernate.annotations.OnDeleteAction +import javax.persistence.* + +@Entity +@Table(name = "data_message_state_events") +class DataMessageStateEvent : MessageStateEvent() { + + @field:JsonIgnore + @field:OnDelete(action = OnDeleteAction.CASCADE) + @field:JoinColumn(name = "data_message_id", nullable = false) + @field:ManyToOne(fetch = FetchType.EAGER, optional = false) + lateinit var dataMessage: DataMessage + + companion object { + private const val serialVersionUID = 876253616328520L + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/Message.kt b/src/main/java/org/radarbase/appserver/entity/Message.kt index 32fb24a6..f8408aad 100644 --- a/src/main/java/org/radarbase/appserver/entity/Message.kt +++ b/src/main/java/org/radarbase/appserver/entity/Message.kt @@ -53,7 +53,7 @@ abstract class Message : AuditModel(), Serializable, Scheduled { var ttlSeconds: Int = 0 @Column(name = "fcm_message_id", unique = true) - var fcmMessageId: String? = null + lateinit var fcmMessageId: String // for use with the FCM admin SDK @Column(name = "fcm_topic") diff --git a/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt b/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt index 83814b58..903c54eb 100644 --- a/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt +++ b/src/main/java/org/radarbase/appserver/entity/MessageStateEvent.kt @@ -18,51 +18,31 @@ * * * */ +package org.radarbase.appserver.entity -package org.radarbase.appserver.entity; - -import java.io.Serializable; -import java.time.Instant; -import javax.persistence.Column; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.MappedSuperclass; -import javax.validation.constraints.NotNull; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.radarbase.appserver.event.state.MessageState; +import org.radarbase.appserver.event.state.MessageState +import java.io.Serializable +import java.time.Instant +import javax.persistence.* +import javax.validation.constraints.NotNull @MappedSuperclass -@Getter -@NoArgsConstructor -public abstract class MessageStateEvent implements Serializable { - private static final long serialVersionUID = 876253616328519L; - +abstract class MessageStateEvent : Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; + var id: Long? = null - @NotNull - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private MessageState state; + @field:Column(nullable = false) + @field:Enumerated(EnumType.STRING) + lateinit var state: MessageState - @NotNull - @Column(nullable = false) - private Instant time; + @field:Column(nullable = false) + lateinit var time: @NotNull Instant - @Column(name = "associated_info", length = 1250) - private String associatedInfo; + @field:Column(name = "associated_info", length = 1250) + var associatedInfo: String? = null - public MessageStateEvent( - @NotNull MessageState state, - @NotNull Instant time, - String associatedInfo) { - this.state = state; - this.time = time; - this.associatedInfo = associatedInfo; + companion object { + private const val serialVersionUID = 876253616328519L } -} +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/Notification.kt b/src/main/java/org/radarbase/appserver/entity/Notification.kt index 4319ad4e..30c191d3 100644 --- a/src/main/java/org/radarbase/appserver/entity/Notification.kt +++ b/src/main/java/org/radarbase/appserver/entity/Notification.kt @@ -43,7 +43,7 @@ import javax.persistence.* class Notification : Message() { @Column(nullable = false) - var title: String? = null + lateinit var title: String var body: String? = null // Type of notification. In terms of aRMT - PHQ8, RSES, ESM, etc. @@ -121,11 +121,11 @@ class Notification : Message() { sourceId: String? = this.sourceId, sourceType: String? = this.sourceType, ttlSeconds: Int = this.ttlSeconds, - fcmMessageId: String? = this.fcmMessageId, + fcmMessageId: String = this.fcmMessageId, fcmTopic: String? = this.fcmTopic, fcmCondition: String? = this.fcmCondition, appPackage: String? = this.appPackage, - title: String? = this.title, + title: String = this.title, body: String? = this.body, type: String? = this.type, sound: String? = this.sound, @@ -146,8 +146,6 @@ class Notification : Message() { validated: Boolean = this.validated, priority: String? = this.priority, mutableContent: Boolean = this.mutableContent, - createdAt: Date = this.createdAt, - updatedAt: Date = this.updatedAt, ): Notification { return Notification().apply { this.id = id @@ -181,8 +179,6 @@ class Notification : Message() { this.validated = validated this.priority = priority this.mutableContent = mutableContent - this.createdAt = createdAt - this.updatedAt = updatedAt } } diff --git a/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.java b/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.java deleted file mode 100644 index f1ac6e31..00000000 --- a/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * * - * * * Copyright 2018 King's College London - * * * - * * * 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.radarbase.appserver.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import java.time.Instant; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; -import org.radarbase.appserver.event.state.MessageState; - -@Entity -@Getter -@Table(name = "notification_state_events") -@NoArgsConstructor -public class NotificationStateEvent extends MessageStateEvent { - private static final long serialVersionUID = 876253616328518L; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @NotNull - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "notification_id", nullable = false) - @OnDelete(action = OnDeleteAction.CASCADE) - @JsonIgnore - private Notification notification; - - public NotificationStateEvent( - @NotNull Notification notification, - @NotNull MessageState state, - @NotNull Instant time, - String associatedInfo) { - super(state, time, associatedInfo); - this.notification = notification; - } -} diff --git a/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.kt b/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.kt new file mode 100644 index 00000000..716471da --- /dev/null +++ b/src/main/java/org/radarbase/appserver/entity/NotificationStateEvent.kt @@ -0,0 +1,41 @@ +/* + * + * * + * * * Copyright 2018 King's College London + * * * + * * * 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.radarbase.appserver.entity + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.OnDelete +import org.hibernate.annotations.OnDeleteAction +import javax.persistence.* + +@Entity +@Table(name = "notification_state_events") +class NotificationStateEvent : MessageStateEvent() { + + @field:JsonIgnore + @field:OnDelete(action = OnDeleteAction.CASCADE) + @field:JoinColumn(name = "notification_id", nullable = false) + @field:ManyToOne(fetch = FetchType.EAGER, optional = false) + lateinit var notification: Notification + + companion object { + private const val serialVersionUID = 876253616328518L + } +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/entity/User.java b/src/main/java/org/radarbase/appserver/entity/User.java index 648406ea..3ce2f1bc 100644 --- a/src/main/java/org/radarbase/appserver/entity/User.java +++ b/src/main/java/org/radarbase/appserver/entity/User.java @@ -41,7 +41,6 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import lombok.Getter; import lombok.ToString; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; @@ -151,7 +150,7 @@ public User setEnrolmentDate(Instant enrolmentDate) { return this; } - public User setUserMetrics(UserMetrics userMetrics) { + public User setUsermetrics(UserMetrics userMetrics) { this.usermetrics = userMetrics; return this; } diff --git a/src/main/java/org/radarbase/appserver/entity/UserMetrics.java b/src/main/java/org/radarbase/appserver/entity/UserMetrics.java index c9ac53d7..5e9bba83 100644 --- a/src/main/java/org/radarbase/appserver/entity/UserMetrics.java +++ b/src/main/java/org/radarbase/appserver/entity/UserMetrics.java @@ -44,7 +44,6 @@ */ @Table(name = "user_metrics") @Entity -@Getter @ToString public class UserMetrics extends AuditModel implements Serializable { @@ -52,7 +51,6 @@ public class UserMetrics extends AuditModel implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) - @Setter private Long id; // The most recent time when the app was opened @@ -88,4 +86,27 @@ public UserMetrics setUser(User user) { this.user = user; return this; } + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + @Nullable + public Instant getLastOpened() { + return lastOpened; + } + + @Nullable + public Instant getLastDelivered() { + return lastDelivered; + } + + @NonNull + public User getUser() { + return user; + } } diff --git a/src/main/java/org/radarbase/appserver/event/state/MessageStateEventListener.java b/src/main/java/org/radarbase/appserver/event/state/MessageStateEventListener.java index 9fee4f0a..10c2e1fc 100644 --- a/src/main/java/org/radarbase/appserver/event/state/MessageStateEventListener.java +++ b/src/main/java/org/radarbase/appserver/event/state/MessageStateEventListener.java @@ -60,8 +60,11 @@ public void onNotificationStateChange(NotificationStateEventDto event) { String info = convertMapToString(event.getAdditionalInfo()); log.debug("ID: {}, STATE: {}", event.getNotification().getId(), event.getState()); org.radarbase.appserver.entity.NotificationStateEvent eventEntity = - new org.radarbase.appserver.entity.NotificationStateEvent( - event.getNotification(), event.getState(), event.getTime(), info); + new org.radarbase.appserver.entity.NotificationStateEvent(); + eventEntity.setNotification(event.getNotification()); + eventEntity.setState(event.getState()); + eventEntity.setTime(event.getTime()); + eventEntity.setAssociatedInfo(info); notificationStateEventService.addNotificationStateEvent(eventEntity); } @@ -70,14 +73,17 @@ public void onDataMessageStateChange(DataMessageStateEventDto event) { String info = convertMapToString(event.getAdditionalInfo()); log.debug("ID: {}, STATE: {}", event.getDataMessage().getId(), event.getState()); org.radarbase.appserver.entity.DataMessageStateEvent eventEntity = - new org.radarbase.appserver.entity.DataMessageStateEvent( - event.getDataMessage(), event.getState(), event.getTime(), info); + new org.radarbase.appserver.entity.DataMessageStateEvent(); + eventEntity.setDataMessage(event.getDataMessage()); + eventEntity.setState(event.getState()); + eventEntity.setTime(event.getTime()); + eventEntity.setAssociatedInfo(info); dataMessageStateEventService.addDataMessageStateEvent(eventEntity); } public String convertMapToString(Map additionalInfoMap) { String info = null; - if (additionalInfoMap != null) { + if (additionalInfoMap!=null) { try { info = objectMapper.writeValueAsString(additionalInfoMap); } catch (JsonProcessingException exc) { diff --git a/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt b/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt index 376aab38..991b0d7b 100644 --- a/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/DataMessageRepository.kt @@ -18,41 +18,33 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; - -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import org.radarbase.appserver.entity.DataMessage; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; +import org.radarbase.appserver.entity.DataMessage +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository +import java.time.Instant +import java.util.* /** * @author yatharthranjan */ @Repository @RepositoryRestResource(exported = false) -public interface DataMessageRepository extends JpaRepository { - - List findByUserId(Long userId); - - void deleteByUserId(Long userId); - - boolean existsByUserIdAndSourceIdAndScheduledTimeAndTtlSeconds( - Long userId, - String sourceId, - Instant scheduledTime, - int ttlSeconds); - - boolean existsByIdAndUserId(Long id, Long userId); - - void deleteByFcmMessageId(String fcmMessageId); - - void deleteByIdAndUserId(Long id, Long userId); - - Optional findByFcmMessageId(String fcmMessageId); - - Optional findByIdAndUserId(long id, long userId); -} +interface DataMessageRepository : JpaRepository { + fun findByUserId(userId: Long?): List? + fun deleteByUserId(userId: Long?) + fun existsByUserIdAndSourceIdAndScheduledTimeAndTtlSeconds( + userId: Long?, + sourceId: String?, + scheduledTime: Instant?, + ttlSeconds: Int + ): Boolean + + fun existsByIdAndUserId(id: Long?, userId: Long?): Boolean + fun deleteByFcmMessageId(fcmMessageId: String?) + fun deleteByIdAndUserId(id: Long?, userId: Long?) + fun findByFcmMessageId(fcmMessageId: String?): Optional? + fun findByIdAndUserId(id: Long, userId: Long): Optional? +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt b/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt index 2c724c3d..8d1344fa 100644 --- a/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/DataMessageStateEventRepository.kt @@ -18,21 +18,16 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; - -import java.util.List; -import org.radarbase.appserver.entity.DataMessageStateEvent; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; +import org.radarbase.appserver.entity.DataMessageStateEvent +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository @Repository @RepositoryRestResource(exported = false) -public interface DataMessageStateEventRepository extends - JpaRepository { - - List findByDataMessageId(long dataMessageId); - - long countByDataMessageId(long dataMessageId); -} +interface DataMessageStateEventRepository : JpaRepository { + fun findByDataMessageId(dataMessageId: Long): List? + fun countByDataMessageId(dataMessageId: Long): Long +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt b/src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt index 4c82bfb9..d81325a5 100644 --- a/src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/NotificationRepository.kt @@ -18,54 +18,47 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; +import org.radarbase.appserver.entity.Notification +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository +import java.time.Instant +import java.util.* +import javax.validation.constraints.NotNull -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import javax.validation.constraints.NotNull; -import org.radarbase.appserver.entity.Notification; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @Repository @RepositoryRestResource(exported = false) -public interface NotificationRepository extends JpaRepository { - - List findByUserId(Long userId); - - void deleteByUserId(Long userId); - - boolean existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - Long userId, - String sourceId, - Instant scheduledTime, - String title, - String body, - String type, - int ttlSeconds); - - Optional findByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - Long userId, - String sourceId, - Instant scheduledTime, - String title, - String body, - String type, - int ttlSeconds); - - boolean existsByIdAndUserId(Long id, Long userId); - - boolean existsById(@NotNull Long id); - - void deleteByFcmMessageId(String fcmMessageId); - - void deleteByIdAndUserId(Long id, Long userId); +interface NotificationRepository : JpaRepository { + fun findByUserId(userId: Long?): List + fun deleteByUserId(userId: Long?) + fun existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + userId: Long?, + sourceId: String?, + scheduledTime: Instant?, + title: String?, + body: String?, + type: String?, + ttlSeconds: Int + ): Boolean - Optional findByFcmMessageId(String fcmMessageId); + fun findByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + userId: Long?, + sourceId: String?, + scheduledTime: Instant?, + title: String?, + body: String?, + type: String?, + ttlSeconds: Int + ): Optional? - Optional findByIdAndUserId(long id, long userId); -} + fun existsByIdAndUserId(id: Long?, userId: Long?): Boolean + override fun existsById(id: @NotNull Long?): Boolean + fun deleteByFcmMessageId(fcmMessageId: String?) + fun deleteByIdAndUserId(id: Long?, userId: Long?) + fun findByFcmMessageId(fcmMessageId: String?): Optional? + fun findByIdAndUserId(id: Long, userId: Long): Optional? +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt b/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt index c7a7392d..b9b15fc6 100644 --- a/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/NotificationStateEventRepository.kt @@ -18,21 +18,16 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; - -import java.util.List; -import org.radarbase.appserver.entity.NotificationStateEvent; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; +import org.radarbase.appserver.entity.NotificationStateEvent +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository @Repository @RepositoryRestResource(exported = false) -public interface NotificationStateEventRepository extends - JpaRepository { - - List findByNotificationId(long notificationId); - - long countByNotificationId(long notificationId); -} +interface NotificationStateEventRepository : JpaRepository { + fun findByNotificationId(notificationId: Long): List? + fun countByNotificationId(notificationId: Long): Long +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt b/src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt index 8c0209e9..3157c51b 100644 --- a/src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/ProjectRepository.kt @@ -18,21 +18,19 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; +import org.radarbase.appserver.entity.Project +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository +import java.util.* -import java.util.Optional; -import org.radarbase.appserver.entity.Project; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @Repository @RepositoryRestResource(exported = false) -public interface ProjectRepository extends JpaRepository { - - Optional findByProjectId(String projectId); - - Boolean existsByProjectId(String projectId); -} +interface ProjectRepository : JpaRepository { + fun findByProjectId(projectId: String?): Optional? + fun existsByProjectId(projectId: String?): Boolean? +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/repository/UserRepository.kt b/src/main/java/org/radarbase/appserver/repository/UserRepository.kt index 29c5549d..8349d5cb 100644 --- a/src/main/java/org/radarbase/appserver/repository/UserRepository.kt +++ b/src/main/java/org/radarbase/appserver/repository/UserRepository.kt @@ -18,29 +18,23 @@ * * * */ +package org.radarbase.appserver.repository -package org.radarbase.appserver.repository; +import org.radarbase.appserver.entity.User +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.rest.core.annotation.RepositoryRestResource +import org.springframework.stereotype.Repository +import java.util.* +import javax.validation.constraints.NotNull -import java.util.List; -import java.util.Optional; -import javax.validation.constraints.NotNull; -import org.radarbase.appserver.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import org.springframework.stereotype.Repository; - -/** @author yatharthranjan */ +/** @author yatharthranjan + */ @Repository @RepositoryRestResource(exported = false) -public interface UserRepository extends JpaRepository { - - Optional findBySubjectId(String subjectId); - - List findByProjectId(Long projectId); - - Optional findBySubjectIdAndProjectId(String subjectId, Long projectId); - - Optional findByFcmToken(String fcmToken); - - void deleteById(@NotNull Long id); -} +interface UserRepository : JpaRepository { + fun findBySubjectId(subjectId: String?): Optional? + fun findByProjectId(projectId: Long?): List? + fun findBySubjectIdAndProjectId(subjectId: String?, projectId: Long?): Optional? + fun findByFcmToken(fcmToken: String?): Optional? + override fun deleteById(id: @NotNull Long?) +} \ No newline at end of file diff --git a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java index 7a266369..483d6e0b 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmDataMessageService.java @@ -145,8 +145,8 @@ public boolean checkIfDataMessageExists(FcmDataMessageDto dataMessageDto, String if (user.isEmpty()) { throw new NotFoundException(INVALID_SUBJECT_ID_MESSAGE); } - DataMessage dataMessage = - dataMessageConverter.dtoToEntity(dataMessageDto).copy(null, user.get()); + DataMessage dataMessage = dataMessageConverter.dtoToEntity(dataMessageDto); + dataMessage.setUser(user.get()); List dataMessages = this.dataMessageRepository.findByUserId(user.get().getId()); return dataMessages.contains(dataMessage); @@ -176,7 +176,8 @@ public FcmDataMessageDto addDataMessage( dataMessageDto.getScheduledTime(), dataMessageDto.getTtlSeconds())) { - DataMessage dataMessage = dataMessageConverter.dtoToEntity(dataMessageDto).copy(null, user); + DataMessage dataMessage = dataMessageConverter.dtoToEntity(dataMessageDto); + dataMessage.setUser(user); DataMessage dataMessageSaved = this.dataMessageRepository.saveAndFlush(dataMessage); user.getUsermetrics().setLastOpened(Instant.now()); diff --git a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java index 97313377..42b8573e 100644 --- a/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java +++ b/src/main/java/org/radarbase/appserver/service/FcmNotificationService.java @@ -217,13 +217,12 @@ public FcmNotificationDto addNotification( notificationDto.getTtlSeconds()); if (notification.isEmpty()) { - Notification notificationSaved = - this.notificationRepository.saveAndFlush( - notificationConverter.dtoToEntity(notificationDto) - .copy(null, user) - ); + Notification notif = notificationConverter.dtoToEntity(notificationDto); + notif.setUser(user); + Notification notificationSaved = this.notificationRepository.saveAndFlush(notif); user.getUsermetrics().setLastOpened(Instant.now()); this.userRepository.save(user); + addNotificationStateEvent( notificationSaved, MessageState.ADDED, notificationSaved.getCreatedAt().toInstant()); this.schedulerService.schedule(notificationSaved); diff --git a/src/main/java/org/radarbase/appserver/service/UserService.java b/src/main/java/org/radarbase/appserver/service/UserService.java index e445537b..42e8e89a 100644 --- a/src/main/java/org/radarbase/appserver/service/UserService.java +++ b/src/main/java/org/radarbase/appserver/service/UserService.java @@ -192,7 +192,7 @@ public FcmUserDto updateUser(FcmUserDto userDto) { User updatedUser = user.get() .setFcmToken(userDto.getFcmToken()) - .setUserMetrics(UserConverter.getValidUserMetrics(userDto)) + .setUsermetrics(UserConverter.getValidUserMetrics(userDto)) .setEnrolmentDate(userDto.getEnrolmentDate()) .setTimezone(userDto.getTimezone()); // maintain a bi-directional relationship diff --git a/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt b/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt index c6223182..e8878a68 100644 --- a/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt +++ b/src/main/java/org/radarbase/appserver/service/scheduler/DataMessageSchedulerService.kt @@ -49,8 +49,9 @@ class DataMessageSchedulerService( companion object { private fun createMessageFromDataMessage(dataMessage: DataMessage): FcmDataMessage { - val to = dataMessage.fcmTopic ?: dataMessage.user?.fcmToken - ?: throw IllegalArgumentException("FCM Topic or User FCM Token is not set") + val to = checkNotNull( + dataMessage.fcmTopic ?: dataMessage.user?.fcmToken + ) { "FCM Topic or User FCM Token is not set" } return FcmDataMessage( to = to, @@ -58,8 +59,7 @@ class DataMessageSchedulerService( priority = dataMessage.priority, mutableContent = dataMessage.mutableContent, deliveryReceiptRequested = IS_DELIVERY_RECEIPT_REQUESTED, - messageId = dataMessage.fcmMessageId - ?: Random(System.currentTimeMillis()).nextLong().toString(), + messageId = dataMessage.fcmMessageId, timeToLive = dataMessage.ttlSeconds, data = dataMessage.dataMap, ) diff --git a/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt index a4bef34e..b2369aad 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmDataMessage.kt @@ -66,17 +66,17 @@ class FcmDataMessage( override val dryRun: Boolean = false, @JsonProperty - override val data: Map? = null, + override val data: Map? = null, ) : FcmDownstreamMessage { private val ttl = timeToLive * 1000L - override fun getAndroidConfig(): AndroidConfig = AndroidConfig.builder() - .setCollapseKey(collapseKey) - .setPriority(AndroidConfig.Priority.valueOf(priority ?: "HIGH")) - .setTtl(ttl) - .putAllData(data) - .build() + override fun getAndroidConfig(): AndroidConfig = AndroidConfig.builder().apply { + collapseKey?.let { setCollapseKey(collapseKey) } + setPriority(AndroidConfig.Priority.valueOf(priority ?: "HIGH")) + setTtl(ttl) + data?.let { putAllData(data) } + }.build() override fun getApnsConfig(): ApnsConfig { val config = ApnsConfig.builder() @@ -86,17 +86,19 @@ class FcmDataMessage( // The date at which the notification is no longer valid. This value is a UNIX epoch // expressed in seconds (UTC). - return config.putHeader( - "apns-expiration", ( - Instant.now() - .plus(Duration.ofSeconds(timeToLive.toLong())) - .toEpochMilli() / 1000).toString() - ) - .putAllCustomData(data) - .setAps(Aps.builder().setContentAvailable(true).setSound("default").build()) - .putHeader("apns-push-type", "background") // No alert is shown - .putHeader("apns-priority", "5") // 5 required in case of background type - .build() + return config.apply { + + putHeader( + "apns-expiration", ( + Instant.now() + .plus(Duration.ofSeconds(timeToLive.toLong())) + .toEpochMilli() / 1000).toString() + ) + data?.let { putAllCustomData(data) } + setAps(Aps.builder().setContentAvailable(true).setSound("default").build()) + putHeader("apns-push-type", "background") // No alert is shown + putHeader("apns-priority", "5") // 5 required in case of background type + }.build() } override fun getWebPushConfig(): WebpushConfig { diff --git a/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt index 628c6b3c..278f8560 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmDownstreamMessage.kt @@ -40,7 +40,7 @@ interface FcmDownstreamMessage : FcmMessage { val timeToLive: Int val deliveryReceiptRequested: Boolean val dryRun: Boolean - val data: Map? + val data: Map? fun getAndroidConfig(): AndroidConfig fun getApnsConfig(): ApnsConfig diff --git a/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt b/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt index 8f6807f6..3978759f 100644 --- a/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt +++ b/src/main/java/org/radarbase/fcm/model/FcmNotificationMessage.kt @@ -62,7 +62,7 @@ class FcmNotificationMessage( override val dryRun: Boolean = false, @JsonProperty - override val data: Map? = null, + override val data: Map? = null, // TODO Add specific Notification model and data model classes instead of using Maps. @JsonProperty @@ -141,25 +141,39 @@ class FcmNotificationMessage( } private fun getAndroidNotification(): AndroidNotification { - val builder = AndroidNotification.builder() - .setBody(notification.getOrDefault("body", "").toString()) - .setTitle(notification.getOrDefault("title", "").toString()) - .setChannelId(notification["android_channel_id"].toString()) - .setColor(notification["color"].toString()) - .setTag(notification["tag"].toString()) - .setIcon(notification["icon"].toString()) - .setSound(notification["sound"].toString()) - .setClickAction(notification["click_action"].toString()) - notification["body_loc_key"]?.let { - builder - .setBodyLocalizationKey(notification["body_loc_key"].toString()) - .addBodyLocalizationArg(notification["body_loc_args"].toString()) - } - notification["title_loc_key"]?.let { - builder - .addTitleLocalizationArg(notification["title_loc_args"].toString()) - .setTitleLocalizationKey(notification["title_loc_key"].toString()) - } - return builder.build() + return AndroidNotification.builder().apply { + setBody(notification.getOrDefault("body", "").toString()) + setTitle(notification.getOrDefault("title", "").toString()) + notification["android_channel_id"]?.let { + setChannelId(it.toString()) + } + notification["color"]?.let { + setColor(it.toString()) + } + notification["icon"]?.let { + setIcon(it.toString()) + } + notification["image"]?.let { + setImage(it.toString()) + } + notification["tag"]?.let { + setTag(it.toString()) + } + notification["click_action"]?.let { + setClickAction(it.toString()) + } + notification["body_loc_key"]?.let { + setBodyLocalizationKey(it.toString()) + addBodyLocalizationArg(notification["body_loc_args"].toString()) + } + + notification["title_loc_key"]?.let { + setTitleLocalizationKey(it.toString()) + addTitleLocalizationArg(notification["title_loc_args"].toString()) + } + notification["sound"]?.let { + setSound(it.toString()) + } + }.build() } } \ No newline at end of file diff --git a/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt b/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt index 04fa867a..0a9a4727 100644 --- a/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt +++ b/src/test/java/org/radarbase/appserver/repository/DataMessageRepositoryTest.kt @@ -18,190 +18,183 @@ * * * */ - -package org.radarbase.appserver.repository; - -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.radarbase.appserver.controller.RadarUserControllerTest.TIMEZONE; - -import java.time.Duration; -import java.time.Instant; -import javax.persistence.PersistenceException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.appserver.entity.DataMessage; -import org.radarbase.appserver.entity.Project; -import org.radarbase.appserver.entity.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -@ExtendWith(SpringExtension.class) +package org.radarbase.appserver.repository + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.appserver.controller.RadarUserControllerTest +import org.radarbase.appserver.entity.DataMessage +import org.radarbase.appserver.entity.Project +import org.radarbase.appserver.entity.User +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.time.Duration +import java.time.Instant +import javax.persistence.PersistenceException + +@ExtendWith(SpringExtension::class) @DataJpaTest @EnableJpaAuditing -public class DataMessageRepositoryTest { - public static final String DATA_MESSAGE_FCM_MESSAGE_ID = "12345"; - public static final String DATA_MESSAGE_SOURCE_ID = "test"; +@EnableJpaRepositories("org.radarbase.appserver.repository") +class DataMessageRepositoryTest { @Autowired - private transient TestEntityManager entityManager; + @Transient + lateinit var entityManager: TestEntityManager + @Autowired - private transient DataMessageRepository dataMessageRepository; - private transient Long id; - private transient User user; - private transient Instant scheduledTime; + @Transient + lateinit var dataMessageRepository: DataMessageRepository + + @Transient + private var id: Long? = null + + @Transient + private lateinit var user: User + + @Transient + private lateinit var scheduledTime: Instant /** * Insert a DataMessage Before each test. */ @BeforeEach - public void initDataMessage() { + fun initDataMessage() { // given - Project project = new Project().setProjectId("test-project"); - entityManager.persist(project); - - this.user = - new User() - .setFcmToken("xxxx") - .setEnrolmentDate(Instant.now()) - .setProject(project) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId("test-user"); - entityManager.persist(this.user); - - this.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)); - - DataMessage dataMessage = new DataMessage(); - dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); - dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); - dataMessage.setScheduledTime(this.scheduledTime); - dataMessage.setUser(this.user); - dataMessage.setTtlSeconds(86400); - dataMessage.setDelivered(false); - - this.id = (Long) entityManager.persistAndGetId(dataMessage); - entityManager.flush(); + val project = Project().setProjectId("test-project") + entityManager.persist(project) + user = User() + .setFcmToken("xxxx") + .setEnrolmentDate(Instant.now()) + .setProject(project) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId("test-user") + entityManager.persist(user) + scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + val dataMessage = DataMessage() + dataMessage.fcmMessageId = DATA_MESSAGE_FCM_MESSAGE_ID + dataMessage.sourceId = DATA_MESSAGE_SOURCE_ID + dataMessage.scheduledTime = scheduledTime + dataMessage.user = user + dataMessage.ttlSeconds = 86400 + dataMessage.delivered = false + id = entityManager.persistAndGetId(dataMessage) as Long + entityManager.flush() } @Test - public void whenInsertWithTransientUser_thenThrowException() { + fun whenInsertWithTransientUser_thenThrowException() { // given - DataMessage dataMessage = new DataMessage(); - dataMessage.setUser(new User()); - dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); - dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - dataMessage.setTtlSeconds(86400); - dataMessage.setDelivered(false); - dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); - - IllegalStateException ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(dataMessage); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); + val dataMessage = DataMessage() + dataMessage.user = User() + dataMessage.sourceId = DATA_MESSAGE_SOURCE_ID + dataMessage.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + dataMessage.ttlSeconds = 86400 + dataMessage.delivered = false + dataMessage.fcmMessageId = DATA_MESSAGE_FCM_MESSAGE_ID + val ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(dataMessage) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) } @Test - public void whenInsertWithoutUser_thenThrowException() { + fun whenInsertWithoutUser_thenThrowException() { // given - DataMessage dataMessage = new DataMessage(); - dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); - dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - dataMessage.setTtlSeconds(86400); - dataMessage.setDelivered(false); - dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); - - assertThrows( - PersistenceException.class, - () -> { - entityManager.persist(dataMessage); - entityManager.flush(); - }); + val dataMessage = DataMessage() + dataMessage.sourceId = DATA_MESSAGE_SOURCE_ID + dataMessage.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + dataMessage.ttlSeconds = 86400 + dataMessage.delivered = false + dataMessage.fcmMessageId = DATA_MESSAGE_FCM_MESSAGE_ID + Assertions.assertThrows( + PersistenceException::class.java + ) { + entityManager.persist(dataMessage) + entityManager.flush() + } } @Test - public void whenInsertWithUserButTransientProject_thenThrowException() { + fun whenInsertWithUserButTransientProject_thenThrowException() { // given - User user = - new User() - .setFcmToken("xxxx") - .setEnrolmentDate(Instant.now()) - .setProject(new Project()) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId("test-user"); - - IllegalStateException ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(user); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); - - DataMessage dataMessage = new DataMessage(); - dataMessage.setUser(user); - dataMessage.setSourceId(DATA_MESSAGE_SOURCE_ID); - dataMessage.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - dataMessage.setTtlSeconds(86400); - dataMessage.setDelivered(false); - dataMessage.setFcmMessageId(DATA_MESSAGE_FCM_MESSAGE_ID); - - ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(dataMessage); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); + val user = User() + .setFcmToken("xxxx") + .setEnrolmentDate(Instant.now()) + .setProject(Project()) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId("test-user") + var ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(user) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) + val dataMessage = DataMessage() + dataMessage.user = user + dataMessage.sourceId = DATA_MESSAGE_SOURCE_ID + dataMessage.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + dataMessage.ttlSeconds = 86400 + dataMessage.delivered = false + dataMessage.fcmMessageId = DATA_MESSAGE_FCM_MESSAGE_ID + ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(dataMessage) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) } @Test - public void whenExists_thenReturnTrue() { + fun whenExists_thenReturnTrue() { // when - boolean exists = - dataMessageRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTtlSeconds( - this.user.getId(), - DATA_MESSAGE_SOURCE_ID, - this.scheduledTime, - 86400); + val exists = dataMessageRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTtlSeconds( + user.id, + DATA_MESSAGE_SOURCE_ID, + scheduledTime, + 86400 + ) // then - assertTrue(exists); - assertTrue(dataMessageRepository.existsById(this.id)); + Assertions.assertTrue(exists) + Assertions.assertTrue(dataMessageRepository.existsById(id)) } @Test - public void whenDeleteDataMessageById_thenExistsFalse() { + fun whenDeleteDataMessageById_thenExistsFalse() { // when - dataMessageRepository.deleteById(this.id); + dataMessageRepository.deleteById(id) // then - DataMessage dataMessage = entityManager.find(DataMessage.class, this.id); - assertNull(dataMessage); + val dataMessage = entityManager.find(DataMessage::class.java, id) + Assertions.assertNull(dataMessage) } @Test - public void whenDeleteDataMessageByUserId_thenExistsFalse() { + fun whenDeleteDataMessageByUserId_thenExistsFalse() { // when - dataMessageRepository.deleteByUserId(this.user.getId()); + dataMessageRepository.deleteByUserId(user.id) // then - DataMessage dataMessage = entityManager.find(DataMessage.class, this.id); - assertNull(dataMessage); + val dataMessage = entityManager.find(DataMessage::class.java, id) + Assertions.assertNull(dataMessage) + } + + companion object { + const val DATA_MESSAGE_FCM_MESSAGE_ID = "12345" + const val DATA_MESSAGE_SOURCE_ID = "test" } -} +} \ No newline at end of file diff --git a/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt b/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt index 6e59fb00..2f0cd60a 100644 --- a/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt +++ b/src/test/java/org/radarbase/appserver/repository/NotificationRepositoryTest.kt @@ -18,205 +18,200 @@ * * * */ - -package org.radarbase.appserver.repository; - -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.radarbase.appserver.controller.RadarUserControllerTest.TIMEZONE; - -import java.time.Duration; -import java.time.Instant; -import javax.persistence.PersistenceException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.appserver.entity.Notification; -import org.radarbase.appserver.entity.Project; -import org.radarbase.appserver.entity.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -@ExtendWith(SpringExtension.class) +package org.radarbase.appserver.repository + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.appserver.controller.RadarUserControllerTest +import org.radarbase.appserver.entity.Notification +import org.radarbase.appserver.entity.Project +import org.radarbase.appserver.entity.User +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.time.Duration +import java.time.Instant +import javax.persistence.PersistenceException + +@ExtendWith(SpringExtension::class) @DataJpaTest @EnableJpaAuditing -public class NotificationRepositoryTest { - public static final String NOTIFICATION_BODY = "Test notif"; - public static final String NOTIFICATION_TITLE = "Testing"; - public static final String NOTIFICATION_FCM_MESSAGE_ID = "12345"; - public static final String NOTIFICATION_SOURCE_ID = "test"; +@EnableJpaRepositories("org.radarbase.appserver.repository") +class NotificationRepositoryTest { @Autowired - private transient TestEntityManager entityManager; + @Transient + lateinit var entityManager: TestEntityManager + @Autowired - private transient NotificationRepository notificationRepository; - private transient Long id; - private transient User user; - private transient Instant scheduledTime; + @Transient + lateinit var notificationRepository: NotificationRepository + + @Transient + private var id: Long? = null + + @Transient + private lateinit var user: User + + @Transient + private lateinit var scheduledTime: Instant /** * Insert a Notification Before each test. */ @BeforeEach - public void initNotification() { + fun initNotification() { // given - Project project = new Project().setProjectId("test-project"); - entityManager.persist(project); - - this.user = - new User() - .setFcmToken("xxxx") - .setEnrolmentDate(Instant.now()) - .setProject(project) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId("test-user"); - entityManager.persist(this.user); - - this.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)); - - Notification notification = new Notification(); - notification.setBody(NOTIFICATION_BODY); - notification.setTitle(NOTIFICATION_TITLE); - notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); - notification.setSourceId(NOTIFICATION_SOURCE_ID); - notification.setScheduledTime(this.scheduledTime); - notification.setUser(this.user); - notification.setTtlSeconds(86400); - notification.setDelivered(false); - - this.id = (Long) entityManager.persistAndGetId(notification); - entityManager.flush(); + val project = Project().setProjectId("test-project") + entityManager.persist(project) + user = User() + .setFcmToken("xxxx") + .setEnrolmentDate(Instant.now()) + .setProject(project) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId("test-user") + entityManager.persist(user) + scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + val notification = Notification() + notification.body = NOTIFICATION_BODY + notification.title = NOTIFICATION_TITLE + notification.fcmMessageId = NOTIFICATION_FCM_MESSAGE_ID + notification.sourceId = NOTIFICATION_SOURCE_ID + notification.scheduledTime = scheduledTime + notification.user = user + notification.ttlSeconds = 86400 + notification.delivered = false + id = entityManager.persistAndGetId(notification) as Long + entityManager.flush() } @Test - public void whenInsertWithTransientUser_thenThrowException() { + fun whenInsertWithTransientUser_thenThrowException() { // given - Notification notification = new Notification(); - notification.setBody(NOTIFICATION_BODY); - notification.setTitle(NOTIFICATION_TITLE); - notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); - notification.setSourceId(NOTIFICATION_SOURCE_ID); - notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - notification.setUser(new User()); - notification.setTtlSeconds(86400); - notification.setDelivered(false); - - - - IllegalStateException ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(notification); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); + val notification = Notification() + notification.body = NOTIFICATION_BODY + notification.title = NOTIFICATION_TITLE + notification.fcmMessageId = NOTIFICATION_FCM_MESSAGE_ID + notification.sourceId = NOTIFICATION_SOURCE_ID + notification.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + notification.user = User() + notification.ttlSeconds = 86400 + notification.delivered = false + val ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(notification) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) } @Test - public void whenInsertWithoutUser_thenThrowException() { + fun whenInsertWithoutUser_thenThrowException() { // given - Notification notification = new Notification(); - notification.setBody(NOTIFICATION_BODY); - notification.setTitle(NOTIFICATION_TITLE); - notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); - notification.setSourceId(NOTIFICATION_SOURCE_ID); - notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - notification.setTtlSeconds(86400); - notification.setDelivered(false); - - assertThrows( - PersistenceException.class, - () -> { - entityManager.persist(notification); - entityManager.flush(); - }); + val notification = Notification() + notification.body = NOTIFICATION_BODY + notification.title = NOTIFICATION_TITLE + notification.fcmMessageId = NOTIFICATION_FCM_MESSAGE_ID + notification.sourceId = NOTIFICATION_SOURCE_ID + notification.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + notification.ttlSeconds = 86400 + notification.delivered = false + Assertions.assertThrows( + PersistenceException::class.java + ) { + entityManager.persist(notification) + entityManager.flush() + } } @Test - public void whenInsertWithUserButTransientProject_thenThrowException() { + fun whenInsertWithUserButTransientProject_thenThrowException() { // given - User user = - new User() - .setFcmToken("xxxx") - .setEnrolmentDate(Instant.now()) - .setProject(new Project()) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId("test-user"); - - IllegalStateException ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(user); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); - - Notification notification = new Notification(); - notification.setBody(NOTIFICATION_BODY); - notification.setTitle(NOTIFICATION_TITLE); - notification.setFcmMessageId(NOTIFICATION_FCM_MESSAGE_ID); - notification.setSourceId(NOTIFICATION_SOURCE_ID); - notification.setScheduledTime(Instant.now().plus(Duration.ofSeconds(100))); - notification.setUser(user); - notification.setTtlSeconds(86400); - notification.setDelivered(false); - - ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(notification); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); + val user = User() + .setFcmToken("xxxx") + .setEnrolmentDate(Instant.now()) + .setProject(Project()) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId("test-user") + var ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(user) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) + val notification = Notification() + notification.body = NOTIFICATION_BODY + notification.title = NOTIFICATION_TITLE + notification.fcmMessageId = NOTIFICATION_FCM_MESSAGE_ID + notification.sourceId = NOTIFICATION_SOURCE_ID + notification.scheduledTime = Instant.now().plus(Duration.ofSeconds(100)) + notification.user = user + notification.ttlSeconds = 86400 + notification.delivered = false + ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(notification) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) } @Test - public void whenExists_thenReturnTrue() { + fun whenExists_thenReturnTrue() { // when - boolean exists = - notificationRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - this.user.getId(), - NOTIFICATION_SOURCE_ID, - this.scheduledTime, - NOTIFICATION_TITLE, - NOTIFICATION_BODY, - null, - 86400); + val exists = notificationRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + user.id, + NOTIFICATION_SOURCE_ID, + scheduledTime, + NOTIFICATION_TITLE, + NOTIFICATION_BODY, + null, + 86400 + ) // then - assertTrue(exists); - assertTrue(notificationRepository.existsById(this.id)); + Assertions.assertTrue(exists) + Assertions.assertTrue(notificationRepository.existsById(id)) } @Test - public void whenDeleteNotificationById_thenExistsFalse() { + fun whenDeleteNotificationById_thenExistsFalse() { // when - notificationRepository.deleteById(this.id); + notificationRepository.deleteById(id) // then - Notification notification = entityManager.find(Notification.class, this.id); - assertNull(notification); + val notification = entityManager.find( + Notification::class.java, id + ) + Assertions.assertNull(notification) } @Test - public void whenDeleteNotificationByUserId_thenExistsFalse() { + fun whenDeleteNotificationByUserId_thenExistsFalse() { // when - notificationRepository.deleteByUserId(this.user.getId()); + notificationRepository.deleteByUserId(user.id) // then - Notification notification = entityManager.find(Notification.class, this.id); - assertNull(notification); + val notification = entityManager.find( + Notification::class.java, id + ) + Assertions.assertNull(notification) + } + + companion object { + const val NOTIFICATION_BODY = "Test notif" + const val NOTIFICATION_TITLE = "Testing" + const val NOTIFICATION_FCM_MESSAGE_ID = "12345" + const val NOTIFICATION_SOURCE_ID = "test" } -} +} \ No newline at end of file diff --git a/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt b/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt index 40ce7f27..e180ae4d 100644 --- a/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt +++ b/src/test/java/org/radarbase/appserver/repository/UserRepositoryTest.kt @@ -18,133 +18,131 @@ * * * */ - -package org.radarbase.appserver.repository; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.radarbase.appserver.controller.FcmNotificationControllerTest.USER_ID; -import static org.radarbase.appserver.controller.RadarUserControllerTest.FCM_TOKEN_1; -import static org.radarbase.appserver.controller.RadarUserControllerTest.TIMEZONE; - -import java.time.Instant; -import javax.persistence.PersistenceException; - -import org.hibernate.exception.ConstraintViolationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.appserver.entity.Project; -import org.radarbase.appserver.entity.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -@ExtendWith(SpringExtension.class) +package org.radarbase.appserver.repository + +import org.hibernate.exception.ConstraintViolationException +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.appserver.controller.FcmNotificationControllerTest +import org.radarbase.appserver.controller.RadarUserControllerTest +import org.radarbase.appserver.entity.Project +import org.radarbase.appserver.entity.User +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.time.Instant +import javax.persistence.PersistenceException + +@ExtendWith(SpringExtension::class) @DataJpaTest @EnableJpaAuditing -class UserRepositoryTest { - +internal class UserRepositoryTest { @Autowired - private transient TestEntityManager entityManager; + @Transient + lateinit var entityManager: TestEntityManager @Autowired - private transient UserRepository userRepository; + @Transient + lateinit var userRepository: UserRepository - private transient Project project; - private transient Long projectId; - private transient Long userId; + @Transient + private var project: Project? = null - @BeforeEach - void setUp() { + @Transient + private var projectId: Long? = null - this.project = new Project().setProjectId("test-project"); - this.projectId = entityManager.persistAndGetId(project, Long.class); + @Transient + private var userId: Long? = null - User user = - new User() - .setFcmToken(FCM_TOKEN_1) - .setEnrolmentDate(Instant.now()) - .setProject(project) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId(USER_ID); - this.userId = entityManager.persistAndGetId(user, Long.class); - entityManager.flush(); + @BeforeEach + fun setUp() { + project = Project().setProjectId("test-project") + projectId = entityManager.persistAndGetId(project) as Long + val user = User() + .setFcmToken(RadarUserControllerTest.FCM_TOKEN_1) + .setEnrolmentDate(Instant.now()) + .setProject(project) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId(FcmNotificationControllerTest.USER_ID) + userId = entityManager.persistAndGetId(user) as Long + entityManager.flush() } @Test - public void whenInsertWithTransientProject_thenThrowException() { - User user1 = - new User() - .setFcmToken(FCM_TOKEN_1) - .setEnrolmentDate(Instant.now()) - .setProject(new Project()) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId(USER_ID); - - IllegalStateException ex = - assertThrows( - IllegalStateException.class, - () -> { - entityManager.persist(user1); - entityManager.flush(); - }); - - assertTrue(ex.getMessage().contains("Not-null property references a transient value")); + fun whenInsertWithTransientProject_thenThrowException() { + val user1 = User() + .setFcmToken(RadarUserControllerTest.FCM_TOKEN_1) + .setEnrolmentDate(Instant.now()) + .setProject(Project()) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId(FcmNotificationControllerTest.USER_ID) + val ex = Assertions.assertThrows( + IllegalStateException::class.java + ) { + entityManager.persist(user1) + entityManager.flush() + } + Assertions.assertTrue(ex.message!!.contains("Not-null property references a transient value")) } @Test - public void whenFindUserBySubjectId_thenReturnUser() { - - assertEquals( - userRepository.findBySubjectId(USER_ID).get(), entityManager.find(User.class, this.userId)); + fun whenFindUserBySubjectId_thenReturnUser() { + Assertions.assertEquals( + userRepository.findBySubjectId(FcmNotificationControllerTest.USER_ID)!!.get(), + entityManager.find( + User::class.java, userId + ) + ) } @Test - public void whenFindByProjectId_thenReturnUsers() { - assertEquals( - userRepository.findByProjectId(this.projectId).get(0), - entityManager.find(User.class, this.userId)); + fun whenFindByProjectId_thenReturnUsers() { + Assertions.assertEquals( + userRepository.findByProjectId(projectId)!![0], + entityManager.find(User::class.java, userId) + ) } @Test - public void whenFindBySubjectIdAndProjectId_thenReturnUser() { - assertEquals( - userRepository.findBySubjectIdAndProjectId(USER_ID, this.projectId).get(), - entityManager.find(User.class, this.userId)); + fun whenFindBySubjectIdAndProjectId_thenReturnUser() { + Assertions.assertEquals( + userRepository.findBySubjectIdAndProjectId( + FcmNotificationControllerTest.USER_ID, + projectId + )!!.get(), + entityManager.find(User::class.java, userId) + ) } @Test - public void whenFindByFcmToken_thenReturnUser() { - assertEquals( - userRepository.findByFcmToken(FCM_TOKEN_1).get(), - entityManager.find(User.class, this.userId)); + fun whenFindByFcmToken_thenReturnUser() { + Assertions.assertEquals( + userRepository.findByFcmToken(RadarUserControllerTest.FCM_TOKEN_1)!!.get(), + entityManager.find(User::class.java, userId) + ) } @Test - public void whenInsertWithExistingFcmToken_thenThrowException() { - User user1 = - new User() - .setFcmToken(FCM_TOKEN_1) - .setEnrolmentDate(Instant.now()) - .setProject(this.project) - .setTimezone(TIMEZONE) - .setLanguage("en") - .setSubjectId(USER_ID + "-2"); - - PersistenceException ex = - assertThrows( - PersistenceException.class, - () -> { - entityManager.persistAndGetId(user1, Long.class); - entityManager.flush(); - }); - - assertEquals(ConstraintViolationException.class, ex.getCause().getClass()); + fun whenInsertWithExistingFcmToken_thenThrowException() { + val user1 = User() + .setFcmToken(RadarUserControllerTest.FCM_TOKEN_1) + .setEnrolmentDate(Instant.now()) + .setProject(project) + .setTimezone(RadarUserControllerTest.TIMEZONE) + .setLanguage("en") + .setSubjectId(FcmNotificationControllerTest.USER_ID + "-2") + val ex = Assertions.assertThrows( + PersistenceException::class.java + ) { + entityManager.persistAndGetId(user1) as Long + entityManager.flush() + } + Assertions.assertEquals(ConstraintViolationException::class.java, ex.cause!!.javaClass) } -} +} \ No newline at end of file diff --git a/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java b/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java index 53a99db6..3ebc9602 100644 --- a/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/FcmNotificationServiceTest.java @@ -30,18 +30,17 @@ import static org.radarbase.appserver.controller.FcmNotificationControllerTest.PROJECT_ID; import static org.radarbase.appserver.controller.FcmNotificationControllerTest.USER_ID; import static org.radarbase.appserver.controller.RadarUserControllerTest.FCM_TOKEN_1; +import static org.radarbase.appserver.controller.RadarUserControllerTest.TIMEZONE; import static org.radarbase.appserver.repository.NotificationRepositoryTest.NOTIFICATION_BODY; import static org.radarbase.appserver.repository.NotificationRepositoryTest.NOTIFICATION_FCM_MESSAGE_ID; import static org.radarbase.appserver.repository.NotificationRepositoryTest.NOTIFICATION_SOURCE_ID; import static org.radarbase.appserver.repository.NotificationRepositoryTest.NOTIFICATION_TITLE; -import static org.radarbase.appserver.controller.RadarUserControllerTest.TIMEZONE; import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Optional; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -79,15 +78,19 @@ class FcmNotificationServiceTest { private static final String NOTIFICATION_TITLE_4 = "Testing4"; private static User user; private final transient Instant scheduledTime = Instant.now().plus(Duration.ofSeconds(100)); + @MockBean private transient NotificationSchedulerService schedulerService; // TODO Make this generic when NotificationService interface is complete @Autowired private transient FcmNotificationService notificationService; + @MockBean private transient NotificationRepository notificationRepository; + @MockBean private transient UserRepository userRepository; + @MockBean private transient ProjectRepository projectRepository; @@ -106,7 +109,7 @@ void setUp() { .setEnrolmentDate(Instant.now()) .setFcmToken(FCM_TOKEN_1) .setSubjectId(USER_ID + NEW_SUFFIX) - .setUserMetrics( + .setUsermetrics( new UserMetrics().setLastOpened(Instant.now()).setLastDelivered(Instant.now())) .setId(2L); @@ -118,6 +121,7 @@ void setUp() { notification3.setTitle(NOTIFICATION_TITLE_3); notification3.setScheduledTime(scheduledTime); notification3.setSourceId(NOTIFICATION_SOURCE_ID); + notification3.setBody(NOTIFICATION_BODY); notification3.setFcmMessageId("1234567"); notification3.setTtlSeconds(86400); @@ -129,15 +133,15 @@ void setUp() { Mockito.when(notificationRepository.findById(3L)).thenReturn(Optional.of(notification3)); Mockito.when( - notificationRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - 1L, - NOTIFICATION_SOURCE_ID, - scheduledTime, - NOTIFICATION_TITLE_3, - NOTIFICATION_BODY, - null, - 86400)) + notificationRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + 1L, + NOTIFICATION_SOURCE_ID, + scheduledTime, + NOTIFICATION_TITLE_3, + NOTIFICATION_BODY, + null, + 86400)) .thenReturn(false); Notification notification4 = new Notification(); @@ -158,15 +162,15 @@ void setUp() { Mockito.when(notificationRepository.findById(4L)).thenReturn(Optional.of(notification4)); Mockito.when( - notificationRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - 2L, - NOTIFICATION_SOURCE_ID, - scheduledTime, - NOTIFICATION_TITLE_4, - NOTIFICATION_BODY, - null, - 86400)) + notificationRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + 2L, + NOTIFICATION_SOURCE_ID, + scheduledTime, + NOTIFICATION_TITLE_4, + NOTIFICATION_BODY, + null, + 86400)) .thenReturn(false); Notification notification5 = new Notification(); @@ -178,6 +182,7 @@ void setUp() { notification5.setBody(NOTIFICATION_BODY + " Updated"); notification5.setDelivered(false); notification5.setFcmMessageId(FCM_MESSAGE_ID); + notification5.setTtlSeconds(86400); notification5.setCreatedAt(new Date()); @@ -203,7 +208,7 @@ private void setUpProjectAndUser() { .setTimezone(TIMEZONE) .setLanguage("en") .setSubjectId(USER_ID) - .setUserMetrics( + .setUsermetrics( new UserMetrics().setLastOpened(Instant.now()).setLastDelivered(Instant.now())) .setId(1L); @@ -259,34 +264,34 @@ private void setUpNotification1And2() { Mockito.when(notificationRepository.findById(2L)).thenReturn(Optional.of(notification2)); Mockito.when( - notificationRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - 1L, - NOTIFICATION_SOURCE_ID, - scheduledTime, - NOTIFICATION_TITLE_1, - NOTIFICATION_BODY, - null, - 86400)) + notificationRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + 1L, + NOTIFICATION_SOURCE_ID, + scheduledTime, + NOTIFICATION_TITLE_1, + NOTIFICATION_BODY, + null, + 86400)) .thenReturn(true); Mockito.when( - notificationRepository - .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( - 1L, - NOTIFICATION_SOURCE_ID, - scheduledTime, - NOTIFICATION_TITLE_2, - NOTIFICATION_BODY, - null, - 86400)) + notificationRepository + .existsByUserIdAndSourceIdAndScheduledTimeAndTitleAndBodyAndTypeAndTtlSeconds( + 1L, + NOTIFICATION_SOURCE_ID, + scheduledTime, + NOTIFICATION_TITLE_2, + NOTIFICATION_BODY, + null, + 86400)) .thenReturn(true); Mockito.when( - notificationRepository - .existsByIdAndUserId( - 1L, - 1L)) + notificationRepository + .existsByIdAndUserId( + 1L, + 1L)) .thenReturn(true); Mockito.when(notificationRepository.findByIdAndUserId(1L, 1L)).thenReturn(Optional.of(notification1)); @@ -359,7 +364,11 @@ void checkIfNotificationExists() { // A random notification should not exist assertFalse( notificationService.checkIfNotificationExists( - new FcmNotificationDto().setScheduledTime(Instant.now()), USER_ID)); + new FcmNotificationDto() + .setTitle("") + .setFcmMessageId(FCM_MESSAGE_ID) + .setScheduledTime(Instant.now()), + USER_ID)); } @Test @@ -380,8 +389,9 @@ void addNotification() { .setTtlSeconds(86400) .setDelivered(false); - notificationService.addNotification(notificationDto, USER_ID, PROJECT_ID); - FcmNotificationDto savedNotification = notificationService.getNotificationById(3L); + FcmNotificationDto result = notificationService.addNotification(notificationDto, USER_ID, + PROJECT_ID); + FcmNotificationDto savedNotification = notificationService.getNotificationById(result.getId()); assertEquals(NOTIFICATION_TITLE_3, savedNotification.getTitle()); assertEquals("1234567", savedNotification.getFcmMessageId()); diff --git a/src/test/java/org/radarbase/appserver/service/UserServiceTest.java b/src/test/java/org/radarbase/appserver/service/UserServiceTest.java index dae99fbd..5910562b 100644 --- a/src/test/java/org/radarbase/appserver/service/UserServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/UserServiceTest.java @@ -63,7 +63,7 @@ class UserServiceTest { @MockBean private transient ProjectRepository projectRepository; - private transient Instant enrolmentDate = Instant.now().plus(Duration.ofSeconds(100)); + private final transient Instant enrolmentDate = Instant.now().plus(Duration.ofSeconds(100)); @BeforeEach void setUp() { @@ -113,7 +113,7 @@ void setUp() { .setEnrolmentDate(enrolmentDate) .setLanguage("es") .setTimezone("Europe/Bucharest") - .setUserMetrics( + .setUsermetrics( new UserMetrics().setLastDelivered(enrolmentDate).setLastOpened(enrolmentDate)); Mockito.when(userRepository.save(userUpdated)).thenReturn(userUpdated.setId(1L)); diff --git a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java index db3dec8a..361610d1 100644 --- a/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java +++ b/src/test/java/org/radarbase/appserver/service/scheduler/NotificationSchedulerServiceTest.java @@ -77,6 +77,7 @@ class NotificationSchedulerServiceTest { private static final String JOB_DETAIL_ID = "message-jobdetail-test-subject-1"; + private static final String NOTIFICATION_TITLE = "Testing"; private static Notification notification; @Autowired private transient NotificationSchedulerService notificationSchedulerService; @@ -104,8 +105,8 @@ void setUp() throws SchedulerException { notification.setTtlSeconds(900); notification.setFcmMessageId("xxxx"); notification.setAppPackage("aRMT"); - notification.setTitle("Testing"); - notification.setBody("Testing"); + notification.setTitle(NOTIFICATION_TITLE); + notification.setBody(NOTIFICATION_TITLE); notification.setType("ESM"); } @@ -145,8 +146,8 @@ void updateScheduledNotification() throws SchedulerException { notification2.setScheduledTime(Instant.now().plus(Duration.ofSeconds(3))); notification2.setTtlSeconds(900); notification2.setFcmMessageId("yyyy"); - notification2.setTitle("Testing"); - notification2.setBody("Testing"); + notification2.setTitle(NOTIFICATION_TITLE); + notification2.setBody(NOTIFICATION_TITLE); // when notificationSchedulerService.updateScheduled(notification2); From 2d518cdb24584452a9af3d67484155a0957a7b65 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Thu, 14 Apr 2022 21:05:23 +0100 Subject: [PATCH 07/11] fix CI --- build.gradle | 4 ++++ gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes 2 files changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 08f5e184..76759446 100644 --- a/build.gradle +++ b/build.gradle @@ -196,6 +196,10 @@ rootProject.tasks.named("processIntegrationTestResources") { duplicatesStrategy = 'include' } +tasks.withType(Copy).configureEach { + duplicatesStrategy = 'include' +} + check.dependsOn integrationTest integrationTest { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 From a128597acaa66e0e5cc0509f0ffa461ac2ec8235 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Thu, 14 Apr 2022 21:11:16 +0100 Subject: [PATCH 08/11] fix bootJar task --- build.gradle | 5 +---- gradlew.bat | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 76759446..5f37377f 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ repositories { bootJar { mainClass = 'org.radarbase.appserver.AppserverApplication' + duplicatesStrategy = 'include' } //apply from: 'gradle/liquibase.gradle' @@ -196,10 +197,6 @@ rootProject.tasks.named("processIntegrationTestResources") { duplicatesStrategy = 'include' } -tasks.withType(Copy).configureEach { - duplicatesStrategy = 'include' -} - check.dependsOn integrationTest integrationTest { diff --git a/gradlew.bat b/gradlew.bat index 477c8966..107acd32 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -86,4 +86,4 @@ exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal -:omega \ No newline at end of file +:omega From 774737a15a0c33875b18643647b7285692e41f33 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Fri, 15 Apr 2022 11:20:10 +0100 Subject: [PATCH 09/11] remove gradle caching in GH actions. --- .github/workflows/main.yml | 13 ------------- .github/workflows/release.yml | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3ee78394..8b9dbbe8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,19 +26,6 @@ jobs: with: java-version: 11 - - name: Cache - uses: actions/cache@v2.0.0 - with: - # Cache gradle directories - path: | - ~/.gradle/caches/jars-3 - ~/.gradle/caches/modules-2/files-2.1/ - ~/.gradle/caches/modules-2/metadata-2.96/ - ~/.gradle/native - ~/.gradle/wrapper - # Key for restoring and saving the cache - key: ${{ runner.os }}-gradle - # Compile the code - name: Compile code run: ./gradlew assemble diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5610788f..f20e5025 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,19 +18,6 @@ jobs: with: java-version: 11 - - name: Cache - uses: actions/cache@v2.0.0 - with: - # A list of files, directories, and wildcard patterns to cache and restore - path: | - ~/.gradle/caches/jars-3 - ~/.gradle/caches/modules-2/files-2.1/ - ~/.gradle/caches/modules-2/metadata-2.96/ - ~/.gradle/native - ~/.gradle/wrapper - # An explicit key for restoring and saving the cache - key: ${{ runner.os }}-gradle - # Compile code - name: Compile code run: ./gradlew assemble From 9cf133862c8eab21a41b265dd5d69cf2a4bbeb4e Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Fri, 15 Apr 2022 11:26:13 +0100 Subject: [PATCH 10/11] fix jar --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 5f37377f..69a31e39 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,11 @@ bootJar { duplicatesStrategy = 'include' } +jar { + duplicatesStrategy = 'include' +} + + //apply from: 'gradle/liquibase.gradle' ext { From 2bc5d1ed7d96f0b7f2a18b493c4b052f5d30e573 Mon Sep 17 00:00:00 2001 From: yatharthranjan Date: Fri, 15 Apr 2022 11:32:54 +0100 Subject: [PATCH 11/11] use java gh action v3 with gradle caching --- .github/workflows/main.yml | 6 ++++-- .github/workflows/release.yml | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b9dbbe8..256284e3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,9 +22,11 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v3 with: - java-version: 11 + distribution: 'temurin' + java-version: '11' + cache: 'gradle' # Compile the code - name: Compile code diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f20e5025..ce3fa6de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,9 +14,12 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + + - uses: actions/setup-java@v3 with: - java-version: 11 + distribution: 'temurin' + java-version: '11' + cache: 'gradle' # Compile code - name: Compile code