diff --git a/core/src/main/java/com/abavilla/fpi/sms/codec/DCSCodingCodec.java b/core/src/main/java/com/abavilla/fpi/sms/codec/DCSCodingCodec.java index b179c63..4c2de4e 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/codec/DCSCodingCodec.java +++ b/core/src/main/java/com/abavilla/fpi/sms/codec/DCSCodingCodec.java @@ -18,17 +18,83 @@ package com.abavilla.fpi.sms.codec; -import com.abavilla.fpi.fw.codec.AbsEnumCodec; -import com.abavilla.fpi.sms.entity.enums.DCSCoding; +import java.lang.reflect.Method; -public class DCSCodingCodec extends AbsEnumCodec { +import com.vincejv.m360.dto.DCSCoding; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; +import org.bson.BsonReader; +import org.bson.BsonType; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; - public DCSCodingCodec() { - super(); +/** + * Codec for encoding and decoding {@link DCSCoding} enum to MongoDB Document + * + * @author Vince Villamora + */ +@NoArgsConstructor +public class DCSCodingCodec implements Codec { + + /** + * Document key name for the value node + */ + public static final String VALUE_KEY_NODE_NAME = "value"; + + /** + * Document key name for the enum id + */ + public static final String ORD_KEY_NODE_NAME = "ord"; + + /** + * {@inheritDoc} + */ + @SneakyThrows + @Override + public DCSCoding decode(BsonReader reader, DecoderContext decoderContext) { + reader.readStartDocument(); + int ord = Integer.MIN_VALUE; + while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) { + // decode only value type, ignore ord + String key = reader.readName(); + if (StringUtils.equals(key, VALUE_KEY_NODE_NAME)) { + reader.readString(); + } else if (StringUtils.equals(key, ORD_KEY_NODE_NAME)) { + ord = reader.readInt32(); + } else { + reader.skipValue(); + } + } + reader.readEndDocument(); + + Method fromValue = getEncoderClass().getDeclaredMethod("fromId", int.class); + return (DCSCoding) fromValue.invoke(null, ord); } + /** + * {@inheritDoc} + */ + @SneakyThrows + @Override + public void encode(BsonWriter writer, DCSCoding value, EncoderContext encoderContext) { + if (value != null) { + Method getId = getEncoderClass().getDeclaredMethod("getId"); + writer.writeStartDocument(); + writer.writeString(VALUE_KEY_NODE_NAME, value.toString()); + writer.writeInt32(ORD_KEY_NODE_NAME, (Integer) getId.invoke(value)); + writer.writeEndDocument(); + } + } + + /** + * {@inheritDoc} + */ @Override public Class getEncoderClass() { return DCSCoding.class; } + } diff --git a/core/src/main/java/com/abavilla/fpi/sms/codec/EnumCodecProvider.java b/core/src/main/java/com/abavilla/fpi/sms/codec/EnumCodecProvider.java index bf20eeb..c7ed1c5 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/codec/EnumCodecProvider.java +++ b/core/src/main/java/com/abavilla/fpi/sms/codec/EnumCodecProvider.java @@ -19,11 +19,11 @@ package com.abavilla.fpi.sms.codec; import com.abavilla.fpi.fw.codec.IEnumCodecProvider; -import com.abavilla.fpi.sms.entity.enums.DCSCoding; import com.abavilla.fpi.telco.ext.codec.ApiStatusCodec; import com.abavilla.fpi.telco.ext.codec.TelcoCodec; import com.abavilla.fpi.telco.ext.enums.ApiStatus; import com.abavilla.fpi.telco.ext.enums.Telco; +import com.vincejv.m360.dto.DCSCoding; import org.bson.codecs.Codec; public class EnumCodecProvider implements IEnumCodecProvider { diff --git a/core/src/main/java/com/abavilla/fpi/sms/codec/M360CodecProvider.java b/core/src/main/java/com/abavilla/fpi/sms/codec/M360CodecProvider.java deleted file mode 100644 index 574063f..0000000 --- a/core/src/main/java/com/abavilla/fpi/sms/codec/M360CodecProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************* - * FPI Application - Abavilla * - * Copyright (C) 2023 Vince Jerald Villamora * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see .* - *************************************************************************/ - -package com.abavilla.fpi.sms.codec; - -import java.util.ArrayList; -import java.util.List; - -import com.vincejv.m360.dto.ApiRequest; -import com.vincejv.m360.dto.BroadcastRequest; -import com.vincejv.m360.dto.SMSRequest; -import org.bson.codecs.Codec; -import org.bson.codecs.configuration.CodecProvider; -import org.bson.codecs.configuration.CodecRegistry; -import org.bson.codecs.pojo.ClassModel; -import org.bson.codecs.pojo.ClassModelBuilder; -import org.bson.codecs.pojo.PojoCodecProvider; - -/** - * MongoDB Codec registry, contains the codec for saving DVS API Objects to mongodb. - * - * @author Vince Villamora - */ -public class M360CodecProvider implements CodecProvider { - - private static final List> discriminatorClasses; - - private static final List ignoredFields; - - static { - discriminatorClasses = List.of( - ApiRequest.class, BroadcastRequest.class, SMSRequest.class - ); - - ignoredFields = List.of("appKey", "appSecret"); - } - - @Override - public Codec get(Class clazz, CodecRegistry registry) { - if (discriminatorClasses.contains(clazz)) { - return buildDiscriminatorCodec(clazz, registry); - } - return null; // Don't throw here, this tells - } - - private Codec buildDiscriminatorCodec(Class clazz, CodecRegistry registry) { - var discriminatorModelBuilder = ClassModel.builder(clazz) - .enableDiscriminator(true); - if (clazz == BroadcastRequest.class) { - stripNonProperties(discriminatorModelBuilder); - } - return PojoCodecProvider.builder() - .register(discriminatorModelBuilder.build()) - .build().get(clazz, registry); - } - - private void stripNonProperties(final ClassModelBuilder builder) { - List names = new ArrayList<>(); - - for (var property : builder.getPropertyModelBuilders()) { - var name = property.getName(); - if (ignoredFields.contains(name)) { - names.add(name); - } - } - - for (var name : names) { - builder.removeProperty(name); - } - } - -} diff --git a/core/src/main/java/com/abavilla/fpi/sms/config/ReflectionConfig.java b/core/src/main/java/com/abavilla/fpi/sms/config/ReflectionConfig.java index b15968c..eb812c4 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/config/ReflectionConfig.java +++ b/core/src/main/java/com/abavilla/fpi/sms/config/ReflectionConfig.java @@ -24,6 +24,7 @@ import com.vincejv.m360.dto.ApiResponse; import com.vincejv.m360.dto.BroadcastRequest; import com.vincejv.m360.dto.BroadcastResponse; +import com.vincejv.m360.dto.DCSCoding; import com.vincejv.m360.dto.ErrorResponse; import com.vincejv.m360.dto.PageInfo; import com.vincejv.m360.dto.SMSRequest; @@ -35,6 +36,7 @@ ApiResponse.class, BroadcastRequest.class, BroadcastResponse.class, + DCSCoding.class, ErrorResponse.class, PageInfo.class, SMSRequest.class, diff --git a/core/src/main/java/com/abavilla/fpi/sms/entity/enums/DCSCoding.java b/core/src/main/java/com/abavilla/fpi/sms/entity/enums/DCSCoding.java deleted file mode 100644 index 8e99d6e..0000000 --- a/core/src/main/java/com/abavilla/fpi/sms/entity/enums/DCSCoding.java +++ /dev/null @@ -1,91 +0,0 @@ -/****************************************************************************** - * FPI Application - Abavilla * - * Copyright (C) 2022 Vince Jerald Villamora * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ******************************************************************************/ - -package com.abavilla.fpi.sms.entity.enums; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; - -import com.abavilla.fpi.fw.entity.enums.IBaseEnum; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -import io.quarkus.runtime.annotations.RegisterForReflection; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -@RegisterForReflection -public enum DCSCoding implements IBaseEnum { - GSM0338(0, "GSM 03.38"), - ASCII(1, "ASCII"), - LATIN(3, "Latin 1 (ISO-8859-1)"), - UCS2(8, "UCS2 (ISO/IEC-10646)"), - UNKNOWN(-1, ""); - - /** - * Ordinal id to enum mapping - */ - private static final Map ENUM_MAP = new HashMap<>(); - - static { - for(IBaseEnum w : EnumSet.allOf(DCSCoding.class)) - ENUM_MAP.put(w.getId(), w); - } - - /** - * The enum ordinal id - */ - private final int id; - - /** - * The enum value - */ - private final String value; - - /** - * Creates an enum based from given string value - * - * @param value the string value - * @return the created enum - */ - @JsonCreator(mode = JsonCreator.Mode.DELEGATING) - public static DCSCoding fromValue(String value) { - return (DCSCoding) IBaseEnum.fromValue(value, ENUM_MAP, UNKNOWN); - } - - /** - * Creates an enum based from given an ordinal id - * - * @param id the ordinal id - * @return the created enum - */ - public static DCSCoding fromId(int id) { - return (DCSCoding) IBaseEnum.fromId(id, ENUM_MAP, UNKNOWN); - } - - /** - * {@inheritDoc} - */ - @Override - @JsonValue - public String toString() { - return value; - } -} diff --git a/core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequest.java b/core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequestEntity.java similarity index 90% rename from core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequest.java rename to core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequestEntity.java index ac06d81..55dcb07 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequest.java +++ b/core/src/main/java/com/abavilla/fpi/sms/entity/sms/BroadcastRequestEntity.java @@ -18,12 +18,13 @@ package com.abavilla.fpi.sms.entity.sms; -import com.abavilla.fpi.fw.entity.mongo.AbsMongoItem; -import com.abavilla.fpi.sms.entity.enums.DCSCoding; +import com.abavilla.fpi.fw.entity.mongo.AbsMongoField; +import com.vincejv.m360.dto.DCSCoding; import io.quarkus.runtime.annotations.RegisterForReflection; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import org.bson.codecs.pojo.annotations.BsonDiscriminator; import org.bson.codecs.pojo.annotations.BsonProperty; @@ -32,7 +33,8 @@ @RegisterForReflection @AllArgsConstructor @BsonDiscriminator -public class BroadcastRequest extends AbsMongoItem { +@NoArgsConstructor +public class BroadcastRequestEntity extends AbsMongoField { @BsonProperty("msisdn") private String mobileNumber; @@ -49,7 +51,4 @@ public class BroadcastRequest extends AbsMongoItem { @BsonProperty("dcs") private DCSCoding dataCodingScheme; - public BroadcastRequest() { - isInternational = false; - } } diff --git a/core/src/main/java/com/abavilla/fpi/sms/entity/sms/MsgReq.java b/core/src/main/java/com/abavilla/fpi/sms/entity/sms/MsgReq.java index 4a827d2..544684b 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/entity/sms/MsgReq.java +++ b/core/src/main/java/com/abavilla/fpi/sms/entity/sms/MsgReq.java @@ -21,9 +21,9 @@ import java.time.LocalDateTime; import java.util.List; +import com.abavilla.fpi.fw.entity.mongo.AbsMongoField; import com.abavilla.fpi.fw.entity.mongo.AbsMongoItem; import com.abavilla.fpi.telco.ext.enums.Telco; -import com.vincejv.m360.dto.ApiRequest; import io.quarkus.mongodb.panache.common.MongoEntity; import io.quarkus.runtime.annotations.RegisterForReflection; import lombok.Data; @@ -52,5 +52,5 @@ public class MsgReq extends AbsMongoItem { private List apiStatus; private List message; @BsonProperty(value = "request", useDiscriminator = true) - private ApiRequest broadcastRequest; + private AbsMongoField broadcastRequest; } diff --git a/core/src/main/java/com/abavilla/fpi/sms/mapper/sms/MsgReqMapper.java b/core/src/main/java/com/abavilla/fpi/sms/mapper/sms/MsgReqMapper.java index e6ad735..0c3d422 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/mapper/sms/MsgReqMapper.java +++ b/core/src/main/java/com/abavilla/fpi/sms/mapper/sms/MsgReqMapper.java @@ -18,31 +18,53 @@ package com.abavilla.fpi.sms.mapper.sms; +import com.abavilla.fpi.fw.entity.mongo.AbsMongoField; import com.abavilla.fpi.fw.mapper.IDtoToEntityMapper; import com.abavilla.fpi.sms.dto.api.m360.BroadcastResponseDto; +import com.abavilla.fpi.sms.entity.sms.BroadcastRequestEntity; import com.abavilla.fpi.sms.entity.sms.MsgReq; import com.abavilla.fpi.sms.ext.dto.MsgReqDto; import com.abavilla.fpi.telco.ext.enums.Telco; +import com.vincejv.m360.dto.ApiRequest; +import com.vincejv.m360.dto.BroadcastRequest; +import com.vincejv.m360.dto.SMSRequest; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.mapstruct.AfterMapping; import org.mapstruct.InjectionStrategy; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; import org.mapstruct.MappingTarget; @Mapper(componentModel = MappingConstants.ComponentModel.CDI, injectionStrategy = InjectionStrategy.CONSTRUCTOR) -public interface MsgReqMapper extends IDtoToEntityMapper { +public abstract class MsgReqMapper implements IDtoToEntityMapper { - @Override - MsgReqDto mapToDto(MsgReq msgReq); + @ConfigProperty(name = "ph.com.m360.sender-id") + String senderId; - @Override - MsgReq mapToEntity(MsgReqDto dto); + public abstract MsgReq mapFromResponse(BroadcastResponseDto broadcastResponseDto); + + AbsMongoField mapApiReqToBroadcastReqEntity(ApiRequest request) { + AbsMongoField entity = null; + if (request instanceof BroadcastRequest req) { + entity = mapBroadcastReqDtoToBroadcastReqEntity(req); + } else if (request instanceof SMSRequest req) { + entity = mapSMSReqToBroadcastReqEntity(req); + } + return entity; + } + + @Mapping(target = "senderId", expression = "java(senderId)") + abstract BroadcastRequestEntity mapSMSReqToBroadcastReqEntity(SMSRequest smsRequest); - MsgReq mapFromResponse(BroadcastResponseDto broadcastResponseDto); + + @Mapping(target = "senderId", expression = "java(senderId)") + abstract BroadcastRequestEntity mapBroadcastReqDtoToBroadcastReqEntity(BroadcastRequest smsRequest); @AfterMapping - default void afterMappingFromResponse(BroadcastResponseDto broadcastResponseDto, @MappingTarget MsgReq msgReq) { + void afterMappingFromResponse(BroadcastResponseDto broadcastResponseDto, @MappingTarget MsgReq msgReq) { msgReq.setTelco(Telco.fromId(broadcastResponseDto.getTelcoId())); } + } diff --git a/core/src/main/java/com/abavilla/fpi/sms/service/sms/M360Svc.java b/core/src/main/java/com/abavilla/fpi/sms/service/sms/M360Svc.java index 34ce084..a18571a 100644 --- a/core/src/main/java/com/abavilla/fpi/sms/service/sms/M360Svc.java +++ b/core/src/main/java/com/abavilla/fpi/sms/service/sms/M360Svc.java @@ -23,10 +23,8 @@ import com.abavilla.fpi.fw.exceptions.ApiSvcEx; import com.abavilla.fpi.fw.service.ISvc; import com.abavilla.fpi.sms.dto.api.m360.BroadcastResponseDto; -import com.abavilla.fpi.sms.entity.enums.DCSCoding; import com.abavilla.fpi.sms.ext.dto.MsgReqDto; import com.abavilla.fpi.sms.mapper.m360.BroadcastResponseMapper; -import com.abavilla.fpi.sms.util.SMSUtil; import com.vincejv.m360.M360ApiClient; import com.vincejv.m360.dto.ApiError; import com.vincejv.m360.dto.SMSRequest; @@ -48,11 +46,8 @@ public class M360Svc implements ISvc { public Uni sendMsg(MsgReqDto msgReqDto) { Log.debug("m360 message request: " + msgReqDto); - var smsRequest = new SMSRequest(); - smsRequest.setMobileNumber(msgReqDto.getMobileNumber()); - smsRequest.setContent(msgReqDto.getContent()); - smsRequest.setDataCodingScheme(SMSUtil.isEncodeableInGsm0338(msgReqDto.getContent()) ? - DCSCoding.GSM0338.getId() : DCSCoding.UCS2.getId()); + var smsRequest = new SMSRequest(msgReqDto.getMobileNumber(), + msgReqDto.getContent()); var m360Resp = Uni.createFrom().future(() -> m360client.sendBroadcastMessage(smsRequest)); diff --git a/core/src/main/java/com/abavilla/fpi/sms/util/SMSUtil.java b/core/src/main/java/com/abavilla/fpi/sms/util/SMSUtil.java deleted file mode 100644 index 20ad135..0000000 --- a/core/src/main/java/com/abavilla/fpi/sms/util/SMSUtil.java +++ /dev/null @@ -1,71 +0,0 @@ -/****************************************************************************** - * FPI Application - Abavilla * - * Copyright (C) 2022 Vince Jerald Villamora * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ******************************************************************************/ - -package com.abavilla.fpi.sms.util; - -import java.util.HashSet; -import java.util.Set; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class SMSUtil { - private static final char[] BASIC_CHARS = { - // Basic Character Set - '@', '£', '$', '¥', 'è', 'é', 'ù', 'ì', 'ò', 'Ç', '\n', 'Ø', 'ø', '\r', 'Å', 'å', - 'Δ', '_', 'Φ', 'Γ', 'Λ', 'Ω', 'Π', 'Ψ', 'Σ', 'Θ', 'Ξ', 'Æ', 'æ', 'ß', 'É', - ' ', '!', '"', '#', '¤', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', - '¡', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ñ', 'Ü', '§', - '¿', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'ä', 'ö', 'ñ', 'ü', 'à', - // Basic Character Set Extension - '\f', '^', '{', '}', '\\', '[', '~', ']', '|', '€' - }; - - private static final boolean[] ENCODEABLE_BY_ORD_UP_TO_253 = new boolean[254]; - private static final Set ENCODEABLE_REST = new HashSet<>(); - static { - for (char ch : BASIC_CHARS) { - if (ch <= 253) { - ENCODEABLE_BY_ORD_UP_TO_253[ch] = true; - } else { - ENCODEABLE_REST.add(ch); - } - } - } - - public static boolean isEncodeableInGsm0338(String msg) { - final int length = msg.length(); - for (int i = 0; i < length; ++i) { - char ch = msg.charAt(i); - if (ch <= 253) { - if (!ENCODEABLE_BY_ORD_UP_TO_253[ch]) { - return false; - } - } else { - if (!ENCODEABLE_REST.contains(ch)) { - return false; - } - } - } - return true; - } -} diff --git a/pom.xml b/pom.xml index c3ada08..fe07e02 100644 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,7 @@ com.vincejv m360-api-client - 1.0.7 + 1.0.9