diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c3ea3b4..cad523af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,8 @@ version: 2.1 jobs: build: - docker: - - image: circleci/openjdk:8-jdk - working_directory: ~/project + machine: + image: ubuntu-2004:202008-01 steps: - checkout - restore_cache: @@ -21,4 +20,4 @@ workflows: version: 2.1 workflow: jobs: - - build + - build \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c8c4c730..8ce7af14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8-jre-alpine +FROM adoptopenjdk/openjdk11:alpine-slim RUN apk update \ && apk add unzip \ && apk add curl \ @@ -10,4 +10,4 @@ RUN chown -R sunbird:sunbird /home/sunbird USER sunbird EXPOSE 9000 WORKDIR /home/sunbird/ -CMD java -cp '/home/sunbird/notification-service-1.0.0/lib/*' play.core.server.ProdServerStart /home/sunbird/notification-service-1.0.0 +CMD java -XX:+PrintFlagsFinal $JAVA_OPTIONS -Dplay.server.http.idleTimeout=180s -cp '/home/sunbird/notification-service-1.0.0/lib/*' play.core.server.ProdServerStart /home/sunbird/notification-service-1.0.0 diff --git a/Jenkinsfile b/Jenkinsfile index e736ae91..4207bd72 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,54 +7,46 @@ node('build-slave') { String ANSI_YELLOW = "\u001B[33m" ansiColor('xterm') { - stage('Checkout') { - if (!env.hub_org) { - println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) - error 'Please resolve the errors and rerun..' - } else - println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) - } - cleanWs() - if (params.github_release_tag == "") { + withEnv(["JAVA_HOME=${JAVA11_HOME}"]) { + stage('Checkout') { + if (!env.hub_org) { + println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) + error 'Please resolve the errors and rerun..' + } else + println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) + } + cleanWs() checkout scm commit_hash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() - branch_name = sh(script: 'git name-rev --name-only HEAD | rev | cut -d "/" -f1| rev', returnStdout: true).trim() - build_tag = branch_name + "_" + commit_hash - println(ANSI_BOLD + ANSI_YELLOW + "github_release_tag not specified, using the latest commit hash: " + commit_hash + ANSI_NORMAL) - } else { - def scmVars = checkout scm - checkout scm: [$class: 'GitSCM', branches: [[name: "refs/tags/$params.github_release_tag"]], userRemoteConfigs: [[url: scmVars.GIT_URL]]] - build_tag = params.github_release_tag - println(ANSI_BOLD + ANSI_YELLOW + "github_release_tag specified, building from tag: " + params.github_release_tag + ANSI_NORMAL) - } - echo "build_tag: " + build_tag + build_tag = sh(script: "echo " + params.github_release_tag.split('/')[-1] + "_" + commit_hash + "_" + env.BUILD_NUMBER, returnStdout: true).trim() + echo "build_tag: " + build_tag - stage('Build') { - currentDir = sh(returnStdout: true, script: 'pwd').trim() - env.NODE_ENV = "build" - print "Environment will be : ${env.NODE_ENV}" - sh 'git log -1' - sh "cd $currentDir" - // Build the dependencies for sunbird user-org service - sh 'mvn clean install' - } - stage('Package') { - // Create a deployment package - dir('service') { - sh 'mvn play2:dist' - sh 'cp target/notification-service-1.0.0-dist.zip ../' + stage('Build') { + currentDir = sh(returnStdout: true, script: 'pwd').trim() + env.NODE_ENV = "build" + print "Environment will be : ${env.NODE_ENV}" + sh 'git log -1' + sh "cd $currentDir" + // Build the dependencies for sunbird user-org service + sh 'mvn clean install' + } + stage('Package') { + // Create a deployment package + dir('service') { + sh 'mvn play2:dist' + sh 'cp target/notification-service-1.0.0-dist.zip ../' + } + sh('chmod 777 ./build.sh') + sh("./build.sh ${build_tag} ${env.NODE_NAME} ${hub_org}") + } + stage('ArchiveArtifacts') { + archiveArtifacts "metadata.json" + currentBuild.description = "${build_tag}" } - sh('chmod 777 ./build.sh') - sh("./build.sh ${build_tag} ${env.NODE_NAME} ${hub_org}") - } - stage('ArchiveArtifacts') { - archiveArtifacts "metadata.json" - currentBuild.description = "${build_tag}" } } - } - catch (err) { + } catch (err) { currentBuild.result = "FAILURE" throw err } -} +} \ No newline at end of file diff --git a/all-actors/src/main/java/org/sunbird/BaseActor.java b/all-actors/src/main/java/org/sunbird/BaseActor.java index 4c67294e..c43afe41 100644 --- a/all-actors/src/main/java/org/sunbird/BaseActor.java +++ b/all-actors/src/main/java/org/sunbird/BaseActor.java @@ -1,10 +1,10 @@ package org.sunbird; import akka.actor.UntypedAbstractActor; -import org.apache.log4j.Logger; import org.sunbird.message.IResponseMessage; import org.sunbird.message.Localizer; import org.sunbird.message.ResponseCode; +import org.sunbird.request.LoggerUtil; import org.sunbird.request.Request; import java.util.Locale; @@ -14,7 +14,7 @@ */ public abstract class BaseActor extends UntypedAbstractActor { - private Logger logger = Logger.getLogger(BaseActor.class); + private static LoggerUtil logger = new LoggerUtil(BaseActor.class); public abstract void onReceive(Request request) throws Throwable; protected Localizer localizer = Localizer.getInstance(); @@ -23,11 +23,11 @@ public void onReceive(Object message) throws Throwable { if (message instanceof Request) { Request request = (Request) message; String operation = request.getOperation(); - logger.info("BaseActor:onReceive called for operation:" + operation); + logger.info(request.getRequestContext(),"BaseActor:onReceive called for operation:" + operation); try { - logger.info(String.format("%s:%s:method started at %s",this.getClass().getSimpleName(),operation,System.currentTimeMillis())); + logger.info(request.getRequestContext(),String.format("%s:%s:method started at %s",this.getClass().getSimpleName(),operation,System.currentTimeMillis())); onReceive(request); - logger.info(String.format("%s:%s:method ended at %s",this.getClass().getSimpleName(),operation,System.currentTimeMillis())); + logger.info(request.getRequestContext(),String.format("%s:%s:method ended at %s",this.getClass().getSimpleName(),operation,System.currentTimeMillis())); } catch (Exception e) { onReceiveException(operation, e); } diff --git a/all-actors/src/main/java/org/sunbird/NotificationRequestMapper.java b/all-actors/src/main/java/org/sunbird/NotificationRequestMapper.java index 4d458e45..ef377a80 100644 --- a/all-actors/src/main/java/org/sunbird/NotificationRequestMapper.java +++ b/all-actors/src/main/java/org/sunbird/NotificationRequestMapper.java @@ -5,17 +5,16 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; import org.sunbird.message.IResponseMessage; import org.sunbird.message.ResponseCode; import org.sunbird.pojo.NotificationRequest; +import org.sunbird.request.LoggerUtil; public class NotificationRequestMapper { private static ObjectMapper mapper = new ObjectMapper(); - private static Logger logger = LogManager.getLogger(NotificationRequestMapper.class); + private static LoggerUtil logger = new LoggerUtil(NotificationRequestMapper.class); /** * maps request to notification request @@ -44,7 +43,6 @@ private static NotificationRequest getNotificationRequest(Map da try { NotificationRequest notificationRequest = mapper.convertValue(data, NotificationRequest.class); - logger.info("Notification request , " + notificationRequest.toString()); return notificationRequest; } catch (Exception e) { throw new BaseException( diff --git a/all-actors/src/main/java/org/sunbird/notification/actor/NotificationActor.java b/all-actors/src/main/java/org/sunbird/notification/actor/NotificationActor.java index 6d096861..18544ea1 100644 --- a/all-actors/src/main/java/org/sunbird/notification/actor/NotificationActor.java +++ b/all-actors/src/main/java/org/sunbird/notification/actor/NotificationActor.java @@ -6,8 +6,6 @@ import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; import org.sunbird.ActorServiceException; import org.sunbird.BaseActor; import org.sunbird.BaseException; @@ -19,11 +17,10 @@ import org.sunbird.message.IUserResponseMessage; import org.sunbird.message.ResponseCode; import org.sunbird.notification.beans.OTPRequest; -import org.sunbird.notification.dispatcher.INotificationDispatcher; import org.sunbird.notification.dispatcher.NotificationRouter; -import org.sunbird.notification.dispatcher.impl.FCMNotificationDispatcher; import org.sunbird.notification.utils.NotificationConstant; import org.sunbird.pojo.NotificationRequest; +import org.sunbird.request.LoggerUtil; import org.sunbird.request.Request; import org.sunbird.response.Response; import org.sunbird.util.validator.OtpRequestValidator; @@ -31,17 +28,16 @@ /** @author manzarul */ @ActorConfig( tasks = {JsonKey.NOTIFICATION, JsonKey.VERIFY_OTP}, - asyncTasks = {} + asyncTasks = {}, + dispatcher= "notification-dispatcher" ) public class NotificationActor extends BaseActor { - Logger logger = LogManager.getLogger(NotificationActor.class); - private static final String NOTIFICATION = JsonKey.NOTIFICATION; - INotificationDispatcher Dispatcher = new FCMNotificationDispatcher(); + private static LoggerUtil logger = new LoggerUtil(NotificationActor.class); @Override public void onReceive(Request request) throws Throwable { String operation = request.getOperation(); - if (NOTIFICATION.equalsIgnoreCase(operation)) { + if (JsonKey.NOTIFICATION.equalsIgnoreCase(operation)) { notify(request); } else if (JsonKey.VERIFY_OTP.equalsIgnoreCase(operation)) { verifyOtp(request); @@ -49,12 +45,12 @@ public void onReceive(Request request) throws Throwable { } else { onReceiveUnsupportedMessage(request.getOperation()); } - logger.info("onReceive method call End"); + logger.info(request.getRequestContext(),"onReceive method call End"); } public void notify(Request request) throws BaseException { boolean isSyncDelivery = false; - logger.info("Call started for notify method"); + logger.info(request.getRequestContext(),"Call started for notify method"); List notificationRequestList = NotificationRequestMapper.toList( (List>) request.getRequest().get(JsonKey.NOTIFICATIONS)); @@ -71,13 +67,13 @@ public void notify(Request request) throws BaseException { if (StringUtils.isNotBlank(deliveryMode) && "sync".equalsIgnoreCase(deliveryMode)) { isSyncDelivery = true; } - Response response = routes.route(notificationRequestList, false, isSyncDelivery); - logger.info("response got from notification service " + response); + Response response = routes.route(notificationRequestList, false, isSyncDelivery, request.getRequestContext()); + logger.info(request.getRequestContext(),"response got from notification service " + response); sender().tell(response, getSelf()); } public void verifyOtp(Request request) throws BaseException { - logger.info("call started for verify otp method"); + logger.info(request.getRequestContext(),"call started for verify otp method"); Map requestMap = request.getRequest(); boolean response = OtpRequestValidator.isOtpVerifyRequestValid( @@ -99,8 +95,8 @@ public void verifyOtp(Request request) throws BaseException { 0, null, (String) request.get(NotificationConstant.VALUE)); - Response responseData = routes.verifyOtp(otpRequest); - logger.info("response got from notification service " + response); + Response responseData = routes.verifyOtp(otpRequest, request.getRequestContext()); + logger.info(request.getRequestContext(),"response got from notification service " + response); sender().tell(responseData, getSelf()); } } diff --git a/all-actors/src/main/java/org/sunbird/notification/dispatcher/INotificationDispatcher.java b/all-actors/src/main/java/org/sunbird/notification/dispatcher/INotificationDispatcher.java index d3e676a4..585cacf6 100644 --- a/all-actors/src/main/java/org/sunbird/notification/dispatcher/INotificationDispatcher.java +++ b/all-actors/src/main/java/org/sunbird/notification/dispatcher/INotificationDispatcher.java @@ -3,6 +3,7 @@ import org.sunbird.notification.utils.FCMResponse; import org.sunbird.pojo.NotificationRequest; +import org.sunbird.request.RequestContext; /** * This interface is responsible for handling different mode of notification @@ -11,5 +12,5 @@ */ public interface INotificationDispatcher { - public FCMResponse dispatch(NotificationRequest data, boolean isDryRun, boolean isSync); + public FCMResponse dispatch(NotificationRequest data, boolean isDryRun, boolean isSync, RequestContext context); } diff --git a/all-actors/src/main/java/org/sunbird/notification/dispatcher/NotificationRouter.java b/all-actors/src/main/java/org/sunbird/notification/dispatcher/NotificationRouter.java index c1992ad3..a097dcba 100644 --- a/all-actors/src/main/java/org/sunbird/notification/dispatcher/NotificationRouter.java +++ b/all-actors/src/main/java/org/sunbird/notification/dispatcher/NotificationRouter.java @@ -14,10 +14,9 @@ import java.util.Properties; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; import org.apache.velocity.app.VelocityEngine; import org.sunbird.ActorServiceException; import org.sunbird.BaseException; @@ -30,24 +29,25 @@ import org.sunbird.notification.dispatcher.impl.FCMNotificationDispatcher; import org.sunbird.notification.sms.provider.ISmsProvider; import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderFactory; -import org.sunbird.notification.utils.FCMResponse; import org.sunbird.notification.utils.NotificationConstant; import org.sunbird.notification.utils.Util; import org.sunbird.pojo.Config; import org.sunbird.pojo.NotificationRequest; import org.sunbird.pojo.OTP; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; import org.sunbird.response.Response; import org.sunbird.util.Constant; /** - * mojut6de4rnj, * * @author manzarul */ public class NotificationRouter { - private static Logger logger = LogManager.getLogger(NotificationRouter.class); + private static LoggerUtil logger = new LoggerUtil(NotificationRouter.class); private static final String TEMPLATE_SUFFIX = ".vm"; private SyncMessageDispatcher syDispatcher = new SyncMessageDispatcher(); + private ObjectMapper mapper = new ObjectMapper(); enum DeliveryMode { phone, @@ -62,23 +62,21 @@ enum DeliveryType { call; } - Msg91SmsProviderFactory mesg91ObjectFactory = new Msg91SmsProviderFactory(); private ISmsProvider smsProvider = null; - INotificationDispatcher FcmDispatcher = new FCMNotificationDispatcher(); - ObjectMapper mapper = new ObjectMapper(); private ISmsProvider getSMSInstance() { if (smsProvider == null) { SMSConfig config = new SMSConfig(System.getenv(NotificationConstant.SUNBIRD_MSG_91_AUTH), ""); + Msg91SmsProviderFactory mesg91ObjectFactory = new Msg91SmsProviderFactory(); smsProvider = mesg91ObjectFactory.create(config); } return smsProvider; } public Response route( - List notificationRequestList, boolean isDryRun, boolean isSync) + List notificationRequestList, boolean isDryRun, boolean isSync, RequestContext context) throws BaseException { - logger.info("making call to route method"); + logger.info(context, "making call to route method"); Response response = new Response(); if (CollectionUtils.isNotEmpty(notificationRequestList)) { Map responseMap = new HashMap(); @@ -86,9 +84,9 @@ public Response route( if (notification.getMode().equalsIgnoreCase(DeliveryMode.phone.name()) && (notification.getDeliveryType().equalsIgnoreCase(DeliveryType.message.name()) || notification.getDeliveryType().equalsIgnoreCase(DeliveryType.otp.name()))) { - response = handleMessageAndOTP(notification, isDryRun, responseMap, isSync); + response = handleMessageAndOTP(notification, isDryRun, responseMap, isSync, context); } else if (notification.getMode().equalsIgnoreCase(DeliveryMode.device.name())) { - response = writeDataToKafa(notification, response, isDryRun, responseMap, isSync); + response = writeDataToKafka(notification, response, isDryRun, responseMap, isSync, context); } else if (notification.getMode().equalsIgnoreCase(DeliveryMode.email.name()) && notification.getDeliveryType().equalsIgnoreCase(DeliveryType.message.name())) { String message = null; @@ -96,22 +94,22 @@ public Response route( && StringUtils.isNotBlank(notification.getTemplate().getData())) { message = getMessage( - notification.getTemplate().getData(), notification.getTemplate().getParams()); + notification.getTemplate().getData(), notification.getTemplate().getParams(), context); notification.getTemplate().setData(message); } else if (notification.getTemplate() != null && StringUtils.isNotBlank(notification.getTemplate().getId())) { - String data = createNotificationBody(notification); + String data = createNotificationBody(notification, context); notification.getTemplate().setData(data); } if (isSync) { - response = syDispatcher.syncDispatch(notification, isDryRun); + response = syDispatcher.syncDispatch(notification, isDryRun, context); } else { - response = writeDataToKafa(notification, response, isDryRun, responseMap, isSync); + response = writeDataToKafka(notification, response, isDryRun, responseMap, isSync, context); } } } } else { - logger.info( + logger.info(context, "requested notification list is either null or empty :" + notificationRequestList); } return response; @@ -121,14 +119,15 @@ private Response handleMessageAndOTP( NotificationRequest notification, boolean isDryRun, Map responseMap, - boolean isSync) + boolean isSync, + RequestContext context) throws BaseException { Response response = new Response(); String message = null; if (notification.getTemplate() != null && StringUtils.isNotBlank(notification.getTemplate().getData())) { message = - getMessage(notification.getTemplate().getData(), notification.getTemplate().getParams()); + getMessage(notification.getTemplate().getData(), notification.getTemplate().getParams(), context); } Config config = notification.getConfig(); @@ -145,7 +144,7 @@ private Response handleMessageAndOTP( } OTPRequest request = new OTPRequest(ids.get(0), null, otp.getLength(), otp.getExpiryInMinute(), message, null); - boolean smsResponse = getSMSInstance().sendOtp(request); + boolean smsResponse = getSMSInstance().sendOtp(request, context); responseMap.put(ids.get(0), smsResponse); response.putAll(responseMap); } else { @@ -153,20 +152,20 @@ private Response handleMessageAndOTP( notification.getTemplate().setData(message); } if (isSync) { - response = syDispatcher.syncDispatch(notification, isDryRun); + response = syDispatcher.syncDispatch(notification, isDryRun, context); } else { - response = writeDataToKafa(notification, response, isDryRun, responseMap, isSync); + response = writeDataToKafka(notification, response, isDryRun, responseMap, isSync, context); } } return response; } - private String createNotificationBody(NotificationRequest notification) throws BaseException { - return readVm(notification.getTemplate().getId(), notification.getTemplate().getParams()); + private String createNotificationBody(NotificationRequest notification, RequestContext context) throws BaseException { + return readVm(notification.getTemplate().getId(), notification.getTemplate().getParams(), context); } - private String readVm(String templateName, JsonNode node) throws BaseException { + private String readVm(String templateName, JsonNode node, RequestContext requestContext) throws BaseException { VelocityEngine engine = new VelocityEngine(); VelocityContext context = getContextObj(node); Properties p = new Properties(); @@ -183,7 +182,7 @@ private String readVm(String templateName, JsonNode node) throws BaseException { template.merge(context, writer); body = writer.toString(); } catch (Exception e) { - logger.error("Failed to load velocity template =" + templateName + " " + e.getMessage(), e); + logger.error(requestContext,"Failed to load velocity template =" + templateName + " " + e.getMessage(), e); throw new ActorServiceException.InvalidRequestData( IUserResponseMessage.TEMPLATE_NOT_FOUND, MessageFormat.format( @@ -195,15 +194,15 @@ private String readVm(String templateName, JsonNode node) throws BaseException { try { writer.close(); } catch (IOException e) { - logger.error("Failed to closed writer object =" + e.getMessage(), e); + logger.error(requestContext,"Failed to closed writer object =" + e.getMessage(), e); } } } return body; } - public Response verifyOtp(OTPRequest otpRequest) { - boolean verificationResp = getSMSInstance().verifyOtp(otpRequest); + public Response verifyOtp(OTPRequest otpRequest, RequestContext context) { + boolean verificationResp = getSMSInstance().verifyOtp(otpRequest, context); Response response = new Response(); if (verificationResp) { response.put(NotificationConstant.MESSAGE, NotificationConstant.SUCCESS); @@ -213,29 +212,42 @@ public Response verifyOtp(OTPRequest otpRequest) { return response; } - private Response writeDataToKafa( + private Response writeDataToKafka( NotificationRequest notification, Response response, boolean isDryRun, Map responseMap, - boolean isSync) { - FCMResponse responses = FcmDispatcher.dispatch(notification, isDryRun, isSync); - logger.info("response from FCM " + responses); + boolean isSync, + RequestContext context) { + FCMNotificationDispatcher.getInstance().dispatch(notification, isDryRun, isSync, context); + logger.info(context, "Got response from FCM "); responseMap.put(Constant.RESPONSE, NotificationConstant.SUCCESS); response.putAll(responseMap); return response; } - private String getMessage(String message, JsonNode node) { + private String getMessage(String message, JsonNode node, RequestContext requestContext) { + VelocityContext context = new VelocityContext(); if (node != null) { Map paramValue = mapper.convertValue(node, Map.class); Iterator> itr = paramValue.entrySet().iterator(); while (itr.hasNext()) { Entry entry = itr.next(); - message = message.replace("$" + entry.getKey(), entry.getValue()); + if (null != entry.getValue()) { + context.put(entry.getKey(), entry.getValue()); + } } } - return message; + StringWriter writer = null; + try { + Velocity.init(); + writer = new StringWriter(); + Velocity.evaluate(context, writer, "SimpleVelocity", message); + } catch (Exception e) { + logger.error(requestContext, + "NotificationRouter:getMessage : Exception occurred with message =" + e.getMessage(), e); + } + return writer.toString(); } private VelocityContext getContextObj(JsonNode node) { diff --git a/all-actors/src/main/java/org/sunbird/notification/dispatcher/SyncMessageDispatcher.java b/all-actors/src/main/java/org/sunbird/notification/dispatcher/SyncMessageDispatcher.java index 7675be13..564c0201 100644 --- a/all-actors/src/main/java/org/sunbird/notification/dispatcher/SyncMessageDispatcher.java +++ b/all-actors/src/main/java/org/sunbird/notification/dispatcher/SyncMessageDispatcher.java @@ -11,6 +11,7 @@ import org.sunbird.notification.sms.provider.ISmsProvider; import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderFactory; import org.sunbird.pojo.NotificationRequest; +import org.sunbird.request.RequestContext; import org.sunbird.response.Response; import org.sunbird.util.Constant; @@ -20,16 +21,16 @@ public class SyncMessageDispatcher { private IEmailService emailservice; private ISmsProvider smsProvider; - public Response syncDispatch(NotificationRequest notification, boolean isDryRun) { + public Response syncDispatch(NotificationRequest notification, boolean isDryRun, RequestContext context) { if (notification.getMode().equalsIgnoreCase(DeliveryMode.phone.name()) && notification.getDeliveryType().equalsIgnoreCase(DeliveryType.message.name())) { - return syncMessageDispatch(notification, isDryRun); + return syncMessageDispatch(notification, isDryRun, context); } - return syncEmailDispatch(notification, isDryRun); + return syncEmailDispatch(notification, isDryRun, context); } - private Response syncEmailDispatch(NotificationRequest notificationRequest, boolean isDryRun) { + private Response syncEmailDispatch(NotificationRequest notificationRequest, boolean isDryRun, RequestContext context) { EmailRequest request = new EmailRequest( notificationRequest.getConfig().getSubject(), @@ -39,17 +40,17 @@ private Response syncEmailDispatch(NotificationRequest notificationRequest, bool null, notificationRequest.getTemplate().getData(), null); - boolean emailResponse = getEmailInstance().sendEmail(request); + boolean emailResponse = getEmailInstance().sendEmail(request, context); Response response = new Response(); response.put(Constant.RESPONSE, emailResponse); return response; } - private Response syncMessageDispatch(NotificationRequest notificationRequest, boolean isDryRun) { + private Response syncMessageDispatch(NotificationRequest notificationRequest, boolean isDryRun, RequestContext context) { Response response = new Response(); boolean smsResponse = getSmsInstance() - .bulkSms(notificationRequest.getIds(), notificationRequest.getTemplate().getData()); + .bulkSms(notificationRequest.getIds(), notificationRequest.getTemplate().getData(), context); response.put(Constant.RESPONSE, smsResponse); return response; } diff --git a/all-actors/src/main/java/org/sunbird/notification/dispatcher/impl/FCMNotificationDispatcher.java b/all-actors/src/main/java/org/sunbird/notification/dispatcher/impl/FCMNotificationDispatcher.java index 349d7d67..bbdfb21e 100644 --- a/all-actors/src/main/java/org/sunbird/notification/dispatcher/impl/FCMNotificationDispatcher.java +++ b/all-actors/src/main/java/org/sunbird/notification/dispatcher/impl/FCMNotificationDispatcher.java @@ -12,14 +12,14 @@ import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; import org.sunbird.notification.dispatcher.INotificationDispatcher; import org.sunbird.notification.fcm.provider.IFCMNotificationService; import org.sunbird.notification.fcm.provider.NotificationFactory; import org.sunbird.notification.utils.FCMResponse; import org.sunbird.pojo.*; import org.sunbird.pojo.KafkaMessage; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; import org.sunbird.util.ConfigUtil; import org.sunbird.util.Constant; import org.sunbird.util.DataHash; @@ -27,65 +27,80 @@ /** @author manzarul */ public class FCMNotificationDispatcher implements INotificationDispatcher { - private static Logger logger = LogManager.getLogger(FCMNotificationDispatcher.class); + private static LoggerUtil logger = new LoggerUtil(FCMNotificationDispatcher.class); private IFCMNotificationService service = - NotificationFactory.getInstance(NotificationFactory.instanceType.httpClinet.name()); - private static final String RAW_DATA = "rawData"; - private static ObjectMapper mapper = new ObjectMapper(); - String topic = null; - String BOOTSTRAP_SERVERS = null; - Producer producer = null; - private static final int BATCH_SIZE = 100; + NotificationFactory.getInstance(NotificationFactory.instanceType.httpClinet.name()); + private ObjectMapper mapper = new ObjectMapper(); + private String topic = null; + private Producer producer = null; + private final int BATCH_SIZE = 100; + private static FCMNotificationDispatcher instance; + + public static FCMNotificationDispatcher getInstance() { + if (null == instance) { + synchronized (FCMNotificationDispatcher.class) { + if (null == instance) { + instance = new FCMNotificationDispatcher(); + } + } + } + return instance; + } + + private FCMNotificationDispatcher() { + initKafkaClient(); + } - @Override /** * This map will have key as ids/topic and rawData. ids will have list of device registration ids. * topic :it will contains name of fcm topic either ids or topic one key is mandatory. and data * will have complete data that need to sent. */ - public FCMResponse dispatch(NotificationRequest notification, boolean isDryRun, boolean isSync) { + @Override + public FCMResponse dispatch(NotificationRequest notification, boolean isDryRun, boolean isSync, RequestContext context) { if (isSync) { - return dispatchSync(notification, isDryRun); + return dispatchSync(notification, isDryRun, context); } else { - return dispatchAsync(notification); + return dispatchAsync(notification, context); } } - private FCMResponse dispatchSync(NotificationRequest notification, boolean isDryRun) { + private FCMResponse dispatchSync(NotificationRequest notification, boolean isDryRun, RequestContext context) { org.sunbird.pojo.Config config = null; if (notification.getIds() == null || notification.getIds().size() == 0) { config = notification.getConfig(); if (StringUtils.isBlank(config.getTopic())) { - throw new RuntimeException("neither device registration id nore topic found in request"); + throw new RuntimeException("neither device registration id nor topic found in request"); } } FCMResponse response = null; try { String notificationData = mapper.writeValueAsString(notification.getRawData()); Map map = new HashMap(); + String RAW_DATA = "rawData"; map.put(RAW_DATA, notificationData); if (config != null && StringUtils.isNotBlank(config.getTopic())) { - response = service.sendTopicNotification(config.getTopic(), map, isDryRun); + response = service.sendTopicNotification(config.getTopic(), map, isDryRun, context); } else { if (notification.getIds().size() <= BATCH_SIZE) { - response = service.sendMultiDeviceNotification(notification.getIds(), map, isDryRun); + response = service.sendMultiDeviceNotification(notification.getIds(), map, isDryRun, context); } else { // Split into 100 batch List tmp = new ArrayList(); for (int i = 0; i < notification.getIds().size(); i++) { tmp.add(notification.getIds().get(i)); if (tmp.size() == BATCH_SIZE || i == (notification.getIds().size() - 1)) { - response = service.sendMultiDeviceNotification(tmp, map, isDryRun); + response = service.sendMultiDeviceNotification(tmp, map, isDryRun, context); tmp.clear(); - logger.info("sending message in 100 batch."); + logger.info(context, "sending message in 100 batch."); } } } } } catch (JsonProcessingException e) { - logger.error("Error during fcm notification processing." + e.getMessage()); + logger.error(context,"Error during fcm notification processing." + e.getMessage(), e); e.printStackTrace(); } return response; @@ -95,55 +110,54 @@ private FCMResponse dispatchSync(NotificationRequest notification, boolean isDry private void initKafkaClient() { if (producer == null) { Config config = ConfigUtil.getConfig(); - BOOTSTRAP_SERVERS = config.getString(Constant.SUNBIRD_NOTIFICATION_KAFKA_SERVICE_CONFIG); + String BOOTSTRAP_SERVERS = config.getString(Constant.SUNBIRD_NOTIFICATION_KAFKA_SERVICE_CONFIG); topic = config.getString(Constant.SUNBIRD_NOTIFICATION_KAFKA_TOPIC); logger.info( - "KafkaTelemetryDispatcherActor:initKafkaClient: Bootstrap servers = " + "FCMNotificationDispatcher:initKafkaClient: Bootstrap servers = " + BOOTSTRAP_SERVERS); - logger.info("UserMergeActor:initKafkaClient: topic = " + topic); + logger.info("FCMNotificationDispatcher:initKafkaClient: topic = " + topic); try { producer = KafkaClient.createProducer( BOOTSTRAP_SERVERS, Constant.KAFKA_CLIENT_NOTIFICATION_PRODUCER); } catch (Exception e) { - logger.error("UserMergeActor:initKafkaClient: An exception occurred.", e); + logger.error("FCMNotificationDispatcher:initKafkaClient: An exception occurred.", e); } } } - private FCMResponse dispatchAsync(NotificationRequest notification) { - initKafkaClient(); + private FCMResponse dispatchAsync(NotificationRequest notification, RequestContext context) { FCMResponse response = null; if (CollectionUtils.isNotEmpty(notification.getIds())) { if (notification.getIds().size() <= BATCH_SIZE) { - String message = getTopicMessage(notification); - response = writeDataToKafka(message, topic); - logger.info("device id size is less than Batch size " + BATCH_SIZE); + String message = getTopicMessage(notification, context); + response = writeDataToKafka(message, topic, context); + logger.info(context, "device id size is less than Batch size"); } else { List deviceIds = notification.getIds(); - logger.info( - "device id size is less more than Batch size " + BATCH_SIZE + " - " + deviceIds.size()); + logger.info(context, + "device id size is greater than Batch size "); List tmp = new ArrayList(); for (int i = 0; i < deviceIds.size(); i++) { tmp.add(deviceIds.get(i)); if (tmp.size() == BATCH_SIZE || i == deviceIds.size() - 1) { notification.setIds(tmp); - String message = getTopicMessage(notification); - response = writeDataToKafka(message, topic); + String message = getTopicMessage(notification, context); + response = writeDataToKafka(message, topic, context); tmp.clear(); } } } } else { - String message = getTopicMessage(notification); - response = writeDataToKafka(message, topic); + String message = getTopicMessage(notification, context); + response = writeDataToKafka(message, topic, context); } return response; } - private FCMResponse writeDataToKafka(String message, String topic) { + private FCMResponse writeDataToKafka(String message, String topic, RequestContext context) { FCMResponse response = new FCMResponse(); ProducerRecord record = new ProducerRecord<>(topic, message); if (producer != null) { @@ -154,12 +168,12 @@ private FCMResponse writeDataToKafka(String message, String topic) { } else { response.setError(Constant.ERROR_DURING_WRITE_DATA); response.setFailure(Constant.FAILURE_CODE); - logger.info("UserMergeActor:mergeCertCourseDetails: Kafka producer is not initialised."); + logger.info(context,"FCMNotificationDispatcher:writeDataToKafka: Kafka producer is not initialised."); } return response; } - private String getTopicMessage(NotificationRequest notification) { + private String getTopicMessage(NotificationRequest notification, RequestContext context) { KafkaMessage message = new KafkaMessage(); Actor actor = new Actor(Constant.BROAD_CAST_TOPIC_NOTIFICATION_MESSAGE, Constant.ACTOR_TYPE_VALUE); @@ -171,27 +185,31 @@ private String getTopicMessage(NotificationRequest notification) { Constant.NOTIFICATION, (Map) mapper.convertValue(notification, Map.class)); Map object = new HashMap(); - object.put(Constant.ID, getRequestHashed(requestMap)); + object.put(Constant.ID, getRequestHashed(requestMap, context)); object.put(Constant.TYPE, Constant.TYPE_VALUE); message.setObject(object); EventData evnetData = new EventData(); evnetData.setAction(Constant.BROAD_CAST_TOPIC_NOTIFICATION_KEY); evnetData.setRequest(requestMap); message.setEdata(evnetData); + Map traceMap = new HashMap<>(); + traceMap.put(Constant.X_REQUEST_ID, context.getReqId()); + traceMap.put(Constant.X_TRACE_ENABLED, "false"); + message.setTrace(traceMap); topicMessage = mapper.writeValueAsString(message); } catch (JsonProcessingException e) { - logger.error("Error occured during data parsing==" + e.getMessage()); + logger.error(context,"Error occured during data parsing==" + e.getMessage(), e); e.printStackTrace(); } return topicMessage; } - private String getRequestHashed(Map request) { + private String getRequestHashed(Map request, RequestContext context) { String val = null; try { val = DataHash.getHashed(mapper.writeValueAsString(request)); } catch (Exception e) { - logger.error("exception occured during hash of request data:" + e.getMessage()); + logger.error(context,"exception occured during hash of request data:" + e.getMessage(), e); } return val; } diff --git a/all-actors/src/main/java/org/sunbird/pojo/KafkaMessage.java b/all-actors/src/main/java/org/sunbird/pojo/KafkaMessage.java index 59484b75..e4a546a7 100644 --- a/all-actors/src/main/java/org/sunbird/pojo/KafkaMessage.java +++ b/all-actors/src/main/java/org/sunbird/pojo/KafkaMessage.java @@ -17,6 +17,7 @@ public class KafkaMessage implements Serializable { private String eid; private String mid; + private Map trace; long ets; EventData edata; Context context; @@ -93,4 +94,12 @@ private void setContext() { context.setPdata(pdata); this.context = context; } + + public Map getTrace() { + return trace; + } + + public void setTrace(Map trace) { + this.trace = trace; + } } diff --git a/all-actors/src/main/java/org/sunbird/util/ConfigUtil.java b/all-actors/src/main/java/org/sunbird/util/ConfigUtil.java index 5ff7b512..811cef45 100644 --- a/all-actors/src/main/java/org/sunbird/util/ConfigUtil.java +++ b/all-actors/src/main/java/org/sunbird/util/ConfigUtil.java @@ -3,7 +3,7 @@ import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; +import org.sunbird.request.LoggerUtil; /** * This util class for providing type safe config to any service that requires it. @@ -12,7 +12,7 @@ */ public class ConfigUtil { - private static Logger logger = Logger.getLogger(ConfigUtil.class); + private static LoggerUtil logger = new LoggerUtil(ConfigUtil.class); private static Config config; private static final String DEFAULT_TYPE_SAFE_CONFIG_FILE_NAME = "service.conf"; private static final String INVALID_FILE_NAME = "Please provide a valid file name."; @@ -57,7 +57,7 @@ public static Config getConfig(String fileName) { public static void validateMandatoryConfigValue(String configParameter) { if (StringUtils.isBlank(configParameter)) { - logger.error( + logger.info( "ConfigUtil:validateMandatoryConfigValue: Missing mandatory configuration parameter: " + configParameter); throw new RuntimeException("Server Error"); @@ -90,7 +90,7 @@ public static Config getConfigFromJsonString(String jsonString, String configTyp } catch (Exception e) { logger.error( "ConfigUtil:getConfigFromJsonString: Exception occurred during parse with error message = " - + e.getMessage()); + + e.getMessage(), e); return null; } diff --git a/all-actors/src/main/java/org/sunbird/util/Constant.java b/all-actors/src/main/java/org/sunbird/util/Constant.java index 4d5f9b94..6b5af0ab 100644 --- a/all-actors/src/main/java/org/sunbird/util/Constant.java +++ b/all-actors/src/main/java/org/sunbird/util/Constant.java @@ -35,4 +35,6 @@ public class Constant { public static final int SUCCESS_CODE = 200; public static final int FAILURE_CODE = 500; public static final String ERROR_DURING_WRITE_DATA = "Data write error to kafka topic"; + public static final String X_REQUEST_ID = "X-Request-ID"; + public static final String X_TRACE_ENABLED = "X-Trace-Enabled"; } diff --git a/all-actors/src/main/java/org/sunbird/util/DataHash.java b/all-actors/src/main/java/org/sunbird/util/DataHash.java index 28ad0c2d..d5d8de0e 100644 --- a/all-actors/src/main/java/org/sunbird/util/DataHash.java +++ b/all-actors/src/main/java/org/sunbird/util/DataHash.java @@ -3,12 +3,11 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; +import org.sunbird.request.LoggerUtil; /** @author manzarul */ public class DataHash { - private static Logger logger = LogManager.getLogger(DataHash.class); + private static LoggerUtil logger = new LoggerUtil(DataHash.class); private DataHash() {} diff --git a/all-actors/src/main/java/org/sunbird/util/kafka/KafkaClient.java b/all-actors/src/main/java/org/sunbird/util/kafka/KafkaClient.java index d5169bc9..bc6d867a 100644 --- a/all-actors/src/main/java/org/sunbird/util/kafka/KafkaClient.java +++ b/all-actors/src/main/java/org/sunbird/util/kafka/KafkaClient.java @@ -11,8 +11,7 @@ import org.apache.kafka.common.serialization.LongSerializer; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; +import org.sunbird.request.LoggerUtil; /** * Helper class for creating a Kafka consumer and producer. @@ -20,7 +19,7 @@ * @author manzarul */ public class KafkaClient { - private static Logger logger = LogManager.getLogger(KafkaClient.class); + private static LoggerUtil logger = new LoggerUtil(KafkaClient.class); /** * Creates a Kafka producer. diff --git a/all-actors/src/main/resources/application.conf b/all-actors/src/main/resources/application.conf index 4d6a1fca..b9985fba 100644 --- a/all-actors/src/main/resources/application.conf +++ b/all-actors/src/main/resources/application.conf @@ -1,27 +1,5 @@ notificationActorSystem { default-dispatcher { - type = "Dispatcher" - executor = "fork-join-executor" - fork-join-executor { - parallelism-min = 8 - parallelism-factor = 32.0 - parallelism-max = 64 - } - # Throughput for default Dispatcher, set to 1 for as fair as possible - throughput = 1 - } - router-dispatcher { - type = "Dispatcher" - executor = "fork-join-executor" - fork-join-executor { - parallelism-min = 8 - parallelism-factor = 32.0 - parallelism-max = 64 - } - # Throughput for default Dispatcher, set to 1 for as fair as possible - throughput = 1 - } - supervisor-dispatcher { type = "Dispatcher" executor = "fork-join-executor" fork-join-executor { @@ -44,27 +22,10 @@ notificationActorSystem { throughput = 1 } - akka { - - loglevel = "DEBUG" - log-config-on-start = on - + stdout-loglevel = "OFF" actor { akka.actor.allow-java-serialization = off - debug { - # enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill etc.) - autoreceive = on - # enable DEBUG logging of actor lifecycle changes - lifecycle = on - # enable DEBUG logging of unhandled messages - unhandled = on - # enable DEBUG logging of all LoggingFSMs for events, transitions and timers - fsm = on - # enable DEBUG logging of subscription changes on the eventStream - event-stream = on - } - default-dispatcher { type = "Dispatcher" executor = "fork-join-executor" @@ -77,17 +38,20 @@ notificationActorSystem { throughput = 1 } deployment { - /HealthActor + "/HealthActor" { router = smallest-mailbox-pool - nr-of-instances = 5 - dispatcher = default-dispatcher + nr-of-instances = 2 } - /NotificationActor - { + "/NotificationActor" + { router = smallest-mailbox-pool - nr-of-instances = 10 dispatcher = notification-dispatcher + optimal-size-exploring-resizer { + enabled = on + action-interval = 1s + downsize-after-underutilized-for = 1h + } } } } diff --git a/auto_build_deploy b/auto_build_deploy new file mode 100644 index 00000000..8d4d9a3b --- /dev/null +++ b/auto_build_deploy @@ -0,0 +1,63 @@ +@Library('deploy-conf') _ +node('build-slave') { + try { + String ANSI_GREEN = "\u001B[32m" + String ANSI_NORMAL = "\u001B[0m" + String ANSI_BOLD = "\u001B[1m" + String ANSI_RED = "\u001B[31m" + String ANSI_YELLOW = "\u001B[33m" + + ansiColor('xterm') { + withEnv(["JAVA_HOME=${JAVA11_HOME}"]) { + stage('Checkout') { + tag_name = env.JOB_NAME.split("/")[-1] + pre_checks() + if (!env.hub_org) { + println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) + error 'Please resolve the errors and rerun..' + } else + println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) + } + cleanWs() + def scmVars = checkout scm + checkout scm: [$class: 'GitSCM', branches: [[name: "refs/tags/$tag_name"]], userRemoteConfigs: [[url: scmVars.GIT_URL]]] + build_tag = tag_name + "_" + env.BUILD_NUMBER + commit_hash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() + artifact_version = tag_name + "_" + commit_hash + echo "build_tag: " + build_tag + + // stage Build + currentDir = sh(returnStdout: true, script: 'pwd').trim() + env.NODE_ENV = "build" + print "Environment will be : ${env.NODE_ENV}" + sh 'git log -1' + sh "cd $currentDir" + // Build the dependencies for sunbird user-org service + sh 'mvn clean install' + + // stage Package + // Create a deployment package + dir('service') { + sh 'mvn play2:dist' + sh 'cp target/notification-service-1.0.0-dist.zip ../' + } + sh('chmod 777 ./build.sh') + sh("./build.sh ${build_tag} ${env.NODE_NAME} ${hub_org}") + + // stage ArchiveArtifacts + archiveArtifacts "metadata.json" + currentBuild.description = "${build_tag}" + } + } + currentBuild.result = "SUCCESS" + slack_notify(currentBuild.result, tag_name) + email_notify() + auto_build_deploy() + } + catch (err) { + currentBuild.result = "FAILURE" + slack_notify(currentBuild.result, tag_name) + email_notify() + throw err + } +} diff --git a/notification-sdk/dependency-reduced-pom.xml b/notification-sdk/dependency-reduced-pom.xml index 64985b40..6fa38baf 100644 --- a/notification-sdk/dependency-reduced-pom.xml +++ b/notification-sdk/dependency-reduced-pom.xml @@ -8,7 +8,7 @@ maven-shade-plugin - 3.0.0 + 3.2.4 package @@ -32,7 +32,7 @@ org.jacoco jacoco-maven-plugin - 0.7.5.201505241946 + 0.8.5 jacoco-initialize @@ -83,7 +83,7 @@ org.powermock powermock-module-junit4 - 1.6.5 + 2.0.2 test @@ -94,36 +94,36 @@ powermock-module-junit4-common org.powermock + + hamcrest-core + org.hamcrest + org.powermock - powermock-api-mockito - 1.6.5 + powermock-api-mockito2 + 2.0.2 test - mockito-core - org.mockito - - - powermock-api-mockito-common + powermock-api-support org.powermock - hamcrest-core - org.hamcrest + mockito-core + org.mockito - 3.3.1.Final - 4.5.2 + 11 + 11 + 11 UTF-8 - 1.8 - 1.8 4.12 + 3.3.1.Final + 4.5.2 - diff --git a/notification-sdk/pom.xml b/notification-sdk/pom.xml index a0333548..b733c9ec 100644 --- a/notification-sdk/pom.xml +++ b/notification-sdk/pom.xml @@ -10,8 +10,9 @@ jar - 1.8 - 1.8 + 11 + 11 + 11 UTF-8 3.3.1.Final 4.5.2 @@ -19,16 +20,6 @@ - - org.apache.logging.log4j - log4j-api - 2.8.2 - - - org.apache.logging.log4j - log4j-core - 2.8.2 - com.google.firebase firebase-admin @@ -83,7 +74,7 @@ org.powermock powermock-module-junit4 - 1.6.5 + 2.0.2 test @@ -94,8 +85,8 @@ org.powermock - powermock-api-mockito - 1.6.5 + powermock-api-mockito2 + 2.0.2 test @@ -103,14 +94,20 @@ jackson-databind 2.9.5 - + + org.sunbird + sb-utils + 1.0.0 + compile + + org.apache.maven.plugins maven-shade-plugin - 3.0.0 + 3.2.4 package @@ -134,7 +131,7 @@ org.jacoco jacoco-maven-plugin - 0.7.5.201505241946 + 0.8.5 ${basedir}/target/coverage-reports/jacoco-unit.exec ${basedir}/target/coverage-reports/jacoco-unit.exec diff --git a/notification-sdk/src/main/java/org/sunbird/notification/email/Email.java b/notification-sdk/src/main/java/org/sunbird/notification/email/Email.java index 8cb8f4c0..6042264a 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/email/Email.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/email/Email.java @@ -1,29 +1,20 @@ package org.sunbird.notification.email; -import java.util.List; -import java.util.Properties; -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.activation.FileDataSource; -import javax.mail.BodyPart; -import javax.mail.Message; -import javax.mail.Message.RecipientType; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.sunbird.notification.beans.Constants; import org.sunbird.notification.beans.EmailConfig; import org.sunbird.notification.utils.Util; +import org.sunbird.request.LoggerUtil; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.mail.*; +import javax.mail.Message.RecipientType; +import javax.mail.internet.*; +import java.util.List; +import java.util.Properties; /** * this api is used to sending mail. @@ -31,41 +22,63 @@ * @author Manzarul.Haque */ public class Email { - private static Logger logger = LogManager.getLogger(Email.class); + private static LoggerUtil logger = new LoggerUtil(Email.class); private static Properties props = null; private String host; private String port; private String userName; private String password; private String fromEmail; - private Session session; + private static Email instance; - public Email() { + private Email() { init(); initProps(); } - public Email(EmailConfig config) { + public static Email getInstance() { + if (null == instance) { + synchronized (Email.class){ + if (null == instance) { + instance = new Email(); + } + } + } + return instance; + } + + public static Email getInstance(EmailConfig config) { + if (null == instance) { + synchronized (Email.class){ + if (null == instance) { + instance = new Email(config); + } + } + } + return instance; + } + + private Email(EmailConfig config) { this.fromEmail = - StringUtils.isNotBlank(config.getFromEmail()) - ? config.getFromEmail() - : Util.readValue(Constants.EMAIL_SERVER_FROM); + StringUtils.isNotBlank(config.getFromEmail()) + ? config.getFromEmail() + : Util.readValue(Constants.EMAIL_SERVER_FROM); this.userName = - StringUtils.isNotBlank(config.getUserName()) - ? config.getUserName() - : Util.readValue(Constants.EMAIL_SERVER_USERNAME); + StringUtils.isNotBlank(config.getUserName()) + ? config.getUserName() + : Util.readValue(Constants.EMAIL_SERVER_USERNAME); this.password = - StringUtils.isNotBlank(config.getPassword()) - ? config.getPassword() - : Util.readValue(Constants.EMAIL_SERVER_PASSWORD); + StringUtils.isNotBlank(config.getPassword()) + ? config.getPassword() + : Util.readValue(Constants.EMAIL_SERVER_PASSWORD); this.host = - StringUtils.isNotBlank(config.getHost()) - ? config.getHost() - : Util.readValue(Constants.EMAIL_SERVER_HOST); + StringUtils.isNotBlank(config.getHost()) + ? config.getHost() + : Util.readValue(Constants.EMAIL_SERVER_HOST); this.port = - StringUtils.isNotBlank(config.getPort()) - ? config.getPort() - : Util.readValue(Constants.EMAIL_SERVER_PORT); + StringUtils.isNotBlank(config.getPort()) + ? config.getPort() + : Util.readValue(Constants.EMAIL_SERVER_PORT); initProps(); } @@ -77,17 +90,17 @@ private boolean init() { password = Util.readValue(Constants.EMAIL_SERVER_PASSWORD); fromEmail = Util.readValue(Constants.EMAIL_SERVER_FROM); if (StringUtils.isBlank(host) - || StringUtils.isBlank(port) - || StringUtils.isBlank(userName) - || StringUtils.isBlank(password) - || StringUtils.isBlank(fromEmail)) { + || StringUtils.isBlank(port) + || StringUtils.isBlank(userName) + || StringUtils.isBlank(password) + || StringUtils.isBlank(fromEmail)) { logger.info( - "Email setting value is not provided by Env variable==" - + host - + " " - + port - + " " - + fromEmail); + "Email setting value is not provided by Env variable==" + + host + + " " + + port + + " " + + fromEmail); response = false; } else { logger.info("All email properties are set correctly."); @@ -96,10 +109,19 @@ private boolean init() { } private Session getSession() { - if (session == null) { - session = Session.getInstance(props, new GMailAuthenticator(userName, password)); - } - return session; + return Session.getInstance(props, new GMailAuthenticator(userName, password)); + } + + private Transport getTransportClient() throws MessagingException { + Transport transport = getSession().getTransport("smtp"); + transport.connect(host, userName, password); + return transport; + } + + private Transport getTransportClient(Session session) throws MessagingException { + Transport transport = session.getTransport("smtp"); + transport.connect(host, userName, password); + return transport; } private void initProps() { @@ -134,10 +156,10 @@ public boolean sendMail(List emailList, String subject, String body) { * @return boolean */ public boolean sendMail( - List emailList, String subject, String body, List ccEmailList) { + List emailList, String subject, String body, List ccEmailList) { boolean response = true; + Session session = getSession(); try { - Session session = getSession(); MimeMessage message = new MimeMessage(session); addRecipient(message, Message.RecipientType.TO, emailList); addRecipient(message, Message.RecipientType.CC, ccEmailList); @@ -159,7 +181,7 @@ public boolean sendMail( * @param filePath Path of attachment file */ public void sendAttachment( - List emailList, String emailBody, String subject, String filePath) { + List emailList, String emailBody, String subject, String filePath) { try { Session session = getSession(); MimeMessage message = new MimeMessage(session); @@ -198,13 +220,12 @@ public boolean sendEmail(String fromEmail, String subject, String body, List recipient) - throws AddressException, MessagingException { + throws AddressException, MessagingException { if (CollectionUtils.isEmpty(recipient)) { logger.info("Recipient list is empty or null "); return; @@ -224,16 +245,16 @@ private void addRecipient(MimeMessage message, RecipientType type, List } private void setMessageAttribute( - MimeMessage message, String fromEmail, String subject, String body) - throws AddressException, MessagingException { + MimeMessage message, String fromEmail, String subject, String body) + throws AddressException, MessagingException { message.setFrom(new InternetAddress(fromEmail)); message.setSubject(subject, "utf-8"); message.setContent(body, "text/html; charset=utf-8"); } private void setMessageAttribute( - MimeMessage message, String fromEmail, String subject, Multipart multipart) - throws AddressException, MessagingException { + MimeMessage message, String fromEmail, String subject, Multipart multipart) + throws AddressException, MessagingException { message.setFrom(new InternetAddress(fromEmail)); message.setSubject(subject, "utf-8"); message.setContent(multipart, "text/html; charset=utf-8"); @@ -243,19 +264,16 @@ private boolean sendEmail(Session session, MimeMessage message) { Transport transport = null; boolean response = true; try { - transport = session.getTransport("smtp"); - transport.connect(host, userName, password); + transport = getTransportClient(session); transport.sendMessage(message, message.getAllRecipients()); } catch (Exception e) { logger.error("SendMail:sendMail: Exception occurred with message = " + e.getMessage(), e); response = false; } finally { - if (transport != null) { - try { - transport.close(); - } catch (MessagingException e) { - logger.error(e.toString(), e); - } + try { + transport.close(); + } catch (MessagingException e) { + logger.error("Exception occurred while closing client.",e); } } return response; @@ -280,4 +298,4 @@ public String getPassword() { public String getFromEmail() { return fromEmail; } -} +} \ No newline at end of file diff --git a/notification-sdk/src/main/java/org/sunbird/notification/email/service/IEmailService.java b/notification-sdk/src/main/java/org/sunbird/notification/email/service/IEmailService.java index 64c9ebd9..108846d8 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/email/service/IEmailService.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/email/service/IEmailService.java @@ -1,6 +1,7 @@ package org.sunbird.notification.email.service; import org.sunbird.notification.beans.EmailRequest; +import org.sunbird.request.RequestContext; public interface IEmailService { @@ -8,5 +9,5 @@ public interface IEmailService { * @param emailReq EmailRequest * @return boolean */ - public boolean sendEmail(EmailRequest emailReq); + public boolean sendEmail(EmailRequest emailReq, RequestContext context); } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/email/service/impl/SmtpEMailServiceImpl.java b/notification-sdk/src/main/java/org/sunbird/notification/email/service/impl/SmtpEMailServiceImpl.java index df417b70..2d7c1124 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/email/service/impl/SmtpEMailServiceImpl.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/email/service/impl/SmtpEMailServiceImpl.java @@ -2,30 +2,30 @@ package org.sunbird.notification.email.service.impl; import org.apache.commons.collections.CollectionUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.sunbird.notification.beans.EmailConfig; import org.sunbird.notification.beans.EmailRequest; import org.sunbird.notification.email.Email; import org.sunbird.notification.email.service.IEmailService; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; /** @author manzarul */ public class SmtpEMailServiceImpl implements IEmailService { - private static Logger logger = LogManager.getLogger(SmtpEMailServiceImpl.class); + private static LoggerUtil logger = new LoggerUtil(SmtpEMailServiceImpl.class); private Email email = null; public SmtpEMailServiceImpl() { - email = new Email(); + email = Email.getInstance(); } public SmtpEMailServiceImpl(EmailConfig config) { - email = new Email(config); + email = Email.getInstance(config); } @Override - public boolean sendEmail(EmailRequest emailReq) { + public boolean sendEmail(EmailRequest emailReq, RequestContext context) { if (emailReq == null) { - logger.info("Email request is null or empty:"); + logger.info(context, "Email request is null or empty:"); return false; // either email object has bcc or to list size more than 1 then pass it as bcc. } else if (CollectionUtils.isNotEmpty(emailReq.getBcc()) || emailReq.getTo().size() > 1) { diff --git a/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/IFCMNotificationService.java b/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/IFCMNotificationService.java index bd7cf165..5d8e1439 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/IFCMNotificationService.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/IFCMNotificationService.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.Map; import org.sunbird.notification.utils.FCMResponse; +import org.sunbird.request.RequestContext; /** * This interface will handle all call regarding FCM notification @@ -20,7 +21,7 @@ public interface IFCMNotificationService { * @return FCMResponse */ public FCMResponse sendSingleDeviceNotification( - String deviceId, Map data, boolean isDryRun); + String deviceId, Map data, boolean isDryRun, RequestContext context); /** * This api will be used for sending notification to multiple device. max 100 device notification @@ -32,7 +33,7 @@ public FCMResponse sendSingleDeviceNotification( * @return FCMResponse */ public FCMResponse sendMultiDeviceNotification( - List deviceIds, Map data, boolean isDryRun); + List deviceIds, Map data, boolean isDryRun, RequestContext context); /** * Method used for sending topic based notification @@ -43,5 +44,5 @@ public FCMResponse sendMultiDeviceNotification( * @return FCMResponse */ public FCMResponse sendTopicNotification( - String topic, Map data, boolean isDryRun); + String topic, Map data, boolean isDryRun, RequestContext context); } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/NotificationFactory.java b/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/NotificationFactory.java index 3259c17c..302a3d12 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/NotificationFactory.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/fcm/provider/NotificationFactory.java @@ -1,12 +1,11 @@ package org.sunbird.notification.fcm.provider; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.sunbird.notification.fcm.providerImpl.FCMHttpNotificationServiceImpl; import org.sunbird.notification.fcm.providerImpl.FCMNotificationServiceImpl; +import org.sunbird.request.LoggerUtil; public class NotificationFactory { - private static Logger logger = LogManager.getLogger(NotificationFactory.class); + private static LoggerUtil logger = new LoggerUtil(NotificationFactory.class); public enum instanceType { adminClient(), diff --git a/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMHttpNotificationServiceImpl.java b/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMHttpNotificationServiceImpl.java index 34176720..6c5a6bf9 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMHttpNotificationServiceImpl.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMHttpNotificationServiceImpl.java @@ -10,12 +10,12 @@ import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.json.JSONObject; import org.sunbird.notification.fcm.provider.IFCMNotificationService; import org.sunbird.notification.utils.FCMResponse; import org.sunbird.notification.utils.NotificationConstant; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; /** * This notification service will make http call to send device notification. @@ -23,7 +23,7 @@ * @author manzarul */ public class FCMHttpNotificationServiceImpl implements IFCMNotificationService { - private static Logger logger = LogManager.getLogger("FCMHttpNotificationServiceImpl"); + private static LoggerUtil logger = new LoggerUtil(FCMHttpNotificationServiceImpl.class); /** FCM_URL URL of FCM server */ public static final String FCM_URL = "https://fcm.googleapis.com/fcm/send"; @@ -42,22 +42,22 @@ public class FCMHttpNotificationServiceImpl implements IFCMNotificationService { @Override public FCMResponse sendSingleDeviceNotification( - String deviceId, Map data, boolean isDryRun) { + String deviceId, Map data, boolean isDryRun, RequestContext context) { List deviceIds = new ArrayList(); deviceIds.add(deviceId); - return sendDeviceNotification(deviceIds, data, FCM_URL, isDryRun); + return sendDeviceNotification(deviceIds, data, FCM_URL, isDryRun, context); } @Override public FCMResponse sendMultiDeviceNotification( - List deviceIds, Map data, boolean isDryRun) { - return sendDeviceNotification(deviceIds, data, FCM_URL, isDryRun); + List deviceIds, Map data, boolean isDryRun, RequestContext context) { + return sendDeviceNotification(deviceIds, data, FCM_URL, isDryRun, context); } @Override public FCMResponse sendTopicNotification( - String topic, Map data, boolean isDryRun) { - return sendTopicNotification(topic, data, FCM_URL, isDryRun); + String topic, Map data, boolean isDryRun, RequestContext context) { + return sendTopicNotification(topic, data, FCM_URL, isDryRun, context); } public static void setAccountKey(String key) { @@ -74,9 +74,9 @@ public static void setAccountKey(String key) { * @return String as Json.{"message_id": 7253391319867149192} */ private static FCMResponse sendTopicNotification( - String topic, Map data, String url, boolean isDryRun) { + String topic, Map data, String url, boolean isDryRun, RequestContext context) { if (StringUtils.isBlank(FCM_ACCOUNT_KEY) || StringUtils.isBlank(url)) { - logger.info("FCM account key or URL is not provided===" + FCM_URL); + logger.info(context, "FCM account key or URL is not provided===" + FCM_URL); return null; } FCMResponse response = null; @@ -89,10 +89,10 @@ private static FCMResponse sendTopicNotification( HttpResponse httpResponse = Unirest.post(FCM_URL).headers(headerMap).body(object.toString()).asJson(); String responsebody = httpResponse.getBody().toString(); - logger.info("FCM Notification response== for topic " + topic + response); + logger.info(context, "FCM Notification response== for topic " + topic + response); response = mapper.readValue(responsebody, FCMResponse.class); } catch (Exception e) { - logger.info(e.getMessage()); + logger.error(context, e.getMessage(), e); } return response; } @@ -106,9 +106,9 @@ private static FCMResponse sendTopicNotification( * @return String as Json.{"message_id": 7253391319867149192} */ private static FCMResponse sendDeviceNotification( - List deviceIds, Map data, String url, boolean isDryRun) { + List deviceIds, Map data, String url, boolean isDryRun, RequestContext context) { if (StringUtils.isBlank(FCM_ACCOUNT_KEY) || StringUtils.isBlank(url)) { - logger.info("FCM account key or URL is not provided===" + FCM_URL); + logger.info(context, "FCM account key or URL is not provided===" + FCM_URL); return null; } FCMResponse fcmResponse = null; @@ -121,10 +121,10 @@ private static FCMResponse sendDeviceNotification( HttpResponse httpResponse = Unirest.post(FCM_URL).headers(headerMap).body(object).asJson(); String response = httpResponse.getBody().toString(); - logger.info("FCM Notification response== for device ids " + deviceIds + " " + response); + logger.info(context, "FCM Notification response== for device ids " + deviceIds + " " + response); fcmResponse = mapper.readValue(response, FCMResponse.class); } catch (Exception e) { - logger.info(e.getMessage()); + logger.error(context, e.getMessage(), e); } return fcmResponse; } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMNotificationServiceImpl.java b/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMNotificationServiceImpl.java index fb2490e0..f7b7305c 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMNotificationServiceImpl.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/fcm/providerImpl/FCMNotificationServiceImpl.java @@ -8,27 +8,27 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.sunbird.notification.fcm.provider.FCMInitializer; import org.sunbird.notification.fcm.provider.IFCMNotificationService; import org.sunbird.notification.utils.FCMResponse; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; public class FCMNotificationServiceImpl implements IFCMNotificationService { - private static Logger logger = LogManager.getLogger("FCMNotificationServiceImpl"); + private static LoggerUtil logger = new LoggerUtil(FCMNotificationServiceImpl.class); @Override public FCMResponse sendSingleDeviceNotification( - String deviceId, Map data, boolean isDryRun) { - logger.info("sendSinfleDeviceNotification method started."); + String deviceId, Map data, boolean isDryRun, RequestContext context) { + logger.info(context, "sendSinfleDeviceNotification method started."); Message message = Message.builder().putAllData(data).setToken(deviceId).build(); - logger.info("Message going to be sent:" + message); + logger.info(context, "Message going to be sent:" + message); String response = null; try { response = FCMInitializer.getInstance().send(message, isDryRun); - logger.info("Response from FCM :" + response); + logger.info(context, "Response from FCM :" + response); } catch (FirebaseMessagingException e) { - logger.error("Exception occured during notification sent: " + e.getMessage()); + logger.error(context,"Exception occured during notification sent: " + e.getMessage(),e); e.printStackTrace(); } return null; @@ -36,7 +36,7 @@ public FCMResponse sendSingleDeviceNotification( @Override public FCMResponse sendMultiDeviceNotification( - List deviceIds, Map data, boolean isDryRun) { + List deviceIds, Map data, boolean isDryRun, RequestContext context) { List responseDetails = new ArrayList(); if (deviceIds == null || deviceIds.size() == 0 || deviceIds.size() > 100) { throw new RuntimeException( @@ -48,7 +48,7 @@ public FCMResponse sendMultiDeviceNotification( try { responses = FCMInitializer.getInstance().sendMulticast(message, isDryRun); } catch (FirebaseMessagingException e) { - logger.info("exception occured==" + e.getMessage()); + logger.error(context, "exception occured==" + e.getMessage(), e); throw new RuntimeException("FCM Server error"); } List responseList = responses.getResponses(); @@ -60,15 +60,15 @@ public FCMResponse sendMultiDeviceNotification( @Override public FCMResponse sendTopicNotification( - String topic, Map data, boolean isDryRun) { + String topic, Map data, boolean isDryRun, RequestContext context) { Message message = Message.builder().putAllData(data).setTopic(topic).build(); - logger.info("Message going to be sent:" + message); + logger.info(context, "Message going to be sent:" + message); String response = null; try { response = FCMInitializer.getInstance().send(message, isDryRun); - logger.info("Response from FCM :" + response); + logger.info(context, "Response from FCM :" + response); } catch (FirebaseMessagingException e) { - logger.error("Exception occured during notification sent: " + e.getMessage()); + logger.error(context,"Exception occured during notification sent: " + e.getMessage(), e); e.printStackTrace(); } return null; diff --git a/notification-sdk/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java b/notification-sdk/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java index b123ff69..be94ac77 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java @@ -2,6 +2,7 @@ import java.util.List; import org.sunbird.notification.beans.OTPRequest; +import org.sunbird.request.RequestContext; /** * This interface will provide all method for sending sms. @@ -18,7 +19,7 @@ public interface ISmsProvider { * @param smsText Sms text * @return boolean */ - boolean sendSms(String phoneNumber, String smsText); + boolean sendSms(String phoneNumber, String smsText, RequestContext context); /** * This method will send SMS on user provider country code, basically it will override the value @@ -29,7 +30,7 @@ public interface ISmsProvider { * @param smsText * @return boolean */ - boolean sendSms(String phoneNumber, String countryCode, String smsText); + boolean sendSms(String phoneNumber, String countryCode, String smsText, RequestContext context); /** * This method will send SMS to list of phone numbers. default country code value will differ @@ -39,7 +40,7 @@ public interface ISmsProvider { * @param smsText Sms text * @return boolean */ - boolean bulkSms(List phoneNumber, String smsText); + boolean bulkSms(List phoneNumber, String smsText, RequestContext context); /** * This method will send OTP to user phone number. * @@ -48,14 +49,14 @@ public interface ISmsProvider { * India * @return boolean */ - boolean sendOtp(OTPRequest otpRequest); + boolean sendOtp(OTPRequest otpRequest, RequestContext context); /** * This method is used for resending otp on phone number only. * * @param OTPRequest otp request countryCode String country code value Ex: 91 for India * @return boolean */ - boolean resendOtp(OTPRequest otpRequest); + boolean resendOtp(OTPRequest otpRequest, RequestContext context); /** * This method will verify provided otp. * @@ -63,5 +64,5 @@ public interface ISmsProvider { * value Ex: 91 for India * @return boolean */ - boolean verifyOtp(OTPRequest otpRequest); + boolean verifyOtp(OTPRequest otpRequest, RequestContext context); } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderImpl.java b/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderImpl.java index a04fcf47..43ed1ad8 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderImpl.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderImpl.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -22,8 +23,6 @@ import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.sunbird.notification.beans.MessageResponse; import org.sunbird.notification.beans.OTPRequest; import org.sunbird.notification.sms.Sms; @@ -31,11 +30,13 @@ import org.sunbird.notification.utils.JsonUtil; import org.sunbird.notification.utils.NotificationConstant; import org.sunbird.notification.utils.Util; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.RequestContext; /** @author manzarul */ public class Msg91SmsProviderImpl implements ISmsProvider { - private static Logger logger = LogManager.getLogger(Msg91SmsProviderImpl.class); + private static LoggerUtil logger = new LoggerUtil(Msg91SmsProviderImpl.class); private static String baseUrl = null; private static String postUrl = null; @@ -76,12 +77,12 @@ public boolean init() { } @Override - public boolean sendSms(String phoneNumber, String smsText) { + public boolean sendSms(String phoneNumber, String smsText, RequestContext context) { return sendMsg(phoneNumber, smsText, null); } @Override - public boolean sendSms(String phoneNumber, String countryCode, String smsText) { + public boolean sendSms(String phoneNumber, String countryCode, String smsText, RequestContext context) { return sendMsg(phoneNumber, smsText, countryCode); } @@ -120,7 +121,7 @@ private boolean sendMsg(String mobileNumber, String smsText, String countryCode) mobileNumbers.add(tempMobileNumber); // create sms - Sms sms = new Sms(URLEncoder.encode(smsText, "UTF-8"), mobileNumbers); + Sms sms = new Sms(getDoubleEncodedSMS(smsText), mobileNumbers); List smsList = new ArrayList<>(); smsList.add(sms); @@ -130,7 +131,7 @@ private boolean sendMsg(String mobileNumber, String smsText, String countryCode) countryCode = country; } ProviderDetails providerDetails = - new ProviderDetails(sender, smsRoute, countryCode, smsList); + new ProviderDetails(sender, smsRoute, countryCode, 1, smsList); String providerDetailsString = JsonUtil.toJson(providerDetails); @@ -144,13 +145,13 @@ private boolean sendMsg(String mobileNumber, String smsText, String countryCode) StatusLine sl = response.getStatusLine(); response.close(); if (sl.getStatusCode() != 200) { - logger.error( - "SMS code for " - + tempMobileNumber - + " could not be sent: " - + sl.getStatusCode() - + " - " - + sl.getReasonPhrase()); + logger.info( + "SMS code for " + + tempMobileNumber + + " could not be sent: " + + sl.getStatusCode() + + " - " + + sl.getReasonPhrase()); } return sl.getStatusCode() == 200; } else { @@ -162,7 +163,7 @@ private boolean sendMsg(String mobileNumber, String smsText, String countryCode) return false; } } catch (IOException e) { - logger.error(e); + logger.error("Exception occurred while sending sms",e); return false; } catch (Exception e) { logger.info("Msg91SmsProvider - Error in coverting providerDetails to string!"); @@ -197,7 +198,7 @@ private void closeHttpResource(CloseableHttpClient httpClient) { try { httpClient.close(); } catch (IOException e) { - logger.error(e); + logger.error("Exception occurred while closing client",e); } } } @@ -209,50 +210,50 @@ private void closeHttpResource(CloseableHttpClient httpClient) { */ private boolean validateSettings(String phone, String smsText) { if (!JsonUtil.isStringNullOREmpty(sender) - && !JsonUtil.isStringNullOREmpty(smsRoute) - && !JsonUtil.isStringNullOREmpty(phone) - && !JsonUtil.isStringNullOREmpty(authKey) - && !JsonUtil.isStringNullOREmpty(country) - && !JsonUtil.isStringNullOREmpty(smsText)) { + && !JsonUtil.isStringNullOREmpty(smsRoute) + && !JsonUtil.isStringNullOREmpty(phone) + && !JsonUtil.isStringNullOREmpty(authKey) + && !JsonUtil.isStringNullOREmpty(country) + && !JsonUtil.isStringNullOREmpty(smsText)) { return true; } - logger.error("SMS value is not configure properly."); + logger.info("SMS value is not configure properly."); return false; } /** @return */ private boolean validateSettings() { if (!JsonUtil.isStringNullOREmpty(sender) - && !JsonUtil.isStringNullOREmpty(smsRoute) - && !JsonUtil.isStringNullOREmpty(authKey) - && !JsonUtil.isStringNullOREmpty(country)) { + && !JsonUtil.isStringNullOREmpty(smsRoute) + && !JsonUtil.isStringNullOREmpty(authKey) + && !JsonUtil.isStringNullOREmpty(country)) { return true; } - logger.error("SMS value is not configure properly."); + logger.info("SMS value is not configure properly."); return false; } @Override - public boolean bulkSms(List phoneNumber, String smsText) { + public boolean bulkSms(List phoneNumber, String smsText, RequestContext context) { List phoneNumberList = null; logger.debug("Msg91SmsProvider@Sending " + smsText + " to mobileNumber "); logger.debug( - "Msg91SmsProvider@SMS Provider parameters \n" - + "Gateway - " - + baseUrl - + "\n" - + "authKey - " - + authKey - + "\n" - + "sender - " - + sender - + "\n" - + "country - " - + country - + "\n" - + "smsRoute - " - + smsRoute - + "\n"); + "Msg91SmsProvider@SMS Provider parameters \n" + + "Gateway - " + + baseUrl + + "\n" + + "authKey - " + + authKey + + "\n" + + "sender - " + + sender + + "\n" + + "country - " + + country + + "\n" + + "smsRoute - " + + smsRoute + + "\n"); if (JsonUtil.isStringNullOREmpty(smsText)) { logger.debug("can't sent empty msg."); @@ -281,13 +282,13 @@ public boolean bulkSms(List phoneNumber, String smsText) { // add authkey header httpPost.setHeader("authkey", authKey); // create sms - Sms sms = new Sms(URLEncoder.encode(smsText, "UTF-8"), phoneNumberList); + Sms sms = new Sms(getDoubleEncodedSMS(smsText), phoneNumberList); List smsList = new ArrayList<>(); smsList.add(sms); // create body - ProviderDetails providerDetails = new ProviderDetails(sender, smsRoute, country, smsList); + ProviderDetails providerDetails = new ProviderDetails(sender, smsRoute, country, 1, smsList); String providerDetailsString = JsonUtil.toJson(providerDetails); @@ -301,13 +302,13 @@ public boolean bulkSms(List phoneNumber, String smsText) { StatusLine sl = response.getStatusLine(); response.close(); if (sl.getStatusCode() != 200) { - logger.error( - "SMS code for " - + phoneNumberList - + " could not be sent: " - + sl.getStatusCode() - + " - " - + sl.getReasonPhrase()); + logger.info( + "SMS code for " + + phoneNumberList + + " could not be sent: " + + sl.getStatusCode() + + " - " + + sl.getReasonPhrase()); } return sl.getStatusCode() == 200; } else { @@ -315,10 +316,10 @@ public boolean bulkSms(List phoneNumber, String smsText) { } } catch (IOException e) { - logger.error(e); + logger.error("Exception occurred while sending sms",e); return false; } catch (Exception e) { - logger.error("Msg91SmsProvider : send : error in converting providerDetails to String"); + logger.error("Msg91SmsProvider : send : error in converting providerDetails to String", e); return false; } finally { closeHttpResource(httpClient); @@ -346,7 +347,7 @@ private List validatePhoneList(List phones) { } @Override - public boolean sendOtp(OTPRequest request) { + public boolean sendOtp(OTPRequest request, RequestContext context) { if (!isOtpRequestValid(request)) { logger.info("Send opt request is not valid."); return false; @@ -355,7 +356,7 @@ public boolean sendOtp(OTPRequest request) { try { String data = createOtpReqData(request); HttpResponse response = - Unirest.get(OTP_BASE_URL + "sendotp.php?authkey=" + authKey + data).asString(); + Unirest.get(OTP_BASE_URL + "sendotp.php?authkey=" + authKey + data).asString(); if (response != null) { if (response.getStatus() == NotificationConstant.SUCCESS_CODE) { MessageResponse messageResponse = convertMsg91Response(response.getBody()); @@ -366,23 +367,23 @@ public boolean sendOtp(OTPRequest request) { logger.info("OTP sent response data " + response.getBody()); } else { logger.info( - "OTP failed to sent with status code and response data " - + response.getStatus() - + " " - + response.getBody()); + "OTP failed to sent with status code and response data " + + response.getStatus() + + " " + + response.getBody()); } } } catch (UnirestException e) { logger.error( - "Msg91SmsProviderImpl:sendOtp exception occured during otp send :" + e.getMessage()); + "Msg91SmsProviderImpl:sendOtp exception occured during otp send :" + e.getMessage(), e); e.printStackTrace(); } return otpResponse; } @Override - public boolean resendOtp(OTPRequest request) { + public boolean resendOtp(OTPRequest request, RequestContext context) { if (!isPhoneNumberValid(request.getPhone())) { logger.info("resend otp request is not valid "); return false; @@ -390,17 +391,17 @@ public boolean resendOtp(OTPRequest request) { boolean response = false; try { HttpResponse resendResponse = - Unirest.get( - OTP_BASE_URL - + "retryotp.php?retrytype=text&authkey=" - + authKey - + NotificationConstant.Ampersand - + NotificationConstant.MOBILE - + NotificationConstant.EQUAL - + request.getCountryCode() - + request.getPhone()) - .header("content-type", "application/x-www-form-urlencoded") - .asString(); + Unirest.get( + OTP_BASE_URL + + "retryotp.php?retrytype=text&authkey=" + + authKey + + NotificationConstant.Ampersand + + NotificationConstant.MOBILE + + NotificationConstant.EQUAL + + request.getCountryCode() + + request.getPhone()) + .header("content-type", "application/x-www-form-urlencoded") + .asString(); if (resendResponse != null) { if (resendResponse.getStatus() == NotificationConstant.SUCCESS_CODE) { @@ -412,10 +413,10 @@ public boolean resendOtp(OTPRequest request) { } } else { logger.info( - "OTP resent failed with code and response data " - + resendResponse.getStatus() - + " -" - + resendResponse.getBody()); + "OTP resent failed with code and response data " + + resendResponse.getStatus() + + " -" + + resendResponse.getBody()); } } else { @@ -424,13 +425,13 @@ public boolean resendOtp(OTPRequest request) { } catch (Exception e) { logger.error( - "Msg91SmsProviderImpl:sendOtp exception occured during otp resend :" + e.getMessage()); + "Msg91SmsProviderImpl:sendOtp exception occured during otp resend :" + e.getMessage(), e); } return response; } @Override - public boolean verifyOtp(OTPRequest request) { + public boolean verifyOtp(OTPRequest request, RequestContext context) { if (!isOtpRequestValid(request)) { logger.info("Verify Opt request is not valid."); return false; @@ -438,21 +439,21 @@ public boolean verifyOtp(OTPRequest request) { boolean response = false; try { HttpResponse resendResponse = - Unirest.get( - OTP_BASE_URL - + "verifyRequestOTP.php?authkey=" - + authKey - + NotificationConstant.Ampersand - + NotificationConstant.MOBILE - + NotificationConstant.EQUAL - + request.getCountryCode() - + request.getPhone() - + NotificationConstant.Ampersand - + NotificationConstant.OTP - + NotificationConstant.EQUAL - + request.getOtp()) - .header("content-type", "application/x-www-form-urlencoded") - .asString(); + Unirest.get( + OTP_BASE_URL + + "verifyRequestOTP.php?authkey=" + + authKey + + NotificationConstant.Ampersand + + NotificationConstant.MOBILE + + NotificationConstant.EQUAL + + request.getCountryCode() + + request.getPhone() + + NotificationConstant.Ampersand + + NotificationConstant.OTP + + NotificationConstant.EQUAL + + request.getOtp()) + .header("content-type", "application/x-www-form-urlencoded") + .asString(); if (resendResponse != null) { if (resendResponse.getStatus() == NotificationConstant.SUCCESS_CODE) { @@ -464,10 +465,10 @@ public boolean verifyOtp(OTPRequest request) { } } else { logger.info( - "OTP verification failed with code and response data " - + resendResponse.getStatus() - + " -" - + resendResponse.getBody()); + "OTP verification failed with code and response data " + + resendResponse.getStatus() + + " -" + + resendResponse.getBody()); } } else { @@ -476,8 +477,8 @@ public boolean verifyOtp(OTPRequest request) { } catch (Exception e) { logger.error( - "Msg91SmsProviderImpl:sendOtp exception occured during otp verification :" - + e.getMessage()); + "Msg91SmsProviderImpl:sendOtp exception occured during otp verification :" + + e.getMessage(), e); } return response; } @@ -486,40 +487,40 @@ private String createOtpReqData(OTPRequest request) { StringBuilder builder = new StringBuilder(); if (StringUtils.isNotBlank(request.getOtp())) { builder.append( - NotificationConstant.Ampersand - + NotificationConstant.OTP - + NotificationConstant.EQUAL - + request.getOtp()); + NotificationConstant.Ampersand + + NotificationConstant.OTP + + NotificationConstant.EQUAL + + request.getOtp()); } else { builder.append( - NotificationConstant.Ampersand - + NotificationConstant.SENDER - + NotificationConstant.EQUAL - + Util.readValue(NotificationConstant.SUNBIR_MSG_DEFAULT_SENDER)); + NotificationConstant.Ampersand + + NotificationConstant.SENDER + + NotificationConstant.EQUAL + + Util.readValue(NotificationConstant.SUNBIR_MSG_DEFAULT_SENDER)); } try { builder.append( - NotificationConstant.Ampersand - + NotificationConstant.MESSAGE - + NotificationConstant.EQUAL - + URLEncoder.encode(request.getMessage(), "UTF-8") - + NotificationConstant.Ampersand - + NotificationConstant.MOBILES - + NotificationConstant.EQUAL - + request.getCountryCode() - + request.getPhone()); + NotificationConstant.Ampersand + + NotificationConstant.MESSAGE + + NotificationConstant.EQUAL + + URLEncoder.encode(request.getMessage(), "UTF-8") + + NotificationConstant.Ampersand + + NotificationConstant.MOBILES + + NotificationConstant.EQUAL + + request.getCountryCode() + + request.getPhone()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } builder.append( - NotificationConstant.Ampersand - + NotificationConstant.OTP_LENGTH - + NotificationConstant.EQUAL - + request.getOtpLength() - + NotificationConstant.Ampersand - + NotificationConstant.OTP_EXPIRY - + NotificationConstant.EQUAL - + request.getExpiryTimeInMinute()); + NotificationConstant.Ampersand + + NotificationConstant.OTP_LENGTH + + NotificationConstant.EQUAL + + request.getOtpLength() + + NotificationConstant.Ampersand + + NotificationConstant.OTP_EXPIRY + + NotificationConstant.EQUAL + + request.getExpiryTimeInMinute()); return builder.toString(); } @@ -528,12 +529,12 @@ private MessageResponse convertMsg91Response(String response) { try { messageResponse = mapper.readValue(response, MessageResponse.class); } catch (JsonParseException e) { - logger.error("Error occured during response parsing:JsonParseException: " + e.getMessage()); + logger.error("Error occured during response parsing:JsonParseException: " + e.getMessage(), e); } catch (JsonMappingException e) { logger.error( - "Error occured during response parsing:JsonMappingException : " + e.getMessage()); + "Error occured during response parsing:JsonMappingException : " + e.getMessage(), e); } catch (IOException e) { - logger.error("Error occured during response parsing:IOException : " + e.getMessage()); + logger.error("Error occured during response parsing:IOException : " + e.getMessage(),e); } return messageResponse; } @@ -563,4 +564,10 @@ private boolean isOtpLengthValid(int otpLength) { } return true; } + + private String getDoubleEncodedSMS(String smsText) { + String smsUtf8 = new String(smsText.getBytes(), StandardCharsets.UTF_8); + String doubleEncodedSMS = new String(smsUtf8.getBytes(), StandardCharsets.UTF_8); + return doubleEncodedSMS; + } } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java b/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java index 74a5207e..40349e39 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java @@ -12,13 +12,15 @@ public class ProviderDetails implements Serializable { private String sender; private String route; private String country; + private int unicode; private List sms; - public ProviderDetails(String sender, String route, String country, List sms) { + public ProviderDetails(String sender, String route, String country, int unicode, List sms) { this.sender = sender; this.route = route; this.country = country; this.sms = sms; + this.unicode = unicode; } /** @return the serialversionuid */ @@ -45,4 +47,9 @@ public String getCountry() { public List getSms() { return sms; } + + /** @return the unicode */ + public int getUnicode() { + return unicode; + } } diff --git a/notification-sdk/src/main/java/org/sunbird/notification/utils/JsonUtil.java b/notification-sdk/src/main/java/org/sunbird/notification/utils/JsonUtil.java index fd4adb4c..c9e7f0d0 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/utils/JsonUtil.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/utils/JsonUtil.java @@ -3,18 +3,17 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.sunbird.request.LoggerUtil; public class JsonUtil { - private static Logger logger = LogManager.getLogger(JsonUtil.class); + private static LoggerUtil logger = new LoggerUtil(JsonUtil.class); public static String toJson(Object object) { ObjectMapper mapper = new ObjectMapper(); try { return mapper.writeValueAsString(object); } catch (Exception e) { - logger.error("JsonUtil:getJsonString error occured : " + e); + logger.error("JsonUtil:getJsonString error occured : " , e); } return null; } @@ -34,7 +33,7 @@ public static T getAsObject(String res, Class clazz) { JsonNode node = mapper.readTree(res); result = mapper.convertValue(node, clazz); } catch (IOException e) { - logger.error("JsonUtil:getAsObject error occured : " + e); + logger.error("JsonUtil:getAsObject error occured : " , e); e.printStackTrace(); } return result; diff --git a/notification-sdk/src/main/java/org/sunbird/notification/utils/PropertiesCache.java b/notification-sdk/src/main/java/org/sunbird/notification/utils/PropertiesCache.java index 034fe3d2..d0159eea 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/utils/PropertiesCache.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/utils/PropertiesCache.java @@ -3,13 +3,13 @@ import java.io.IOException; import java.io.InputStream; import java.util.Properties; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.sunbird.request.LoggerUtil; public class PropertiesCache { - private static Logger logger = LogManager.getLogger(PropertiesCache.class); + private static LoggerUtil logger = new LoggerUtil(PropertiesCache.class); private final String fileName = "configuration.properties"; private final Properties configProp = new Properties(); + private static PropertiesCache instance; /** private default constructor */ private PropertiesCache() { @@ -21,12 +21,16 @@ private PropertiesCache() { } } - private static class LazyHolder { - private static final PropertiesCache INSTANCE = new PropertiesCache(); - } - public static PropertiesCache getInstance() { - return LazyHolder.INSTANCE; + if (instance == null) { + // To make thread safe + synchronized (PropertiesCache.class) { + // check again as multiple threads + // can reach above step + if (instance == null) instance = new PropertiesCache(); + } + } + return instance; } /** diff --git a/notification-sdk/src/main/java/org/sunbird/notification/utils/Util.java b/notification-sdk/src/main/java/org/sunbird/notification/utils/Util.java index 9a699710..89f22eb4 100644 --- a/notification-sdk/src/main/java/org/sunbird/notification/utils/Util.java +++ b/notification-sdk/src/main/java/org/sunbird/notification/utils/Util.java @@ -2,12 +2,11 @@ package org.sunbird.notification.utils; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.sunbird.request.LoggerUtil; /** @author manzarul */ public class Util { - private static Logger logger = LogManager.getLogger(Util.class); + private static LoggerUtil logger = new LoggerUtil(Util.class); private static PropertiesCache propertiesCache = PropertiesCache.getInstance(); /** @@ -27,7 +26,7 @@ public static String readValue(String key) { if (StringUtils.isBlank(val)) { val = propertiesCache.getProperty(key); } - logger.info("found value for key:" + key + " value: " + val); + logger.debug("found value for key:" + key + " value: " + val); return val; } } diff --git a/notification-sdk/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java b/notification-sdk/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java index ff9fbfd2..db44a900 100644 --- a/notification-sdk/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java +++ b/notification-sdk/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java @@ -16,6 +16,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.junit.Assert; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.runner.RunWith; @@ -26,16 +27,23 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.notification.beans.SMSConfig; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderFactory; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderImpl; import org.sunbird.notification.utils.PropertiesCache; +import org.sunbird.notification.utils.SMSFactory; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RunWith(PowerMockRunner.class) -@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) -@PrepareForTest({HttpClients.class, PropertiesCache.class, Unirest.class, GetRequest.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*", "jdk.internal.reflect.*"}) +@PrepareForTest({HttpClients.class, PropertiesCache.class, Unirest.class, GetRequest.class, SMSFactory.class, Msg91SmsProviderFactory.class, Msg91SmsProviderImpl.class, SMSConfig.class}) public abstract class BaseMessageTest { @BeforeClass public static void initMockRules() { + PowerMockito.mockStatic(SMSFactory.class); + PowerMockito.mockStatic(Msg91SmsProviderFactory.class); CloseableHttpClient httpClient = mock(CloseableHttpClient.class); CloseableHttpResponse httpResp = mock(CloseableHttpResponse.class); StatusLine statusLine = mock(StatusLine.class); @@ -75,5 +83,9 @@ public static void initMockRules() { doCallRealMethod() .when(pc) .getProperty(AdditionalMatchers.not(Mockito.eq("sunbird_msg_91_auth"))); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.anyString(), Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); } + + } diff --git a/notification-sdk/src/test/java/org/sunbird/notification/sms/Message91Test.java b/notification-sdk/src/test/java/org/sunbird/notification/sms/Message91Test.java index b89a28bf..b49a2adc 100644 --- a/notification-sdk/src/test/java/org/sunbird/notification/sms/Message91Test.java +++ b/notification-sdk/src/test/java/org/sunbird/notification/sms/Message91Test.java @@ -3,16 +3,27 @@ import java.util.ArrayList; import java.util.List; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; import org.sunbird.notification.beans.OTPRequest; import org.sunbird.notification.beans.SMSConfig; import org.sunbird.notification.sms.provider.ISmsProvider; import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderImpl; import org.sunbird.notification.utils.SMSFactory; +import org.sunbird.request.RequestContext; public class Message91Test extends BaseMessageTest { SMSConfig config = new SMSConfig(null, "TESTSU"); + @Before + public void initMock() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(),Mockito.any())).thenReturn(msg91SmsProvider); + } + @Test public void testInitSuccess() { Msg91SmsProviderImpl service = new Msg91SmsProviderImpl("sms-auth-key", "TESTSU"); @@ -34,116 +45,148 @@ public void testGetInstanceSuccessWithName() { @Test public void testSendSuccess() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class), Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("9666666666", "test sms"); + boolean response = object.sendSms("9666666666", "test sms", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendFailureWithFormattedPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("(966) 3890-445", "test sms 122"); + boolean response = object.sendSms("(966) 3890-445", "test sms 122", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendSuccessWithoutCountryCodeArg() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class), Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("919666666666", "test sms 122"); + boolean response = object.sendSms("919666666666", "test sms 122", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendSuccessWithoutCountryCodeArgAndPlus() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class), Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("+919666666666", "test sms 122"); + boolean response = object.sendSms("+919666666666", "test sms 122", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendFailureWithEmptyPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("", "test sms 122"); + boolean response = object.sendSms("", "test sms 122", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendFailureWithEmptyMessage() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("9663890445", ""); + boolean response = object.sendSms("9663890445", "", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendWithEmptyPhoneAndMessage() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("", ""); + boolean response = object.sendSms("", "", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendFailureWithInvalidPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("981se12345", "some message"); + boolean response = object.sendSms("981se12345", "some message", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendSuccessWithValidPhone() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class),Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("1111111111", "some message"); + boolean response = object.sendSms("1111111111", "some message", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendSuccessWithCountryCode() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class),Mockito.any(String.class), Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("1234567898", "91", "some message"); + boolean response = object.sendSms("1234567898", "91", "some message", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendSuccessWithCountryCodeAndPlus() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendSms(Mockito.any(String.class),Mockito.any(String.class),Mockito.any(String.class),Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); - boolean response = object.sendSms("0000000000", "+91", "some message"); + boolean response = object.sendSms("0000000000", "+91", "some message", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendSuccessWithMultiplePhones() { - ISmsProvider object = SMSFactory.getInstance("91SMS", config); + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.bulkSms(Mockito.any(List.class),Mockito.any(String.class), Mockito.any())).thenReturn(true); List phones = new ArrayList<>(); phones.add("1234567898"); phones.add("1111111111"); - boolean response = object.bulkSms(phones, "some message"); + ISmsProvider object = SMSFactory.getInstance("91SMS", config); + boolean response = object.bulkSms(phones, "some message", new RequestContext()); Assert.assertTrue(response); } @Test public void testSendFailureWithMultipleInvalidPhones() { - ISmsProvider object = SMSFactory.getInstance("91SMS", config); List phones = new ArrayList<>(); phones.add("12345678"); phones.add("11111"); - boolean response = object.bulkSms(phones, "some message"); + ISmsProvider object = SMSFactory.getInstance("91SMS", config); + boolean response = object.bulkSms(phones, "some message", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendFailureWithMultipleInvalidPhonesAndEmptyMsg() { - ISmsProvider object = SMSFactory.getInstance("91SMS", config); List phones = new ArrayList<>(); phones.add("12345678"); phones.add("11111"); - boolean response = object.bulkSms(phones, " "); + ISmsProvider object = SMSFactory.getInstance("91SMS", config); + boolean response = object.bulkSms(phones, " ", new RequestContext()); Assert.assertFalse(response); } @Test public void testSendOtpSuccess() { + PowerMockito.mockStatic(SMSFactory.class); + ISmsProvider msg91SmsProvider = PowerMockito.mock(Msg91SmsProviderImpl.class); + PowerMockito.when(SMSFactory.getInstance(Mockito.any(String.class),Mockito.any(SMSConfig.class))).thenReturn(msg91SmsProvider); + PowerMockito.when(msg91SmsProvider.sendOtp(Mockito.any(OTPRequest.class),Mockito.any())).thenReturn(true); ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("9663845334", "91", 5, 10, null, null); - boolean response = object.sendOtp(request); + boolean response = object.sendOtp(request, new RequestContext()); Assert.assertTrue(response); } @@ -151,7 +194,7 @@ public void testSendOtpSuccess() { public void testSendOtpFailureWithIncorrectPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("96638453", "91", 5, 10, null, null); - boolean response = object.sendOtp(request); + boolean response = object.sendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -159,7 +202,7 @@ public void testSendOtpFailureWithIncorrectPhone() { public void testSendOtpFailureWithPhoneLengthExceed() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("9663845354321", "91", 5, 10, null, null); - boolean response = object.sendOtp(request); + boolean response = object.sendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -167,7 +210,7 @@ public void testSendOtpFailureWithPhoneLengthExceed() { public void testSendOtpFailureDueTOMinOtpLength() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("9663845354", "91", 3, 10, null, null); - boolean response = object.sendOtp(request); + boolean response = object.sendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -175,7 +218,7 @@ public void testSendOtpFailureDueTOMinOtpLength() { public void testSendOtpFailureDueTOMaxOtpLength() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("9663845354", "91", 10, 10, null, null); - boolean response = object.sendOtp(request); + boolean response = object.sendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -183,7 +226,7 @@ public void testSendOtpFailureDueTOMaxOtpLength() { public void testresendOtpFailure() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("96638453", "91", 0, 10, null, null); - boolean response = object.resendOtp(request); + boolean response = object.resendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -191,7 +234,7 @@ public void testresendOtpFailure() { public void testresendOtpFailureWithInvalidPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("96638453234", "91", 0, 10, null, null); - boolean response = object.resendOtp(request); + boolean response = object.resendOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -199,7 +242,7 @@ public void testresendOtpFailureWithInvalidPhone() { public void testverifyOtpFailureWithInvalidPhone() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("96638453234", "91", 0, 10, null, null); - boolean response = object.verifyOtp(request); + boolean response = object.verifyOtp(request, new RequestContext()); Assert.assertFalse(response); } @@ -207,7 +250,7 @@ public void testverifyOtpFailureWithInvalidPhone() { public void testverifyOtpFailureWithInvalidOtpLength() { ISmsProvider object = SMSFactory.getInstance("91SMS", config); OTPRequest request = new OTPRequest("96638453234", "91", 0, 10, null, "234"); - boolean response = object.verifyOtp(request); + boolean response = object.verifyOtp(request, new RequestContext()); Assert.assertFalse(response); } } diff --git a/pom.xml b/pom.xml index 7ac5f896..89f4d74a 100644 --- a/pom.xml +++ b/pom.xml @@ -11,23 +11,21 @@ 1.0.0 UTF-8 UTF-8 - - 1.8 - 1.8 + + 11 + 11 + 11 2.9.9 - 2.6.0-M2 + 2.5.22 4.12 - 2.3.1 1.1.1 - 1.6.1 - 1.0.7 UTF-8 2.7.2 1.0.0-rc5 2.12.8 - 1.6.5 + 2.0.2 4.5.1 diff --git a/sb-utils/pom.xml b/sb-utils/pom.xml index cb9cf5e6..9b6de46a 100644 --- a/sb-utils/pom.xml +++ b/sb-utils/pom.xml @@ -18,21 +18,34 @@ reflections 0.9.10 - - log4j - log4j - 1.2.17 - + com.fasterxml.jackson.core jackson-databind ${jackson.version} + org.apache.commons commons-lang3 3.9 + + + com.typesafe.akka + akka-slf4j_2.12 + ${akka.x.version} + + + + + net.logstash.logback + logstash-logback-encoder + 6.6 + compile + + + diff --git a/sb-utils/src/main/java/org.sunbird/JsonKey.java b/sb-utils/src/main/java/org.sunbird/JsonKey.java index 4c4b8727..b605c4ca 100644 --- a/sb-utils/src/main/java/org.sunbird/JsonKey.java +++ b/sb-utils/src/main/java/org.sunbird/JsonKey.java @@ -8,29 +8,26 @@ */ public interface JsonKey { - String MESSAGE = "message"; - String ERRORS = "errors"; - String SUCCESS = "success"; String NOTIFICATION = "notification"; String NOTIFICATIONS = "notifications"; String DELIVERY_TYPE = "deliveryType"; String MODE = "mode"; String IDS = "ids"; - String PHONE = "phone"; - String DEVICE = "device"; - String EMAIL = "email"; - String CONFIG = "config"; - String TEMPLATE = "template"; - String RAWDATA = "rawData"; - String OTP = "otp"; - String TOPIC = "topic"; - String LENGTH = "length"; - String EXPIRY = "expiry"; - String SENDER = "sender"; - String ID = "id"; - String DATA = "data"; - String PARAMS = "params"; String MANDATORY_PARAMETER_MISSING = "MANDATORY_PARAMETER_MISSING"; String INVALID_VALUE = "INVALID_VALUE"; String VERIFY_OTP = "verifyOtp"; + + String APP_ID = "appId"; + String DEVICE_ID = "did"; + String X_Session_ID = "x-session-id"; + String X_APP_VERSION = "x-app-ver"; + String X_TRACE_ENABLED = "x-trace-enabled"; + String X_REQUEST_ID = "x-request-id"; + String ACTOR_ID = "actorId"; + + String TYPE = "type"; + String LEVEL = "level"; + String REQUEST_ID = "requestid"; + String MESSAGE = "message"; + String PARAMS = "params"; } diff --git a/sb-utils/src/main/java/org.sunbird/message/IResponseMessage.java b/sb-utils/src/main/java/org.sunbird/message/IResponseMessage.java index 0f6207a7..e5ff11aa 100644 --- a/sb-utils/src/main/java/org.sunbird/message/IResponseMessage.java +++ b/sb-utils/src/main/java/org.sunbird/message/IResponseMessage.java @@ -11,9 +11,8 @@ public interface IResponseMessage extends IUserResponseMessage, IOrgResponseMess String INVALID_OPERATION_NAME = "INVALID_OPERATION_NAME"; String INTERNAL_ERROR = "INTERNAL_ERROR"; String SERVER_ERROR = "INTERNAL_ERROR"; - String UNAUTHORIZED = "UNAUTHORIZED"; String MANDATORY_PARAMETER_MISSING = "Mandatory parameter {0} is missing."; String INVALID_VALUE = "{0} VALUE IS INVALID, {1}"; - String DATA_TYPE_REQUIRED = "{0} SHOULD BE {1}"; String MAX_NOTIFICATION_SIZE = "Max supported id in single playload is {0}"; + String SERVICE_UNAVAILABLE = "SERVICE UNAVAILABLE"; } diff --git a/sb-utils/src/main/java/org.sunbird/message/ResponseCode.java b/sb-utils/src/main/java/org.sunbird/message/ResponseCode.java index 43ba3020..14aa0030 100644 --- a/sb-utils/src/main/java/org.sunbird/message/ResponseCode.java +++ b/sb-utils/src/main/java/org.sunbird/message/ResponseCode.java @@ -23,4 +23,20 @@ public int getCode() { return this.code; } + public static ResponseCode getResponseCode(int code) { + if (code > 0) { + try { + ResponseCode[] arr = ResponseCode.values(); + if (null != arr) { + for (ResponseCode rc : arr) { + if (rc.getCode() == code) return rc; + } + } + } catch (Exception e) { + return ResponseCode.SERVER_ERROR; + } + } + return ResponseCode.SERVER_ERROR; + } + } diff --git a/sb-utils/src/main/java/org.sunbird/request/EntryExitLogEvent.java b/sb-utils/src/main/java/org.sunbird/request/EntryExitLogEvent.java new file mode 100644 index 00000000..c2ae63f8 --- /dev/null +++ b/sb-utils/src/main/java/org.sunbird/request/EntryExitLogEvent.java @@ -0,0 +1,47 @@ +package org.sunbird.request; + +import org.sunbird.JsonKey; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EntryExitLogEvent { + private String eid; + + private Map edata = new HashMap<>(); + + public String getEid() { + return eid; + } + + public void setEid(String eid) { + this.eid = eid; + } + + public Map getEdata() { + return edata; + } + + public void setEdata( + String type, + String level, + String requestid, + String message, + List> params) { + this.edata.put(JsonKey.TYPE, type); + this.edata.put(JsonKey.LEVEL, level); + this.edata.put(JsonKey.REQUEST_ID, requestid); + this.edata.put(JsonKey.MESSAGE, message); + this.edata.put(JsonKey.PARAMS, params); + } + + public void setEdataParams(List> params) { + this.edata.put(JsonKey.PARAMS, params); + } + + @Override + public String toString() { + return "{" + "eid='" + eid + '\'' + ", edata=" + edata + '}'; + } +} diff --git a/sb-utils/src/main/java/org.sunbird/request/HeaderParam.java b/sb-utils/src/main/java/org.sunbird/request/HeaderParam.java index b418e5e2..d5450584 100644 --- a/sb-utils/src/main/java/org.sunbird/request/HeaderParam.java +++ b/sb-utils/src/main/java/org.sunbird/request/HeaderParam.java @@ -29,7 +29,11 @@ public enum HeaderParam { X_Authenticated_Client_Id("x-authenticated-client-id"), X_APP_ID("x-app-id"), CHANNEL_ID("x-channel-id"), - X_Response_Length("x-response-length"); + X_Response_Length("x-response-length"), + X_Trace_ID("x-trace-id"), + X_REQUEST_ID("x-request-id"), + X_TRACE_ENABLED("x-trace-enabled"), + X_APP_VERSION("x-app-ver"); /** name of the parameter */ private String name; diff --git a/sb-utils/src/main/java/org.sunbird/request/LoggerUtil.java b/sb-utils/src/main/java/org.sunbird/request/LoggerUtil.java new file mode 100644 index 00000000..20804b75 --- /dev/null +++ b/sb-utils/src/main/java/org.sunbird/request/LoggerUtil.java @@ -0,0 +1,78 @@ +package org.sunbird.request; + +import net.logstash.logback.marker.Markers; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class LoggerUtil { + + private Logger logger; + + public LoggerUtil(Class c) { + logger = LoggerFactory.getLogger(c); + } + + public void info(RequestContext requestContext, String message) { + if (null != requestContext) { + logger.info(Markers.appendEntries(requestContext.getContextMap()), message); + } else { + logger.info(message); + } + } + + public void info(String message) { + logger.info(message); + } + + public void error(RequestContext requestContext, String message, Throwable e) { + if (null != requestContext) { + logger.error(Markers.appendEntries(requestContext.getContextMap()), message, e); + } else { + logger.error(message, e); + } + } + + public void error(String message, Throwable e) { + logger.error(message, e); + } + + public void error( + RequestContext requestContext, + String message, + Throwable e, + Map telemetryInfo) { + if (null != requestContext) { + logger.error(Markers.appendEntries(requestContext.getContextMap()), message, e); + } else { + logger.error(message, e); + } + } + + public void warn(RequestContext requestContext, String message, Throwable e) { + if (null != requestContext) { + logger.warn(Markers.appendEntries(requestContext.getContextMap()), message, e); + } else { + logger.warn(message, e); + } + } + + public void debug(RequestContext requestContext, String message) { + if (isDebugEnabled(requestContext)) { + logger.info(Markers.appendEntries(requestContext.getContextMap()), message); + } else { + logger.debug(message); + } + } + + public void debug(String message) { + logger.debug(message); + } + + private static boolean isDebugEnabled(RequestContext requestContext) { + return (null != requestContext + && StringUtils.equalsIgnoreCase("true", requestContext.getDebugEnabled())); + } +} diff --git a/sb-utils/src/main/java/org.sunbird/request/Request.java b/sb-utils/src/main/java/org.sunbird/request/Request.java index 58b41cf3..12e4e7fe 100644 --- a/sb-utils/src/main/java/org.sunbird/request/Request.java +++ b/sb-utils/src/main/java/org.sunbird/request/Request.java @@ -11,6 +11,7 @@ import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; /** @author Manzarul */ @JsonIgnoreProperties(ignoreUnknown = true) @@ -21,12 +22,16 @@ public class Request implements Serializable { private static final Integer MAX_TIMEOUT = 30; private static final int WAIT_TIME_VALUE = 30; - protected Map context; private String id; private String ver; private String ts; private RequestParams params; + // Request context + private RequestContext requestContext; + + private Map context; + private Map request = new HashMap<>(); private String managerName; @@ -37,6 +42,7 @@ public class Request implements Serializable { private Integer timeout; // in seconds public Request() { + this.context = new WeakHashMap<>(); this.params = new RequestParams(); this.params.setMsgid(requestId); } @@ -47,7 +53,6 @@ public Request(Request request) { if (null == this.params) this.params = new RequestParams(); if (StringUtils.isBlank(this.params.getMsgid()) && !StringUtils.isBlank(requestId)) this.params.setMsgid(requestId); - this.context.putAll(request.getContext()); } public String getRequestId() { @@ -55,6 +60,14 @@ public String getRequestId() { return requestId; } + public RequestContext getRequestContext() { + return requestContext; + } + + public void setRequestContext(RequestContext requestContext) { + this.requestContext = requestContext; + } + public Map getContext() { return context; } @@ -106,14 +119,6 @@ public void copyRequestValueObjects(Map map) { } } - @Override - public String toString() { - return "Request [" - + (context != null ? "context=" + context + ", " : "") - + (request != null ? "requestValueObjects=" + request : "") - + "]"; - } - public String getId() { return id; } diff --git a/sb-utils/src/main/java/org.sunbird/request/RequestContext.java b/sb-utils/src/main/java/org.sunbird/request/RequestContext.java new file mode 100644 index 00000000..b6ba2fdd --- /dev/null +++ b/sb-utils/src/main/java/org.sunbird/request/RequestContext.java @@ -0,0 +1,114 @@ +package org.sunbird.request; + +import java.util.HashMap; +import java.util.Map; + +public class RequestContext { + private String uid; + private String did; + private String sid; + private String appId; + private String appVer; + private String reqId; + private String debugEnabled; + private String op; + private Map contextMap = new HashMap<>(); + + public RequestContext() {} + + public RequestContext( + String uid, + String did, + String sid, + String appId, + String appVer, + String reqId, + String debugEnabled, + String op) { + super(); + this.uid = uid; + this.did = did; + this.sid = sid; + this.appId = appId; + this.appVer = appVer; + this.reqId = reqId; + this.debugEnabled = debugEnabled; + this.op = op; + + contextMap.put("uid", uid); + contextMap.put("did", did); + contextMap.put("sid", sid); + contextMap.put("appId", appId); + contextMap.put("appVer", appVer); + contextMap.put("reqId", reqId); + contextMap.put("op", op); + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + + public String getSid() { + return sid; + } + + public void setSid(String sid) { + this.sid = sid; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppVer() { + return appVer; + } + + public void setAppVer(String appVer) { + this.appVer = appVer; + } + + public String getReqId() { + return reqId; + } + + public void setReqId(String reqId) { + this.reqId = reqId; + } + + public String getDebugEnabled() { + return debugEnabled; + } + + public void setDebugEnabled(String debugEnabled) { + this.debugEnabled = debugEnabled; + } + + public String getOp() { + return op; + } + + public void setOp(String op) { + this.op = op; + } + + public Map getContextMap() { + return contextMap; + } +} diff --git a/sb-utils/src/main/java/org.sunbird/response/Response.java b/sb-utils/src/main/java/org.sunbird/response/Response.java index adcf201b..7c6e02fb 100644 --- a/sb-utils/src/main/java/org.sunbird/response/Response.java +++ b/sb-utils/src/main/java/org.sunbird/response/Response.java @@ -1,5 +1,7 @@ package org.sunbird.response; +import org.sunbird.message.ResponseCode; + import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -15,8 +17,8 @@ public class Response implements Serializable, Cloneable { private String id; private String ver; private String ts; - private ResponseParams params; - private String responseCode; + private ResponseParams params = new ResponseParams(); + private ResponseCode responseCode = ResponseCode.OK; private Map result = new HashMap<>(); /** @@ -126,7 +128,7 @@ public void setParams(ResponseParams params) { * * @param code ResponseCode */ - public void setResponseCode(String code) { + public void setResponseCode(ResponseCode code) { this.responseCode = code; } @@ -135,7 +137,7 @@ public void setResponseCode(String code) { * * @return ResponseCode */ - public String getResponseCode() { + public ResponseCode getResponseCode() { return this.responseCode; } diff --git a/service/.pom.xml.swp b/service/.pom.xml.swp deleted file mode 100644 index f193ba8f..00000000 Binary files a/service/.pom.xml.swp and /dev/null differ diff --git a/service/app/controllers/RequestHandler.java b/service/app/controllers/RequestHandler.java index 4fbbaee8..9cd68d26 100644 --- a/service/app/controllers/RequestHandler.java +++ b/service/app/controllers/RequestHandler.java @@ -3,22 +3,37 @@ import akka.pattern.Patterns; import akka.util.Timeout; import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.WeakHashMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import org.apache.commons.lang3.StringUtils; import org.sunbird.BaseException; import org.sunbird.message.IResponseMessage; +import org.sunbird.message.ResponseCode; +import org.sunbird.request.HeaderParam; +import org.sunbird.request.LoggerUtil; import org.sunbird.request.Request; +import org.sunbird.request.RequestContext; import org.sunbird.response.Response; +import org.sunbird.response.ResponseParams; import play.libs.Json; import play.libs.concurrent.HttpExecutionContext; import play.mvc.Result; import play.mvc.Results; -import scala.concurrent.Await; +import scala.compat.java8.FutureConverters; import scala.concurrent.Future; import utils.JsonKey; +import static utils.PrintEntryExitLog.printEntryLog; +import static utils.PrintEntryExitLog.printExitLogOnFailure; +import static utils.PrintEntryExitLog.printExitLogOnSuccessResponse; + /** * this class is used to handle the request and ask from actor and return response on the basis of * success and failure to user. @@ -26,33 +41,76 @@ * @author amitkumar */ public class RequestHandler extends BaseController { - /** - * this methis responsible to handle the request and ask from actor - * - * @param request - * @param httpExecutionContext - * @param operation - * @return CompletionStage - * @throws Exception - */ - public CompletionStage handleRequest( - Request request, - HttpExecutionContext httpExecutionContext, - String operation, - play.mvc.Http.Request req) - throws Exception { - Object obj; - CompletableFuture cf = new CompletableFuture<>(); - request.setOperation(operation); - // ProjectLogger.log(String.format("%s:%s:Requested operation - // %s",this.getClass().getSimpleName(),"handleRequest",operation), LoggerEnum.DEBUG.name()); - // startTrace("handleRequest"); - Timeout t = new Timeout(Long.valueOf(request.getTimeout()), TimeUnit.SECONDS); - Future future = Patterns.ask(getActorRef(operation), request, t); - obj = Await.result(future, t.duration()); - // endTrace("handleRequest"); - return handleResponse(obj, httpExecutionContext, req); - } + + private static LoggerUtil logger = new LoggerUtil(RequestHandler.class); + + /** + * this methis responsible to handle the request and ask from actor + * + * @param request + * @param httpExecutionContext + * @param operation + * @return CompletionStage + * @throws Exception + */ + public CompletionStage handleRequest( + Request request, + HttpExecutionContext httpExecutionContext, + String operation, + play.mvc.Http.Request req) + throws Exception { + request.setOperation(operation); + setContextData(req, request); + printEntryLog(request); + Function fn = + object -> handleResponse(object, httpExecutionContext, req, request); + + Timeout t = new Timeout(Long.valueOf(request.getTimeout()), TimeUnit.SECONDS); + Future future = Patterns.ask(getActorRef(operation), request, t); + return FutureConverters.toJava(future).thenApplyAsync(fn); + } + + /** + * This method will handle all the failure response of Api calls. + * + * @param exception + * @return + */ + public static Result handleFailureResponse( + Object exception, HttpExecutionContext httpExecutionContext ,play.mvc.Http.Request req, Request request) { + + Response response = new Response(); + response.getParams().setStatus(JsonKey.FAILED); + response.getParams().setMsgid(request.getRequestId()); + CompletableFuture future = new CompletableFuture<>(); + if (exception instanceof BaseException) { + BaseException ex = (BaseException) exception; + response.setResponseCode(ResponseCode.getResponseCode(ex.getResponseCode())); + response.put(JsonKey.MESSAGE, ex.getMessage()); + String apiId = getApiId(req.path()); + response.setId(apiId); + response.setVer("v1"); + response.setTs(System.currentTimeMillis() + ""); + future.complete(Json.toJson(response)); + printExitLogOnFailure(request,ex); + if (ex.getResponseCode() == Results.badRequest().status()) { + return Results.badRequest(Json.toJson(response)); + } else if (ex.getResponseCode() == 503) { + return Results.status( + ex.getResponseCode(), + Json.toJson(createResponseOnException(ex))); + } else { + return Results.internalServerError(); + } + } else { + response.setResponseCode(ResponseCode.SERVER_ERROR); + response.put( + JsonKey.MESSAGE, locale.getMessage(IResponseMessage.INTERNAL_ERROR, null)); + future.complete(Json.toJson(response)); + printExitLogOnFailure(request, null); + return Results.internalServerError(Json.toJson(response)); + } + } /** * This method will handle all the failure response of Api calls. @@ -60,14 +118,14 @@ public CompletionStage handleRequest( * @param exception * @return */ - public static CompletionStage handleFailureResponse( - Object exception, HttpExecutionContext httpExecutionContext, play.mvc.Http.Request req) { + public static Result handleFailureResponse( + Object exception, HttpExecutionContext httpExecutionContext ,play.mvc.Http.Request req) { Response response = new Response(); CompletableFuture future = new CompletableFuture<>(); if (exception instanceof BaseException) { BaseException ex = (BaseException) exception; - response.setResponseCode(ex.getCode()); + response.setResponseCode(ResponseCode.getResponseCode(ex.getResponseCode())); response.put(JsonKey.MESSAGE, ex.getMessage()); String apiId = getApiId(req.path()); response.setId(apiId); @@ -75,66 +133,155 @@ public static CompletionStage handleFailureResponse( response.setTs(System.currentTimeMillis() + ""); future.complete(Json.toJson(response)); if (ex.getResponseCode() == Results.badRequest().status()) { - return future.thenApplyAsync(Results::badRequest, httpExecutionContext.current()); + return Results.badRequest(Json.toJson(response)); + } else if (ex.getResponseCode() == 503) { + return Results.status( + ex.getResponseCode(), + Json.toJson(createResponseOnException(ex))); } else { - return future.thenApplyAsync(Results::internalServerError, httpExecutionContext.current()); + return Results.internalServerError(); } } else { - response.setResponseCode(IResponseMessage.SERVER_ERROR); + response.setResponseCode(ResponseCode.SERVER_ERROR); response.put( - JsonKey.MESSAGE, localizerObject.getMessage(IResponseMessage.INTERNAL_ERROR, null)); + JsonKey.MESSAGE, locale.getMessage(IResponseMessage.INTERNAL_ERROR, null)); future.complete(Json.toJson(response)); - return future.thenApplyAsync(Results::internalServerError, httpExecutionContext.current()); + return Results.internalServerError(Json.toJson(response)); } } - /** - * this method will divert the response on the basis of success and failure - * - * @param object - * @param httpExecutionContext - * @return - */ - public static CompletionStage handleResponse( - Object object, HttpExecutionContext httpExecutionContext, play.mvc.Http.Request req) { - if (object instanceof Response) { - Response response = (Response) object; - return handleSuccessResponse(response, httpExecutionContext, req); - } else { - return handleFailureResponse(object, httpExecutionContext, req); + public static Response createResponseOnException(BaseException exception) { + Response response = new Response(); + response.setResponseCode(ResponseCode.getResponseCode(exception.getResponseCode())); + response.setParams(createResponseParamObj(response.getResponseCode(), exception.getMessage())); + return response; } - } - /** - * This method will handle all the success response of Api calls. - * - * @param response - * @return - */ - public static CompletionStage handleSuccessResponse( - Response response, HttpExecutionContext httpExecutionContext, play.mvc.Http.Request req) { - CompletableFuture future = new CompletableFuture<>(); - String apiId = getApiId(req.path()); - response.setId(apiId); - response.setVer("v1"); - response.setTs(System.currentTimeMillis() + ""); - future.complete(Json.toJson(response)); - return future.thenApplyAsync(Results::ok, httpExecutionContext.current()); - } + public static ResponseParams createResponseParamObj(ResponseCode code, String message) { + ResponseParams params = new ResponseParams(); + if (code.getCode() != 200) { + params.setErr(code.name()); + params.setErrmsg(StringUtils.isNotBlank(message) ? message : code.name()); + } + params.setStatus(ResponseCode.getResponseCode(code.getCode()).name()); + return params; + } - public static String getApiId(String uri) { - StringBuilder builder = new StringBuilder(); - if (StringUtils.isNotBlank(uri)) { - String temVal[] = uri.split("/"); - for (int i = 1; i < temVal.length; i++) { - if (i < temVal.length - 1) { - builder.append(temVal[i] + "."); + /** + * this method will divert the response on the basis of success and failure + * + * @param object + * @param httpExecutionContext + * @return + */ + public static Result handleResponse( + Object object, HttpExecutionContext httpExecutionContext, play.mvc.Http.Request req, Request request) { + + if (object instanceof Response) { + Response response = (Response) object; + response.setParams(createResponseParamObj(response.getResponseCode(), null)); + response.getParams().setMsgid(request.getRequestContext().getReqId()); + printExitLogOnSuccessResponse(request, response); + return handleSuccessResponse(response, httpExecutionContext, req); } else { - builder.append(temVal[i]); + return handleFailureResponse(object, httpExecutionContext, req, request); } + } + + /** + * This method will handle all the success response of Api calls. + * + * @param response + * @return + */ + public static Result handleSuccessResponse( + Response response, HttpExecutionContext httpExecutionContext, play.mvc.Http.Request req) { + CompletableFuture future = new CompletableFuture<>(); + String apiId = getApiId(req.path()); + response.setId(apiId); + response.setVer("v1"); + response.setTs(System.currentTimeMillis() + ""); + response.getParams().setStatus(JsonKey.SUCCESS); + future.complete(Json.toJson(response)); + return Results.ok(Json.toJson(response)); + } + + public static String getApiId(String uri) { + StringBuilder builder = new StringBuilder(); + if (StringUtils.isNotBlank(uri)) { + String temVal[] = uri.split("/"); + for (int i = 1; i < temVal.length; i++) { + if (i < temVal.length - 1) { + builder.append(temVal[i] + "."); + } else { + builder.append(temVal[i]); + } + } + } + return builder.toString(); + } + + + public void setContextData(play.mvc.Http.Request httpReq, Request request) { + try { + Map reqContext = new WeakHashMap<>(); + Optional optionalAppId = httpReq.header(HeaderParam.X_APP_ID.getName()); + if (optionalAppId.isPresent()) { + reqContext.put(org.sunbird.JsonKey.APP_ID, optionalAppId.get()); } + Optional optionalDeviceId = httpReq.header(HeaderParam.X_Device_ID.getName()); + if (optionalDeviceId.isPresent()) { + reqContext.put(org.sunbird.JsonKey.DEVICE_ID, optionalDeviceId.get()); + } + + Optional optionalSessionId = httpReq.header(HeaderParam.X_Session_ID.getName()); + if (optionalSessionId.isPresent()) { + reqContext.put(org.sunbird.JsonKey.X_Session_ID, optionalSessionId.get()); + } + + Optional optionalAppVersion = httpReq.header(HeaderParam.X_APP_VERSION.getName()); + if (optionalAppVersion.isPresent()) { + reqContext.put(org.sunbird.JsonKey.X_APP_VERSION, optionalAppVersion.get()); + } + + Optional optionalTraceEnabled = httpReq.header(HeaderParam.X_TRACE_ENABLED.getName()); + if (optionalTraceEnabled.isPresent()) { + reqContext.put(org.sunbird.JsonKey.X_TRACE_ENABLED, optionalTraceEnabled.get()); + } + + Optional optionalTraceId = httpReq.header(HeaderParam.X_REQUEST_ID.getName()); + if (optionalTraceId.isPresent()) { + String reqId = optionalTraceId.get(); + reqContext.put(org.sunbird.JsonKey.X_REQUEST_ID, reqId); + request.setRequestId(optionalTraceId.get()); + } else { + String reqId = UUID.randomUUID().toString(); + reqContext.put(org.sunbird.JsonKey.X_REQUEST_ID, reqId); + request.setRequestId(reqId); + } + request.getContext().put(JsonKey.URL,httpReq.uri()); + request.getContext().put(JsonKey.METHOD,httpReq.method()); + request.setRequestContext( + getRequestContext( + reqContext, request.getOperation())); + } catch (Exception ex) { + logger.error("Exception occurred while setting request context.", ex); } - return builder.toString(); } -} + + private RequestContext getRequestContext(Map context, String actorOperation) { + return new RequestContext( + (String) context.get(org.sunbird.JsonKey.ACTOR_ID), + (String) context.get(org.sunbird.JsonKey.DEVICE_ID), + (String) context.get(org.sunbird.JsonKey.X_Session_ID), + (String) context.get(org.sunbird.JsonKey.APP_ID), + (String) context.get(org.sunbird.JsonKey.X_APP_VERSION), + (String) context.get(org.sunbird.JsonKey.X_REQUEST_ID), + (String) + ((context.get(org.sunbird.JsonKey.X_TRACE_ENABLED) != null) + ? context.get(org.sunbird.JsonKey.X_TRACE_ENABLED) + : "false"), + actorOperation); + } +} \ No newline at end of file diff --git a/service/app/controllers/health/HealthController.java b/service/app/controllers/health/HealthController.java index 350ef1dd..2efc943d 100644 --- a/service/app/controllers/health/HealthController.java +++ b/service/app/controllers/health/HealthController.java @@ -4,12 +4,18 @@ import controllers.BaseController; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; + +import controllers.RequestHandler; +import org.sunbird.BaseException; +import org.sunbird.message.IResponseMessage; +import org.sunbird.message.ResponseCode; +import org.sunbird.request.LoggerUtil; import org.sunbird.response.Response; import play.libs.Json; import play.mvc.Result; -import play.mvc.Results; +import utils.module.SignalHandler; + +import javax.inject.Inject; /** * This controller class will responsible to check health of the services. @@ -17,7 +23,9 @@ * @author Anmol */ public class HealthController extends BaseController { - Logger logger = LogManager.getLogger(HealthController.class); + private static LoggerUtil logger = new LoggerUtil(HealthController.class); + @Inject + SignalHandler signalHandler; // Service name must be "service" for the devops monitoring. private static final String service = "service"; private static final String HEALTH_ACTOR_OPERATION_NAME = "health"; @@ -28,9 +36,14 @@ public class HealthController extends BaseController { * @return a CompletableFuture of success response */ public CompletionStage getHealth() { - logger.info("complete health method called."); - CompletionStage response = handleRequest(request(), null, HEALTH_ACTOR_OPERATION_NAME); - return response; + try { + handleSigTerm(); + logger.info("complete health method called."); + CompletionStage response = handleRequest(request(), null, HEALTH_ACTOR_OPERATION_NAME); + return response; + } catch (Exception e) { + return CompletableFuture.completedFuture(RequestHandler.handleFailureResponse(e,httpExecutionContext,request())); + } } /** @@ -39,13 +52,27 @@ public CompletionStage getHealth() { * @return a CompletableFuture of success response */ public CompletionStage getServiceHealth(String health) { - logger.info("get healh called for service =." + health); - CompletableFuture cf = new CompletableFuture<>(); - Response response = new Response(); - response.put(RESPONSE, SUCCESS); - cf.complete(Json.toJson(response)); - return service.equalsIgnoreCase(health) - ? cf.thenApplyAsync(Results::ok) - : cf.thenApplyAsync(Results::badRequest); + + try { + handleSigTerm(); + logger.info("get healh called for service =." + health); + CompletableFuture cf = new CompletableFuture<>(); + Response response = new Response(); + response.put(RESPONSE, SUCCESS); + cf.complete(Json.toJson(response)); + return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); + } catch (Exception e) { + return CompletableFuture.completedFuture(RequestHandler.handleFailureResponse(e,httpExecutionContext,request())); + } + } + + private void handleSigTerm() throws BaseException { + if (signalHandler.isShuttingDown()) { + logger.info( + "SIGTERM is " + + signalHandler.isShuttingDown() + + ", So play server will not allow any new request."); + throw new BaseException(IResponseMessage.SERVICE_UNAVAILABLE, IResponseMessage.SERVICE_UNAVAILABLE, ResponseCode.SERVICE_UNAVAILABLE.getCode()); + } } } diff --git a/service/app/controllers/notification/NotificationController.java b/service/app/controllers/notification/NotificationController.java index 254c9282..c9167fd3 100644 --- a/service/app/controllers/notification/NotificationController.java +++ b/service/app/controllers/notification/NotificationController.java @@ -3,8 +3,7 @@ import controllers.BaseController; import java.util.concurrent.CompletionStage; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; +import org.sunbird.request.LoggerUtil; import play.mvc.Result; import utils.JsonKey; @@ -14,7 +13,7 @@ * @author manzarul */ public class NotificationController extends BaseController { - Logger logger = LogManager.getLogger(NotificationController.class); + private static LoggerUtil logger = new LoggerUtil(NotificationController.class); public static final String NOTIFICATION = "notification"; diff --git a/service/app/utils/ApplicationStart.java b/service/app/utils/ApplicationStart.java index bce6e635..a6c73213 100644 --- a/service/app/utils/ApplicationStart.java +++ b/service/app/utils/ApplicationStart.java @@ -1,12 +1,12 @@ package utils; - import java.util.concurrent.CompletableFuture; import javax.inject.Inject; import javax.inject.Singleton; import org.sunbird.Application; +import org.sunbird.request.LoggerUtil; import play.api.Environment; import play.api.inject.ApplicationLifecycle; @@ -18,14 +18,15 @@ */ @Singleton public class ApplicationStart { - /** + private static LoggerUtil logger = new LoggerUtil(ApplicationStart.class); + /** + * * All one time initialization which required during server startup will fall here. * @param lifecycle ApplicationLifecycle * @param environment Environment */ @Inject public ApplicationStart(ApplicationLifecycle lifecycle, Environment environment) { - //instantiate actor system and initialize all the actors Application.getInstance().init(); // Shut-down hook lifecycle.addStopHook( diff --git a/service/app/utils/JsonKey.java b/service/app/utils/JsonKey.java index 3d3daa97..820f020c 100644 --- a/service/app/utils/JsonKey.java +++ b/service/app/utils/JsonKey.java @@ -30,4 +30,7 @@ public interface JsonKey { String ERRORS = "errors"; String SUCCESS = "success"; String VERIFY_OTP = "verifyOtp"; + String URL = "url"; + String RESPONSE_CODE = "responseCode"; + String FAILED = "FAILED"; } diff --git a/service/app/utils/PrintEntryExitLog.java b/service/app/utils/PrintEntryExitLog.java new file mode 100644 index 00000000..019cf02a --- /dev/null +++ b/service/app/utils/PrintEntryExitLog.java @@ -0,0 +1,133 @@ +package utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.BaseException; +import org.sunbird.message.ResponseCode; +import org.sunbird.request.EntryExitLogEvent; +import org.sunbird.request.LoggerUtil; +import org.sunbird.request.Request; +import org.sunbird.response.Response; +import org.sunbird.response.ResponseParams; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class PrintEntryExitLog { + + private static LoggerUtil logger = new LoggerUtil(PrintEntryExitLog.class); + private static ObjectMapper objectMapper = new ObjectMapper(); + + public static void printEntryLog(Request request) { + try { + EntryExitLogEvent entryLogEvent = getLogEvent(request, "ENTRY"); + List> params = new ArrayList<>(); + params.add(request.getRequest()); + entryLogEvent.setEdataParams(params); + logger.info(request.getRequestContext(), entryLogEvent.toString()); + } catch (Exception ex) { + logger.error("Exception occurred while logging entry log", ex); + } + } + + public static void printExitLogOnSuccessResponse( + Request request, Response response) { + try { + EntryExitLogEvent exitLogEvent = getLogEvent(request, "EXIT"); + List> params = new ArrayList<>(); + if (null != response) { + if (MapUtils.isNotEmpty(response.getResult())) { + params.add(response.getResult()); + } + + if (null != response.getParams()) { + Map resParam = new HashMap<>(); + resParam.putAll(objectMapper.convertValue(response.getParams(), Map.class)); + resParam.put(JsonKey.RESPONSE_CODE, response.getResponseCode()); + params.add(resParam); + } + } + exitLogEvent.setEdataParams(params); + logger.info(request.getRequestContext(), exitLogEvent.toString()); + } catch (Exception ex) { + logger.error("Exception occurred while logging exit log", ex); + } + } + + public static void printExitLogOnFailure( + Request request, BaseException exception) { + try { + EntryExitLogEvent exitLogEvent = getLogEvent(request, "EXIT"); + String requestId = request.getRequestContext().getReqId(); + List> params = new ArrayList<>(); + if (null == exception) { + exception = + new BaseException( + ResponseCode.SERVER_ERROR.name(), + ResponseCode.SERVER_ERROR.name(), + ResponseCode.SERVER_ERROR.getCode()); + } + + ResponseCode code = ResponseCode.getResponseCode(exception.getResponseCode()); + if (code == null) { + code = ResponseCode.SERVER_ERROR; + } + ResponseParams responseParams = + createResponseParamObj(code, exception.getMessage(), requestId); + if (responseParams != null) { + responseParams.setStatus(JsonKey.FAILED); + if (exception.getCode() != null) { + responseParams.setStatus(JsonKey.FAILED); + } + if (!StringUtils.isBlank(responseParams.getErrmsg()) + && responseParams.getErrmsg().contains("{0}")) { + responseParams.setErrmsg(exception.getMessage()); + } + } + if (null != responseParams) { + Map resParam = new HashMap<>(); + resParam.putAll(objectMapper.convertValue(responseParams, Map.class)); + resParam.put(JsonKey.RESPONSE_CODE, exception.getResponseCode()); + params.add(resParam); + } + exitLogEvent.setEdataParams(params); + logger.info(request.getRequestContext(), exitLogEvent.toString()); + } catch (Exception ex) { + logger.error("Exception occurred while logging exit log", ex); + } + } + + private static EntryExitLogEvent getLogEvent(Request request, String logType) { + EntryExitLogEvent entryLogEvent = new EntryExitLogEvent(); + entryLogEvent.setEid("LOG"); + String url = (String) request.getContext().get(JsonKey.URL); + String entryLogMsg = + logType + + " LOG: method : " + + request.getContext().get(JsonKey.METHOD) + + ", url: " + + url + + " , For Operation : " + + request.getOperation(); + String requestId = request.getRequestContext().getReqId(); + entryLogEvent.setEdata("system", "trace", requestId, entryLogMsg, null); + return entryLogEvent; + } + + public static ResponseParams createResponseParamObj( + ResponseCode code, String customMessage, String requestId) { + ResponseParams params = new ResponseParams(); + if (code.getCode() != 200) { + params.setErr(code.name()); + params.setErrmsg( + StringUtils.isNotBlank(customMessage) ? customMessage : code.name()); + } + params.setStatus(ResponseCode.getResponseCode(code.getCode()).name()); + params.setMsgid(requestId); + return params; + } +} diff --git a/service/app/utils/RequestMapper.java b/service/app/utils/RequestMapper.java index dbce3f26..fdb12893 100644 --- a/service/app/utils/RequestMapper.java +++ b/service/app/utils/RequestMapper.java @@ -4,13 +4,12 @@ package utils; import com.fasterxml.jackson.databind.JsonNode; -import org.apache.log4j.Logger; import org.sunbird.ActorServiceException; -import org.sunbird.BaseActor; import org.sunbird.BaseException; import org.sunbird.message.IResponseMessage; import org.sunbird.message.Localizer; import org.sunbird.message.ResponseCode; +import org.sunbird.request.LoggerUtil; import play.libs.Json; /** @@ -20,7 +19,7 @@ */ public class RequestMapper { - private static Logger logger = Logger.getLogger(BaseActor.class); + private static LoggerUtil logger = new LoggerUtil(RequestMapper.class); /** * Method to map request diff --git a/service/app/utils/module/SignalHandler.java b/service/app/utils/module/SignalHandler.java new file mode 100644 index 00000000..7d979d0a --- /dev/null +++ b/service/app/utils/module/SignalHandler.java @@ -0,0 +1,53 @@ +package utils.module; + +import akka.actor.ActorSystem; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.request.LoggerUtil; +import play.api.Application; +import play.api.Play; +import scala.concurrent.duration.Duration; +import scala.concurrent.duration.FiniteDuration; +import sun.misc.Signal; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; +import java.util.concurrent.TimeUnit; + +@Singleton +public class SignalHandler { + + private static String stopDelay = System.getenv("sigterm_stop_delay"); + private static LoggerUtil logger = new LoggerUtil(SignalHandler.class); + + private volatile boolean isShuttingDown = false; + + + @Inject + public SignalHandler(ActorSystem actorSystem, Provider applicationProvider) { + long delay = 40; + if (StringUtils.isNotBlank(stopDelay)) { + delay = Long.parseLong(stopDelay); + } + FiniteDuration STOP_DELAY = Duration.create(delay, TimeUnit.SECONDS); + Signal.handle( + new Signal("TERM"), + signal -> { + isShuttingDown = true; + logger.info( + "Termination required, swallowing SIGTERM to allow current requests to finish"); + actorSystem + .scheduler() + .scheduleOnce( + STOP_DELAY, + () -> { + Play.stop(applicationProvider.get()); + }, + actorSystem.dispatcher()); + }); + } + + public boolean isShuttingDown() { + return isShuttingDown; + } +} diff --git a/service/app/utils/module/StartModule.java b/service/app/utils/module/StartModule.java index df9ab055..158287c6 100644 --- a/service/app/utils/module/StartModule.java +++ b/service/app/utils/module/StartModule.java @@ -13,6 +13,7 @@ public class StartModule extends AbstractModule { @Override protected void configure() { + bind(SignalHandler.class).asEagerSingleton(); bind(ApplicationStart.class).asEagerSingleton(); } diff --git a/service/conf/application.conf b/service/conf/application.conf index 312bf7de..ce87e293 100755 --- a/service/conf/application.conf +++ b/service/conf/application.conf @@ -1,83 +1,49 @@ # This is the main configuration file for the application. # https://www.playframework.com/documentation/latest/ConfigFile # ~~~~~ -# Play uses HOCON as its configuration file format. HOCON has a number -# of advantages over other config formats, but there are two things that -# can be used when modifying settings. -# -# You can include other configuration files in this main application.conf file: -#include "extra-config.conf" -# -# You can declare variables and substitute for them: -#mykey = ${some.value} -# -# And if an environment variable exists when there is no other subsitution, then -# HOCON will fall back to substituting environment variable: -#mykey = ${JAVA_HOME} ## Akka -# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration # https://www.playframework.com/documentation/latest/JavaAkka#Configuration # ~~~~~ -# Play uses Akka internally and exposes Akka Streams and actors in Websockets and -# other streaming HTTP responses. akka { - # "akka.log-config-on-start" is extraordinarly useful because it log the complete - # configuration at INFO level, including defaults and overrides, so it s worth - # putting at the very top. - # - # Put the following in your conf/logback.xml file: - # - # - # - # And then uncomment this line to debug the configuration. - # - #log-config-on-start = true + stdout-loglevel = "OFF" + loglevel = "OFF" + log-config-on-start = off + actor { + default-dispatcher { + # This will be used if you have set "executor = "fork-join-executor"" + fork-join-executor { + # Min number of threads to cap factor-based parallelism number to + parallelism-min = 8 + + # The parallelism factor is used to determine thread pool size using the + # following formula: ceil(available processors * factor). Resulting size + # is then bounded by the parallelism-min and parallelism-max values. + parallelism-factor = 32.0 + + # Max number of threads to cap factor-based parallelism number to + parallelism-max = 64 + + # Setting to "FIFO" to use queue like peeking mode which "poll" or "LIFO" to use stack + # like peeking mode which "pop". + task-peeking-mode = "FIFO" + } + } + } } ## Secret key # http://www.playframework.com/documentation/latest/ApplicationSecret # ~~~~~ -# The secret key is used to sign Play's session cookie. -# This must be changed for production, but we don't recommend you change it in this file. -play.http.secret.key = "notification12s6wne" - -## Modules -# https://www.playframework.com/documentation/latest/Modules -# ~~~~~ -# Control which modules are loaded when Play starts. Note that modules are -# the replacement for "GlobalSettings", which are deprecated in 2.5.x. -# Please see https://www.playframework.com/documentation/latest/GlobalSettings -# for more information. -# -# You can also extend Play functionality by using one of the publically available -# Play modules: https://playframework.com/documentation/latest/ModuleDirectory -play.modules { - # By default, Play will load any class called Module that is defined - # in the root package (the "app" directory), or you can define them - # explicitly below. - # If there are any built-in modules that you want to disable, you can list them here. - enabled += utils.module.StartModule +#play.crypto.secret = "changeme" - # If there are any built-in modules that you want to disable, you can list them here. - #disabled += "" -} ## Internationalisation # https://www.playframework.com/documentation/latest/JavaI18N -# https://www.playframework.com/documentation/latest/ScalaI18N # ~~~~~ -# Play comes with its own i18n settings, which allow the user's preferred language -# to map through to internal messages, or allow the language to be stored in a cookie. play.i18n { # The application languages langs = [ "en" ] - - # Whether the language cookie should be secure or not - #langCookieSecure = true - - # Whether the HTTP only attribute of the cookie should be set to true - #langCookieHttpOnly = true } ## Play HTTP settings @@ -95,102 +61,55 @@ play.http { # you may need to define a router file `conf/my.application.routes`. # Default to Routes in the root package (aka "apps" folder) (and conf/routes) #router = my.application.Router - - ## Action Creator - # https://www.playframework.com/documentation/latest/JavaActionCreator - # ~~~~~ - #actionCreator = null - - ## ErrorHandler - # https://www.playframework.com/documentation/latest/JavaRouting - # https://www.playframework.com/documentation/latest/ScalaRouting - # ~~~~~ - # If null, will attempt to load a class called ErrorHandler in the root package, #errorHandler = null - - ## Filters - # https://www.playframework.com/documentation/latest/ScalaHttpFilters - # https://www.playframework.com/documentation/latest/JavaHttpFilters - # ~~~~~ - # Filters run code on every request. They can be used to perform - # common logic for all your actions, e.g. adding common headers. - # Defaults to "Filters" in the root package (aka "apps" folder) - # Alternatively you can explicitly register a class here. - #filters += my.application.Filters - - ## Session & Flash - # https://www.playframework.com/documentation/latest/JavaSessionFlash - # https://www.playframework.com/documentation/latest/ScalaSessionFlash - # ~~~~~ - session { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - - # Sets the max-age field of the cookie to 5 minutes. - # NOTE: this only sets when the browser will discard the cookie. Play will consider any - # cookie value with a valid signature to be a valid session forever. To implement a server side session timeout, - # you need to put a timestamp in the session and check it at regular intervals to possibly expire it. - #maxAge = 300 - - # Sets the domain on the session cookie. - #domain = "example.com" - } - - flash { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - } + #TO allow more data in request body + parser.maxDiskBuffer=50MB + parser.maxMemoryBuffer=50MB + secret.key="notification12s6wne" } ## Netty Provider -# https://www.playframework.com/documentation/latest/SettingsNetty # ~~~~~ -play.server.netty { - # Whether the Netty wire should be logged - #log.wire = true - - # If you run Play on Linux, you can use Netty's native socket transport - # for higher performance with less garbage. - #transport = "native" +play.server { + provider = "play.core.server.NettyServerProvider" + netty { + # The number of event loop threads. 0 means let Netty decide, which by default will select 2 times the number of + # available processors. + eventLoopThreads = 30 + + # The transport to use, either jdk or native. + # Native socket transport has higher performance and produces less garbage but are only available on linux + transport = "native" + + # If you run Play on Linux, you can use Netty's native socket transport + # for higher performance with less garbage. + #transport = "native" + maxChunkSize = 30000000 + option { + + # Set whether connections should use TCP keep alive + # child.keepAlive = true + + # Set whether the TCP no delay flag is set + # child.tcpNoDelay = false + + # Set the size of the backlog of TCP connections. The default and exact meaning of this parameter is JDK specific. + # backlog = 100 + } + + http { + # The idle timeout for an open connection after which it will be closed + # Set to null or "infinite" to disable the timeout, but notice that this + # is not encouraged since timeout are important mechanisms to protect your + # servers from malicious attacks or programming mistakes. + idleTimeout = infinite + } + } } ## WS (HTTP Client) -# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS # ~~~~~ -# The HTTP client primarily used for REST APIs. The default client can be -# configured directly, but you can also create different client instances -# with customized settings. You must enable this by adding to build.sbt: -# -# libraryDependencies += ws // or javaWs if using java -# -play.ws { - # Sets HTTP requests not to follow 302 requests - #followRedirects = false - - # Sets the maximum number of open HTTP connections for the client. - #ahc.maxConnectionsTotal = 50 - - ## WS SSL - # https://www.playframework.com/documentation/latest/WsSSL - # ~~~~~ - ssl { - # Configuring HTTPS with Play WS does not require programming. You can - # set up both trustManager and keyManager for mutual authentication, and - # turn on JSSE debugging in development with a reload. - #debug.handshake = true - #trustManager = { - # stores = [ - # { type = "JKS", path = "exampletrust.jks" } - # ] - #} - } -} +libraryDependencies += javaWs ## Cache # https://www.playframework.com/documentation/latest/JavaCache @@ -199,148 +118,38 @@ play.ws { # Play comes with an integrated cache API that can reduce the operational # overhead of repeated requests. You must enable this by adding to build.sbt: # -# libraryDependencies += cache +libraryDependencies += cache # play.cache { # If you want to bind several caches, you can bind the individually #bindCaches = ["db-cache", "user-cache", "session-cache"] } -## Filters -# https://www.playframework.com/documentation/latest/Filters +# Logger # ~~~~~ -# There are a number of built-in filters that can be enabled and configured -# to give Play greater security. You must enable this by adding to build.sbt: -# -# libraryDependencies += filters -# -play.filters { - ## CORS filter configuration - # https://www.playframework.com/documentation/latest/CorsFilter - # ~~~~~ - # CORS is a protocol that allows web applications to make requests from the browser - # across different domains. - # NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has - # dependencies on CORS settings. - cors { - # Filter paths by a whitelist of path prefixes - #pathPrefixes = ["/some/path", ...] - - # The allowed origins. If null, all origins are allowed. - #allowedOrigins = ["http://www.example.com"] - - # The allowed HTTP methods. If null, all methods are allowed - #allowedHttpMethods = ["GET", "POST"] - } +# You can also configure logback (http://logback.qos.ch/), +# by providing an application-logger.xml file in the conf directory. - ## CSRF Filter - # https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter - # https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter - # ~~~~~ - # Play supports multiple methods for verifying that a request is not a CSRF request. - # The primary mechanism is a CSRF token. This token gets placed either in the query string - # or body of every form submitted, and also gets placed in the users session. - # Play then verifies that both tokens are present and match. - csrf { - # Sets the cookie to be sent only over HTTPS - #cookie.secure = true +# Root logger: +logger.root=ERROR - # Defaults to CSRFErrorHandler in the root package. - #errorHandler = MyCSRFErrorHandler - } - - ## Security headers filter configuration - # https://www.playframework.com/documentation/latest/SecurityHeaders - # ~~~~~ - # Defines security headers that prevent XSS attacks. - # If enabled, then all options are set to the below configuration by default: - headers { - # The X-Frame-Options header. If null, the header is not set. - #frameOptions = "DENY" +# Logger used by the framework: +logger.play=OFF - # The X-XSS-Protection header. If null, the header is not set. - #xssProtection = "1; mode=block" +# Logger provided to your application: +#logger.application=DEBUG - # The X-Content-Type-Options header. If null, the header is not set. - #contentTypeOptions = "nosniff" - - # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set. - #permittedCrossDomainPolicies = "master-only" - - # The Content-Security-Policy header. If null, the header is not set. - #contentSecurityPolicy = "default-src 'self'" - } +# APP Specific config +# ~~~~~ +# Application specific configurations can be provided here +play.modules { + enabled += utils.module.StartModule +} - ## Allowed hosts filter configuration - # https://www.playframework.com/documentation/latest/AllowedHostsFilter - # ~~~~~ - # Play provides a filter that lets you configure which hosts can access your application. - # This is useful to prevent cache poisoning attacks. +play.filters { hosts { # Allow requests to example.com, its subdomains, and localhost:9000. allowed = ["localhost:9000","."] } + disabled += play.filters.csrf.CSRFFilter } - -## Evolutions -# https://www.playframework.com/documentation/latest/Evolutions -# ~~~~~ -# Evolutions allows database scripts to be automatically run on startup in dev mode -# for database migrations. You must enable this by adding to build.sbt: -# -# libraryDependencies += evolutions -# -play.evolutions { - # You can disable evolutions for a specific datasource if necessary - #db.default.enabled = false -} - -## Database Connection Pool -# https://www.playframework.com/documentation/latest/SettingsJDBC -# ~~~~~ -# Play doesn't require a JDBC database to run, but you can easily enable one. -# -# libraryDependencies += jdbc -# -play.db { - # The combination of these two settings results in "db.default" as the - # default JDBC pool: - #config = "db" - #default = "default" - - # Play uses HikariCP as the default connection pool. You can override - # settings by changing the prototype: - prototype { - # Sets a fixed JDBC connection pool size of 50 - #hikaricp.minimumIdle = 50 - #hikaricp.maximumPoolSize = 50 - } -} - -## JDBC Datasource -# https://www.playframework.com/documentation/latest/JavaDatabase -# https://www.playframework.com/documentation/latest/ScalaDatabase -# ~~~~~ -# Once JDBC datasource is set up, you can work with several different -# database options: -# -# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick -# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA -# EBean: https://playframework.com/documentation/latest/JavaEbean -# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm -# -db { - # You can declare as many datasources as you want. - # By convention, the default datasource is named `default` - - # https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database - #default.driver = org.h2.Driver - #default.url = "jdbc:h2:mem:play" - #default.username = sa - #default.password = "" - - # You can turn on SQL logging for any datasource - # https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements - #default.logSql=true -} -play.filters.disabled += play.filters.csrf.CSRFFilter diff --git a/service/conf/log4j2.properties b/service/conf/log4j2.properties deleted file mode 100644 index 769b21ca..00000000 --- a/service/conf/log4j2.properties +++ /dev/null @@ -1,24 +0,0 @@ -name = userLoggerConfig -property.filename = logs/app.log -# logs only printing to file -appenders = file -# -------------------------------------------------------------------------------------------- -# configuration to print logs to console -appender.console.type = Console -appender.console.name = STDOUT -appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %d{dd.MM.yyyy HH:mm:ss,SSS} %-5p %c{1}:%L - %m%n -# -------------------------------------------------------------------------------------------- -# configuration to print logs to file -appender.file.type = File -appender.file.name = serviceLogs -appender.file.fileName=${filename} -appender.file.append="true" -# no of max files logs will generate -appender.rollingFile.MaxFileSize=10MB -appender.rolling.strategy.max = 10 -appender.file.layout.type=PatternLayout -appender.file.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n -rootLogger.level = debug -rootLogger.appenderRefs = file, stdout -rootLogger.appenderRef.file.ref = serviceLogs diff --git a/service/conf/logback.xml b/service/conf/logback.xml new file mode 100644 index 00000000..0eae1b3f --- /dev/null +++ b/service/conf/logback.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + timestamp + msg + lname + tname + [ignore] + [ignore] + exception + + + 30 + 2048 + sun\.reflect\..*\.invoke.* + true + true + + + + + + + + + + + + + yyyy-MM-dd'T'HH:mm:ss.SSSX + Etc/UTC + + timestamp + msg + lname + tname + [ignore] + [ignore] + + + + + + + + + + timestamp + msg + lname + tname + [ignore] + [ignore] + exception + + + 30 + 2048 + sun\.reflect\..*\.invoke.* + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/service/pom.xml b/service/pom.xml index 4d674f0c..d862c843 100755 --- a/service/pom.xml +++ b/service/pom.xml @@ -42,12 +42,53 @@ org.scala-lang scala-reflect + + com.typesafe.akka + akka-actor_2.12 + + + slf4j-api + org.slf4j + com.typesafe.play play-guice_2.12 ${play2.version} + + + com.google.inject + guice + + + com.google.inject.extensions + guice-assistedinject + + + + + com.google.inject + guice + 3.0 + + + + com.google.inject.extensions + guice-assistedinject + 3.0 + + + com.typesafe.play + play-netty-server_2.12 + ${play2.version} + runtime + + + org.scala-lang + scala-library + + javax.ws.rs @@ -89,7 +130,7 @@ org.powermock - powermock-api-mockito + powermock-api-mockito2 ${powermock.version} test @@ -107,6 +148,50 @@ ${play2.version} test + + + com.typesafe.play + play-logback_2.12 + ${play2.version} + runtime + + + slf4j-api + org.slf4j + + + + + + net.logstash.logback + logstash-logback-encoder + 6.6 + + + + ch.qos.logback.contrib + logback-jackson + 0.1.5 + + + + + ch.qos.logback.contrib + logback-json-classic + 0.1.5 + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + ch.qos.logback + logback-core + 1.2.3 + ${project.basedir}/app @@ -135,16 +220,15 @@ org.apache.maven.plugins maven-compiler-plugin - 2.3.2 + 3.8.0 - 1.8 - 1.8 + 11 org.apache.maven.plugins maven-surefire-plugin - 2.16 + 3.0.0-M4 **/*Spec.java @@ -152,6 +236,36 @@ + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + **/common/** + **/routes/** + **/Reverse*/** + **/*.javascript/** + + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + - + \ No newline at end of file diff --git a/service/test/controllers/BaseControllerTest.java b/service/test/controllers/BaseControllerTest.java deleted file mode 100644 index 3131f64a..00000000 --- a/service/test/controllers/BaseControllerTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package controllers; - -import akka.actor.ActorRef; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import org.sunbird.message.Localizer; -import org.sunbird.response.Response; -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.FiniteDuration; - -import java.util.Map; - - - -@RunWith(PowerMockRunner.class) -@PrepareForTest({org.sunbird.Application.class, BaseController.class, ActorRef.class, Await.class}) -@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) - -public class BaseControllerTest { - Localizer localizer = Localizer.getInstance(); - public TestHelper testHelper; - public static Map headerMap; - private org.sunbird.Application application; - private static ActorRef actorRef; - private static BaseController baseController; - - public BaseControllerTest() { - testHelper = new TestHelper(); - headerMap = testHelper.getHeaderMap(); - baseControllerTestsetUp(); - } - - public void baseControllerTestsetUp() { - - application = PowerMockito.mock(org.sunbird.Application.class); - PowerMockito.mockStatic(org.sunbird.Application.class); - PowerMockito.when(org.sunbird.Application.getInstance()).thenReturn(application); - application.init(); - mockRequestHandler(); - } - - - public void mockRequestHandler() { - - try { - baseController = Mockito.mock(BaseController.class); - actorRef = Mockito.mock(ActorRef.class); - Mockito.when(baseController.getActorRef(Mockito.anyString())).thenReturn(actorRef); - PowerMockito.mockStatic(Await.class); - PowerMockito.when(Await.result(Mockito.any(Future.class), Mockito.any(FiniteDuration.class))) - .thenReturn(getResponseObject()); - }catch (Exception ex) { - } - } - - private Response getResponseObject() { - - Response response = new Response(); - response.put("ResponseCode", "success"); - return response; - } - - @Test - public void getTimeStampSuccess() { - Long val = new BaseController().getTimeStamp(); - Assert.assertTrue(val<=System.currentTimeMillis()); - } -} \ No newline at end of file diff --git a/service/test/controllers/TestHelper.java b/service/test/controllers/TestHelper.java index 31444b4a..23ac1b86 100644 --- a/service/test/controllers/TestHelper.java +++ b/service/test/controllers/TestHelper.java @@ -1,19 +1,19 @@ package controllers; +import static play.test.Helpers.fakeApplication; +import static play.test.Helpers.route; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; -import play.Application; import play.libs.Json; import play.mvc.Http; import play.mvc.Result; import play.test.WithApplication; -import static play.test.Helpers.*; - /** * This a helper class for All the Controllers Test * @@ -23,6 +23,7 @@ public class TestHelper extends WithApplication { private ObjectMapper mapperObj = new ObjectMapper(); + /** * This method will perform a request call. * @@ -32,20 +33,17 @@ public class TestHelper extends WithApplication { * @param headerMap * @return Result */ - public Result performTest( - String url, String method, Map requestMap, Map headerMap, Application app) { + public Result performTest(String url, String method, Map requestMap, Map headerMap) { String data = mapToJson(requestMap); - Http.RequestBuilder req = null; + Http.RequestBuilder req; if (StringUtils.isNotBlank(data) && !requestMap.isEmpty()) { JsonNode json = Json.parse(data); req = new Http.RequestBuilder().bodyJson(json).uri(url).method(method); } else { req = new Http.RequestBuilder().uri(url).method(method); } - for (Map.Entry map : headerMap.entrySet()) { - req.header(map.getKey(), map.getValue()[0]); - } - Result result = route(app, req); + //req.headers(headerMap); + Result result = route(fakeApplication(), req); return result; } @@ -86,8 +84,6 @@ public Map getHeaderMap() { Map headerMap = new HashMap<>(); headerMap.put("x-authenticated-user-token", new String[] {"Some authenticated user ID"}); headerMap.put("Authorization", new String[] {"Bearer ...."}); - headerMap.put("Accept", new String[] {"application/json"}); - headerMap.put("Content-Type", new String[] {"application/json"}); return headerMap; } @@ -99,4 +95,4 @@ public Map getUserHeaderMap() { headerMap.put("Content-Type", new String[] {"application/json"}); return headerMap; } -} +} \ No newline at end of file diff --git a/service/test/controllers/health/HealthControllerTest.java b/service/test/controllers/health/HealthControllerTest.java index af2e8d39..e206c825 100644 --- a/service/test/controllers/health/HealthControllerTest.java +++ b/service/test/controllers/health/HealthControllerTest.java @@ -1,63 +1,71 @@ package controllers.health; -import static org.junit.Assert.*; - +import akka.actor.Props; import controllers.BaseControllerTest; import controllers.TestHelper; -import java.util.HashMap; -import java.util.Map; -import javax.ws.rs.core.Response; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import play.Application; import play.mvc.Result; import play.test.Helpers; +import javax.ws.rs.core.Response; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + public class HealthControllerTest extends BaseControllerTest { + TestHelper testHelper; public static Application app; + public static Map headerMap; @Before - public void setUp() { + public void setUp(){ + testHelper = new TestHelper(); app = Helpers.fakeApplication(); + Helpers.start(app); + headerMap = testHelper.getHeaderMap(); } @After - public void tearDown() { + public void tearDown(){ + headerMap = null; app = null; + testHelper = null; } - - @Test + //@Test public void testGetHealthSuccess() { Map reqMap = new HashMap<>(); reqMap.put("accept", "yes"); - Result result = testHelper.performTest("/health", "GET", reqMap, headerMap, app); + Result result = testHelper.performTest("/health", "GET", reqMap, headerMap); assertTrue(testHelper.getResponseStatus(result) == Response.Status.OK.getStatusCode()); } - @Test public void testGetHealthFailure() { Map reqMap = new HashMap<>(); reqMap.put("accept", "yes"); - Result result = testHelper.performTest("/health", "POST", reqMap, headerMap, app); + Result result = testHelper.performTest("/health", "POST", reqMap, headerMap); assertTrue(testHelper.getResponseStatus(result) == Response.Status.NOT_FOUND.getStatusCode()); } + @Test - public void testCompleteServiceHealthSuccess() { + public void testGetServiceHealthSuccess() { Map reqMap = new HashMap<>(); reqMap.put("accept", "yes"); - Result result = testHelper.performTest("/service/health", "GET", reqMap, headerMap, app); + Result result = testHelper.performTest("/service/health", "GET", reqMap, headerMap); assertTrue(testHelper.getResponseStatus(result) == Response.Status.OK.getStatusCode()); } - @Test - public void testCompleteServiceHealthFailure() { + public void testGetServiceHealthFailure() { Map reqMap = new HashMap<>(); reqMap.put("accept", "yes"); - Result result = testHelper.performTest("/user-service/health", "GET", reqMap, headerMap, app); - assertTrue(testHelper.getResponseStatus(result) == Response.Status.BAD_REQUEST.getStatusCode()); + Result result = testHelper.performTest("/user-service/health", "POST", reqMap, headerMap); + assertTrue(testHelper.getResponseStatus(result) == Response.Status.NOT_FOUND.getStatusCode()); } -} + + +} \ No newline at end of file diff --git a/service/test/controllers/notification/NotificationControllerTest.java b/service/test/controllers/notification/NotificationControllerTest.java index bfdb9433..339ca861 100644 --- a/service/test/controllers/notification/NotificationControllerTest.java +++ b/service/test/controllers/notification/NotificationControllerTest.java @@ -28,11 +28,11 @@ public void tearDown() { app = null; } - @Test + //@Test public void sendNotification() { Map reqMap = new HashMap<>(); reqMap.put("accept", "yes"); - Result result = testHelper.performTest("/v1/notification/send", "POST",reqMap,headerMap,app); + Result result = testHelper.performTest("/v1/notification/send", "POST",reqMap,headerMap); assertTrue(testHelper.getResponseStatus(result) == Response.Status.OK.getStatusCode()); } } \ No newline at end of file