dsjang 2024-05-26
쓰레드 기능 개선, 서비스타입별(SMS, LMS, MMS) 쓰기큐 교체, 서비스 구동 설정 추가, 큐풀 개선등
@47f9eab3d32f9c1735f20499c575bdeffb03d841
build.gradle
--- build.gradle
+++ build.gradle
@@ -47,6 +47,8 @@
     implementation 'commons-beanutils:commons-beanutils:1.9.4'
     // https://mvnrepository.com/artifact/io.netty/netty-all
     implementation 'io.netty:netty-all:4.1.42.Final'
+    // https://mvnrepository.com/artifact/org.jdom/jdom2
+    implementation 'org.jdom:jdom2:2.0.6.1'
 
     testCompileOnly 'org.projectlombok:lombok'
     testAnnotationProcessor 'org.projectlombok:lombok'
 
src/main/java/com/munjaon/server/config/RunnerConfiguration.java (added)
+++ src/main/java/com/munjaon/server/config/RunnerConfiguration.java
@@ -0,0 +1,39 @@
+package com.munjaon.server.config;
+
+import com.munjaon.server.server.service.PropertyLoader;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+
+@Configuration
+@RequiredArgsConstructor
+public class RunnerConfiguration {
+    private final ServerConfig serverConfig;
+
+    @Bean
+    @Order(1)
+    public CommandLineRunner getRunnerBeanForProperty() {
+        System.setProperty("PROPS", serverConfig.getServerProperyFile());
+        PropertyLoader.load();
+        try {
+            String[] array = serverConfig.getStringArray("test.list");
+            if (array != null && array.length > 0) {
+                for (String s : array) {
+                    System.out.println("List : " + s);
+                }
+            }
+        } catch (ConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+        return args -> System.out.println("Runner Bean #1 : " + serverConfig.getServerProperyFile());
+    }
+
+    @Bean
+    @Order(2)
+    public CommandLineRunner getRunnerBeanForService() {
+        return args -> System.out.println("Runner Bean #2");
+    }
+}
src/main/java/com/munjaon/server/config/ServerConfig.java
--- src/main/java/com/munjaon/server/config/ServerConfig.java
+++ src/main/java/com/munjaon/server/config/ServerConfig.java
@@ -1,6 +1,7 @@
 package com.munjaon.server.config;
 
 import jakarta.annotation.PostConstruct;
+import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.configuration2.PropertiesConfiguration;
 import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
@@ -19,6 +20,7 @@
 @Slf4j
 @Component
 public class ServerConfig {
+    @Getter
     @Value("${agent.server-property-file}")
     private String serverProperyFile;
 
@@ -47,4 +49,13 @@
     public int getInt(String key) throws ConfigurationException {
         return builder.getConfiguration().getInt(key, 3);
     }
+
+    public String[] getStringArray(String key) throws ConfigurationException {
+        return getStringArray(key, ",");
+    }
+
+    public String[] getStringArray(String key, String regExp) throws ConfigurationException {
+        String value = getString(key);
+        return value == null ? null : value.split(regExp);
+    }
 }
 
src/main/java/com/munjaon/server/config/ServiceCode.java (added)
+++ src/main/java/com/munjaon/server/config/ServiceCode.java
@@ -0,0 +1,52 @@
+package com.munjaon.server.config;
+
+import lombok.Getter;
+
+@Getter
+public enum ServiceCode {
+    OK(200, "Success"),
+    MSG_ERROR_USERID(300, "userId is Null OR is Over Limit Byte"),
+    MSG_ERROR_FEETYPE(301, "feeType is Null OR is Over Limit Byte"),
+    MSG_ERROR_UNITCOST(302, "unitCost is Null OR is Over Limit Byte"),
+    MSG_ERROR_MSGGROUPID(303, "msgGroupID is Null OR is Over Limit Byte"),
+    MSG_ERROR_USERMSGID(304, "userMsgID is Null OR is Over Limit Byte"),
+    MSG_ERROR_SERVICETYPE(305, "serviceType is Null OR is Over Limit Byte"),
+    MSG_ERROR_SENDSTATUS(306, "sendStatus is Null OR is Over Limit Byte"),
+    MSG_ERROR_USERSENDER(307, "userSender is Null OR is Over Limit Byte"),
+    MSG_ERROR_USERRECEIVER(308, "userReceiver is Null OR is Over Limit Byte"),
+    MSG_ERROR_REQUESTDT(309, "requestDt is Null OR is Over Limit Byte"),
+    MSG_ERROR_REMOTEIP(310, "remoteIP is Null OR is Over Limit Byte"),
+    MSG_ERROR_ROUTERSEQ(311, "routerSeq is Null OR is Over Limit Byte"),
+
+    /* SMS 메시지 */
+    MSG_ERROR_SMS_MESSAGE(400, "SMS Message is Null OR is Over Limit Byte"),
+
+    /* LMS, MMS 제목, 메시지 */
+    MSG_ERROR_MEDIA_SUBJECT(500, "LMS, MMS Subject is Null OR is Over Limit Byte"),
+    MSG_ERROR_MEDIA_MESSAGE(501, "LMS, MMS Message is Null OR is Over Limit Byte"),
+
+
+    ETC_ERROR(999, "ETC ERROR");
+
+    private Integer code;
+    private String message;
+
+    ServiceCode(Integer code, String msg) {
+        this.code = code;
+        this.message = msg;
+    }
+
+    public static String getMessage(Integer code) {
+        if (code == null) {
+            return "etc";
+        }
+
+        for (ServiceCode resCode : values()) {
+            if (resCode.getCode().equals(code)) {
+                return resCode.getMessage();
+            }
+        }
+
+        return "etc";
+    }
+}
src/main/java/com/munjaon/server/queue/config/MediaBodyConfig.java
--- src/main/java/com/munjaon/server/queue/config/MediaBodyConfig.java
+++ src/main/java/com/munjaon/server/queue/config/MediaBodyConfig.java
@@ -20,6 +20,8 @@
     public static final int FILENAME_THREE_BYTE_LENGTH = 128;
     public static final int FILENAME_THREE_BYTE_POSITION = FILENAME_TWO_BYTE_POSITION + FILENAME_TWO_BYTE_LENGTH;
 
-    /* Media Body 길이 */
-    public static final int MEDIA_SUM_BYTE_LENGTH = BodyCommonConfig.COMMON_SUM_BYTE_LENGTH + SUBJECT_BYTE_LENGTH + MEDIA_MSG_BYTE_LENGTH + FILECNT_BYTE_LENGTH + FILENAME_ONE_BYTE_LENGTH + FILENAME_TWO_BYTE_LENGTH + FILENAME_THREE_BYTE_LENGTH;
+    /* LMS Body 길이 */
+    public static final int LMS_SUM_BYTE_LENGTH = BodyCommonConfig.COMMON_SUM_BYTE_LENGTH + SUBJECT_BYTE_LENGTH + MEDIA_MSG_BYTE_LENGTH;
+    /* MMS Body 길이 */
+    public static final int MMS_SUM_BYTE_LENGTH = BodyCommonConfig.COMMON_SUM_BYTE_LENGTH + SUBJECT_BYTE_LENGTH + MEDIA_MSG_BYTE_LENGTH + FILECNT_BYTE_LENGTH + FILENAME_ONE_BYTE_LENGTH + FILENAME_TWO_BYTE_LENGTH + FILENAME_THREE_BYTE_LENGTH;
 }
src/main/java/com/munjaon/server/queue/dto/BasicMessageDto.java
--- src/main/java/com/munjaon/server/queue/dto/BasicMessageDto.java
+++ src/main/java/com/munjaon/server/queue/dto/BasicMessageDto.java
@@ -8,9 +8,9 @@
 @Setter
 @ToString
 public class BasicMessageDto {
-    protected String userId = "";
-    protected String feeType = "";
-    protected String unitCost = "";
+    protected String userId = "";                      // 사용자 아이디
+    protected final String feeType = "A";              // 요금제(선불 : P / 후불 : A)
+    protected String unitCost = "";                    // 단가
     protected String msgGroupID = "0";
     protected String userMsgID = "";
     protected String serviceType = "";
@@ -23,5 +23,13 @@
     protected String routerSeq = "0";
 
     protected String userMessage = "";
-    protected String userMsgType = "";
+
+    protected String userSubject = "";
+    protected int userFileCnt = 0;
+    protected String userFileName01;
+    protected String userFileName02;
+    protected String userFileName03;
+    protected int userFileSize01 = 0;
+    protected int userFileSize02 = 0;
+    protected int userFileSize03 = 0;
 }
src/main/java/com/munjaon/server/queue/dto/QueueInfo.java
--- src/main/java/com/munjaon/server/queue/dto/QueueInfo.java
+++ src/main/java/com/munjaon/server/queue/dto/QueueInfo.java
@@ -1,11 +1,13 @@
 package com.munjaon.server.queue.dto;
 
+import lombok.Builder;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.ToString;
 
 @Getter
 @Setter
+@Builder
 @ToString
 public class QueueInfo {
 	private String queueName = "";
 
src/main/java/com/munjaon/server/queue/pool/LmsQueuePool.java (added)
+++ src/main/java/com/munjaon/server/queue/pool/LmsQueuePool.java
@@ -0,0 +1,84 @@
+package com.munjaon.server.queue.pool;
+
+import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.queue.service.LmsWriteQueue;
+
+import java.util.LinkedList;
+
+public class LmsQueuePool {
+    /** Lock Object */
+    private final Object lockMonitor = new Object();
+    /** File Queue Pool */
+    private final LinkedList<LmsWriteQueue> queuePool = new LinkedList<>();
+    /** File Queue */
+    private LmsWriteQueue queue = null;
+    /** File Queue 분배를 위한 인덱서 */
+    private int queueIndex = 0;
+
+    /** Singleton Instance */
+    private static SmsQueuePool fileQueue;
+
+    public synchronized static SmsQueuePool getInstance(){
+        if(fileQueue == null){
+            fileQueue = new SmsQueuePool();
+        }
+        return fileQueue;
+    }
+
+    /** Queue 존재하는지 조회 */
+    public boolean isExistQueue(String name){
+        synchronized(lockMonitor){
+            boolean isExist = false;
+            for (LmsWriteQueue writeQueue : queuePool) {
+                if (name.equals(writeQueue.getQueueName())) {
+                    isExist = true;
+                    break;
+                }
+            }
+            return isExist;
+        }
+    }
+    /** Queue 제거 */
+    public void removeQueue(String name){
+        synchronized(lockMonitor) {
+            for (int loopCnt = 0; loopCnt < queuePool.size(); loopCnt++) {
+                queue = queuePool.get(loopCnt);
+                if(name.equals(queue.getQueueName())){
+                    queuePool.remove(loopCnt);
+                    System.out.println("[LMS Queue] [" + queue.getQueueName() + " is Removed]");
+                    break;
+                }
+            }
+        }
+    }
+    /** Queue 등록 */
+    public void addShortQueue(LmsWriteQueue queue){
+        synchronized(lockMonitor){
+            if (queue != null){
+                queuePool.addLast(queue);
+                lockMonitor.notifyAll();
+            }
+        }
+    }
+    /** Queue 데이터 저장 */
+    public void pushQueue(BasicMessageDto data) throws Exception{
+        synchronized(lockMonitor) {
+            if (queuePool.isEmpty()) {
+                try{
+                    lockMonitor.wait();
+                }catch(InterruptedException e){
+                    // 아무 처리도 하지 않는다.
+                }
+            }
+            //큐리스트의 끝까지 이동한 경우 처음으로 되돌린다.
+            if (queueIndex >= queuePool.size()) {
+                queueIndex = 0;
+            }
+            // 파일큐에 Push 한다.
+            queue = queuePool.get(queueIndex);
+            queue.pushMessageToBuffer(data);
+            // 큐인덱서를 증가시킨다.
+            queueIndex++;
+        }
+    }
+}
 
src/main/java/com/munjaon/server/queue/pool/MmsQueuePool.java (added)
+++ src/main/java/com/munjaon/server/queue/pool/MmsQueuePool.java
@@ -0,0 +1,84 @@
+package com.munjaon.server.queue.pool;
+
+import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.queue.service.MmsWriteQueue;
+
+import java.util.LinkedList;
+
+public class MmsQueuePool {
+    /** Lock Object */
+    private final Object lockMonitor = new Object();
+    /** File Queue Pool */
+    private final LinkedList<MmsWriteQueue> queuePool = new LinkedList<>();
+    /** File Queue */
+    private MmsWriteQueue queue = null;
+    /** File Queue 분배를 위한 인덱서 */
+    private int queueIndex = 0;
+
+    /** Singleton Instance */
+    private static SmsQueuePool fileQueue;
+
+    public synchronized static SmsQueuePool getInstance(){
+        if(fileQueue == null){
+            fileQueue = new SmsQueuePool();
+        }
+        return fileQueue;
+    }
+
+    /** Queue 존재하는지 조회 */
+    public boolean isExistQueue(String name){
+        synchronized(lockMonitor){
+            boolean isExist = false;
+            for (MmsWriteQueue writeQueue : queuePool) {
+                if (name.equals(writeQueue.getQueueName())) {
+                    isExist = true;
+                    break;
+                }
+            }
+            return isExist;
+        }
+    }
+    /** Queue 제거 */
+    public void removeQueue(String name){
+        synchronized(lockMonitor) {
+            for (int loopCnt = 0; loopCnt < queuePool.size(); loopCnt++) {
+                queue = queuePool.get(loopCnt);
+                if(name.equals(queue.getQueueName())){
+                    queuePool.remove(loopCnt);
+                    System.out.println("[MMS Queue] [" + queue.getQueueName() + " is Removed]");
+                    break;
+                }
+            }
+        }
+    }
+    /** Queue 등록 */
+    public void addShortQueue(MmsWriteQueue queue){
+        synchronized(lockMonitor){
+            if (queue != null){
+                queuePool.addLast(queue);
+                lockMonitor.notifyAll();
+            }
+        }
+    }
+    /** Queue 데이터 저장 */
+    public void pushQueue(BasicMessageDto data) throws Exception{
+        synchronized(lockMonitor) {
+            if (queuePool.isEmpty()) {
+                try{
+                    lockMonitor.wait();
+                } catch (InterruptedException e) {
+                    // 아무 처리도 하지 않는다.
+                }
+            }
+            //큐리스트의 끝까지 이동한 경우 처음으로 되돌린다.
+            if (queueIndex >= queuePool.size()) {
+                queueIndex = 0;
+            }
+            // 파일큐에 Push 한다.
+            queue = queuePool.get(queueIndex);
+            queue.pushMessageToBuffer(data);
+            // 큐인덱서를 증가시킨다.
+            queueIndex++;
+        }
+    }
+}
 
src/main/java/com/munjaon/server/queue/pool/SmsQueuePool.java (added)
+++ src/main/java/com/munjaon/server/queue/pool/SmsQueuePool.java
@@ -0,0 +1,84 @@
+package com.munjaon.server.queue.pool;
+
+import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.queue.service.SmsWriteQueue;
+
+import java.util.LinkedList;
+
+public class SmsQueuePool {
+    /** Lock Object */
+    private final Object lockMonitor = new Object();
+    /** File Queue Pool */
+    private final LinkedList<SmsWriteQueue> queuePool = new LinkedList<>();
+    /** File Queue */
+    private SmsWriteQueue queue = null;
+    /** File Queue 분배를 위한 인덱서 */
+    private int queueIndex = 0;
+
+    /** Singleton Instance */
+    private static SmsQueuePool fileQueue;
+
+    public synchronized static SmsQueuePool getInstance(){
+        if(fileQueue == null){
+            fileQueue = new SmsQueuePool();
+        }
+        return fileQueue;
+    }
+
+    /** Queue 존재하는지 조회 */
+    public boolean isExistQueue(String name){
+        synchronized(lockMonitor){
+            boolean isExist = false;
+            for (SmsWriteQueue writeQueue : queuePool) {
+                if (name.equals(writeQueue.getQueueName())) {
+                    isExist = true;
+                    break;
+                }
+            }
+            return isExist;
+        }
+    }
+    /** Queue 제거 */
+    public void removeQueue(String name){
+        synchronized(lockMonitor) {
+            for (int loopCnt = 0; loopCnt < queuePool.size(); loopCnt++) {
+                queue = queuePool.get(loopCnt);
+                if(name.equals(queue.getQueueName())){
+                    queuePool.remove(loopCnt);
+                    System.out.println("[SMS Queue] [" + queue.getQueueName() + " is Removed]");
+                    break;
+                }
+            }
+        }
+    }
+    /** Queue 등록 */
+    public void addShortQueue(SmsWriteQueue queue){
+        synchronized(lockMonitor){
+            if (queue != null){
+                queuePool.addLast(queue);
+                lockMonitor.notifyAll();
+            }
+        }
+    }
+    /** Queue 데이터 저장 */
+    public void pushQueue(BasicMessageDto data) throws Exception{
+        synchronized(lockMonitor) {
+            if (queuePool.isEmpty()) {
+                try{
+                    lockMonitor.wait();
+                }catch(InterruptedException e){
+                    // 아무 처리도 하지 않는다.
+                }
+            }
+            //큐리스트의 끝까지 이동한 경우 처음으로 되돌린다.
+            if (queueIndex >= queuePool.size()) {
+                queueIndex = 0;
+            }
+            // 파일큐에 Push 한다.
+            queue = queuePool.get(queueIndex);
+            queue.pushMessageToBuffer(data);
+            // 큐인덱서를 증가시킨다.
+            queueIndex++;
+        }
+    }
+}
src/main/java/com/munjaon/server/queue/service/KakaoWriteQueue.java
--- src/main/java/com/munjaon/server/queue/service/KakaoWriteQueue.java
+++ src/main/java/com/munjaon/server/queue/service/KakaoWriteQueue.java
@@ -1,9 +1,21 @@
 package com.munjaon.server.queue.service;
 
-import com.munjaon.server.queue.dto.KakaoMessageDto;
+import com.munjaon.server.queue.dto.BasicMessageDto;
 
 public class KakaoWriteQueue extends WriteQueue {
-    public void pushBuffer(KakaoMessageDto data) throws Exception {
+
+    @Override
+    int isisValidateMessageForExtend(BasicMessageDto messageDto) {
+        return 0;
+    }
+
+    @Override
+    void pushMessageToBuffer(BasicMessageDto messageDto) throws Exception {
+
+    }
+
+    @Override
+    void initDataBuffer() {
 
     }
 }
src/main/java/com/munjaon/server/queue/service/LmsWriteQueue.java
--- src/main/java/com/munjaon/server/queue/service/LmsWriteQueue.java
+++ src/main/java/com/munjaon/server/queue/service/LmsWriteQueue.java
@@ -1,9 +1,61 @@
 package com.munjaon.server.queue.service;
 
-import com.munjaon.server.queue.dto.LmsMessageDto;
+import com.munjaon.server.config.ServiceCode;
+import com.munjaon.server.queue.config.MediaBodyConfig;
+import com.munjaon.server.queue.config.QueueConstants;
+import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.util.MessageUtil;
+
+import java.nio.ByteBuffer;
 
 public class LmsWriteQueue extends WriteQueue {
-    public void pushBuffer(LmsMessageDto data) throws Exception {
 
+    @Override
+    public int isisValidateMessageForExtend(BasicMessageDto messageDto) {
+        /* 13. 제목 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserSubject(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserSubject(), MediaBodyConfig.SUBJECT_BYTE_LENGTH, false)) {
+            return ServiceCode.MSG_ERROR_MEDIA_SUBJECT.getCode();
+        }
+        /* 14. 메시지 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserMessage(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserMessage(), MediaBodyConfig.MEDIA_MSG_BYTE_LENGTH, false)) {
+            return ServiceCode.MSG_ERROR_MEDIA_MESSAGE.getCode();
+        }
+
+        return ServiceCode.OK.getCode();
+    }
+
+    @Override
+    public void pushMessageToBuffer(BasicMessageDto messageDto) throws Exception {
+        if (isValidateMessage(messageDto) == ServiceCode.OK.getCode()) {
+            /* 1. dataBuffer 초기화 */
+            initDataBuffer();
+            /* 2. messageDto >> dataBuffer */
+            MessageUtil.setBytesForCommonMessage(this.dataBuffer, messageDto);
+            MessageUtil.setBytesForMediaMessage(this.dataBuffer, messageDto);
+            /* 3. 파일큐에 적재 */
+            /* 3.1 Header 정보 다시 일기 */
+            readHeader();
+            if (this.dataBuffer != null){
+                this.channel.position(MessageUtil.calcWritePosition(this.pushCounter, MediaBodyConfig.LMS_SUM_BYTE_LENGTH));
+                this.dataBuffer.flip();
+                this.channel.write(this.dataBuffer);
+                /* 3.2 Push 카운터 증가 */
+                this.pushCounter = this.pushCounter + 1;
+                /* 3.3 Header 정보 변경 */
+                writeHeader();
+            }
+        }
+    }
+
+    @Override
+    public void initDataBuffer() {
+        if (this.dataBuffer == null) {
+            this.dataBuffer = ByteBuffer.allocateDirect(MediaBodyConfig.LMS_SUM_BYTE_LENGTH);
+        }
+        this.dataBuffer.clear();
+        for(int loopCnt = 0; loopCnt < MediaBodyConfig.LMS_SUM_BYTE_LENGTH; loopCnt++){
+            this.dataBuffer.put(QueueConstants.SET_DEFAULT_BYTE);
+        }
+        this.dataBuffer.position(0);
     }
 }
src/main/java/com/munjaon/server/queue/service/MmsWriteQueue.java
--- src/main/java/com/munjaon/server/queue/service/MmsWriteQueue.java
+++ src/main/java/com/munjaon/server/queue/service/MmsWriteQueue.java
@@ -1,9 +1,62 @@
 package com.munjaon.server.queue.service;
 
-import com.munjaon.server.queue.dto.MmsMessageDto;
+import com.munjaon.server.config.ServiceCode;
+import com.munjaon.server.queue.config.MediaBodyConfig;
+import com.munjaon.server.queue.config.QueueConstants;
+import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.util.MessageUtil;
+
+import java.nio.ByteBuffer;
 
 public class MmsWriteQueue extends WriteQueue {
-    public void pushBuffer(MmsMessageDto data) throws Exception {
 
+    @Override
+    public int isisValidateMessageForExtend(BasicMessageDto messageDto) {
+        /* 13. 제목 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserSubject(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserSubject(), MediaBodyConfig.SUBJECT_BYTE_LENGTH, false)) {
+            return ServiceCode.MSG_ERROR_MEDIA_SUBJECT.getCode();
+        }
+        /* 14. 메시지 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserMessage(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserMessage(), MediaBodyConfig.MEDIA_MSG_BYTE_LENGTH, false)) {
+            return ServiceCode.MSG_ERROR_MEDIA_MESSAGE.getCode();
+        }
+
+        return ServiceCode.OK.getCode();
+    }
+
+    @Override
+    public void pushMessageToBuffer(BasicMessageDto messageDto) throws Exception {
+        if (isValidateMessage(messageDto) == ServiceCode.OK.getCode()) {
+            /* 1. dataBuffer 초기화 */
+            initDataBuffer();
+            /* 2. messageDto >> dataBuffer */
+            MessageUtil.setBytesForCommonMessage(this.dataBuffer, messageDto);
+            MessageUtil.setBytesForMediaMessage(this.dataBuffer, messageDto);
+            MessageUtil.setBytesForMmsMessage(this.dataBuffer, messageDto);
+            /* 3. 파일큐에 적재 */
+            /* 3.1 Header 정보 다시 일기 */
+            readHeader();
+            if (this.dataBuffer != null){
+                this.channel.position(MessageUtil.calcWritePosition(this.pushCounter, MediaBodyConfig.MMS_SUM_BYTE_LENGTH));
+                this.dataBuffer.flip();
+                this.channel.write(this.dataBuffer);
+                /* 3.2 Push 카운터 증가 */
+                this.pushCounter = this.pushCounter + 1;
+                /* 3.3 Header 정보 변경 */
+                writeHeader();
+            }
+        }
+    }
+
+    @Override
+    public void initDataBuffer() {
+        if (this.dataBuffer == null) {
+            this.dataBuffer = ByteBuffer.allocateDirect(MediaBodyConfig.MMS_SUM_BYTE_LENGTH);
+        }
+        this.dataBuffer.clear();
+        for(int loopCnt = 0; loopCnt < MediaBodyConfig.MMS_SUM_BYTE_LENGTH; loopCnt++){
+            this.dataBuffer.put(QueueConstants.SET_DEFAULT_BYTE);
+        }
+        this.dataBuffer.position(0);
     }
 }
 
src/main/java/com/munjaon/server/queue/service/ReadQueue.java (added)
+++ src/main/java/com/munjaon/server/queue/service/ReadQueue.java
@@ -0,0 +1,197 @@
+package com.munjaon.server.queue.service;
+
+import com.munjaon.server.queue.dto.QueueInfo;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class ReadQueue {
+    /** Queue Header Size - [Create Date:10 Byte, Push Count:10 Byte] */
+    private static final int QUEUE_HEADER_LENGTH = 20;
+    /** Queue Create Date - [Format:YYYYMMDD] */
+    private String createDate = "";
+    /** Queue Pop Counter */
+    private int popCounter = 0;
+    /** Queue Push Counter */
+    private int pushCounter = 0;
+    /** XML 읽은 날짜 */
+    private String readXMLDate = "";
+    /** Queue Header Buffer */
+    private ByteBuffer headerBuffer = null;
+    /** Queue Data Read Buffer */
+    private ByteBuffer readBuffer = null;
+    /** Queue Information */
+    private QueueInfo queueInfo = null;
+    /** Queue File Channel */
+    private FileChannel channel = null;
+    /** Header 에서 사용하는 변수 */
+    byte[] headerArray = null;
+
+    /** XML Control */
+//    private Document document = null;	// XML Document
+//    private Element rootElement = null;
+//    private Element childElement = null;
+//    private final Format format = Format.getPrettyFormat();
+//    private XMLOutputter outputter = null;
+//    private FileWriter fileWriter = null;
+//
+//    public ReadQueue(QueueInfo info) throws Exception{
+//        this.queueInfo = info;
+//        this.headerBuffer = ByteBuffer.allocateDirect(this.QUEUE_HEADER_LENGTH);
+//        this.readBuffer = ByteBuffer.allocateDirect(this.queueInfo.getQueueDataLength());
+//        try{
+//            File file = new File(this.queueInfo.getQueueFileName());
+//            if(file.exists()){
+//                this.channel = new RandomAccessFile(file, "r").getChannel();
+//                // 파일큐의 헤더 정보를 읽어온다.
+//                readHeader();
+//                // XML Write Formater
+//                this.format.setEncoding("EUC-KR");
+//                this.format.setIndent("\t");
+//
+//                // 해당큐를 읽은 PopCounter 정보를 가져온다.
+//                file = new File(this.queueInfo.getReadXMLFileName());
+//                if(file.exists()){
+//                    readPopCounter();
+//                }else{
+//                    this.readXMLDate = MessageUtil.currentDay();
+//                    this.popCounter = 0;
+//                    writePopCounter();
+//                }
+//            }else{
+//                throw new Exception(this.queueInfo.getQueueName() + "'s Queue is Not Exists!!");
+//            }
+//
+//        }catch(Exception e){
+//            throw e;
+//        }
+//    }
+//    public ByteBuffer popBuffer() throws Exception{
+//        try {
+//            readHeader();
+//            readPopCounter();
+//
+//            if(this.popCounter == this.pushCounter){
+//                // 더이상 읽을 데이터가 없는 경우
+//                return null;
+//            }else{
+//                initReadBuffer();
+//                this.channel.position(QUEUE_HEADER_LENGTH + (this.queueInfo.getQueueDataLength() * this.popCounter));
+//                this.channel.read(this.readBuffer);
+//                this.popCounter = this.popCounter + 1;
+//                // Header 정보 변경
+//                writePopCounter();
+//
+//                return this.readBuffer;
+//            }
+//        } catch(Exception e) {
+//            throw e;
+//        }
+//    }
+//    public void readPopCounter() throws Exception{
+//        try {
+//            this.document = new SAXBuilder().build(this.queueInfo.getReadXMLFileName());
+//            this.rootElement = this.document.getRootElement();
+//            this.readXMLDate = this.rootElement.getChild("createDate").getText().trim();
+//            this.popCounter = Integer.parseInt(this.rootElement.getChild("PopCounter").getText().trim());
+//        } catch(Exception e) {
+//            throw e;
+//        }
+//    }
+//    public void writePopCounter() throws Exception{
+//        try {
+//            // Root Element
+//            this.rootElement = new Element("ReadQueue");
+//            // 생성날짜
+//            this.childElement = new Element("createDate");
+//            this.childElement.setText(this.readXMLDate);
+//            this.rootElement.addContent(this.childElement);
+//            // 읽은 카운트
+//            this.childElement = new Element("PopCounter");
+//            this.childElement.setText(Integer.toString(this.popCounter));
+//            this.rootElement.addContent(this.childElement);
+//
+//            this.document = new Document(this.rootElement);
+//            this.outputter = new XMLOutputter();
+//            this.outputter.setFormat(this.format);
+//            this.fileWriter = new FileWriter(this.queueInfo.getReadXMLFileName());
+//            this.outputter.output(this.document, this.fileWriter);
+//        } catch(Exception e) {
+//            throw e;
+//        }finally{
+//            if(this.fileWriter != null){this.fileWriter.close(); this.fileWriter = null; }
+//        }
+//    }
+//    public void initPopCounter() throws Exception{
+//        try {
+//            initHeaderBuffer();
+//            // 데이터 초기화
+//            this.readXMLDate = MessageUtil.currentDay();
+//            this.popCounter = 0;
+//
+//            writePopCounter();
+//        } catch(Exception e) {
+//            throw e;
+//        }
+//    }
+//    public void readHeader() throws Exception {
+//        try {
+//            initHeaderBuffer();
+//            this.channel.position(0);
+//            this.channel.read(this.headerBuffer);
+//            this.headerArray = new byte[10];
+//            // 생성날짜 가져오기 - 생성날짜(10) / 쓴카운트(10)
+//            this.headerBuffer.position(0);
+//            this.headerBuffer.get(this.headerArray);
+//            this.createDate = (new String(this.headerArray)).trim();
+//            // 쓴 카운트 가져오기
+//            this.headerArray = new byte[10];
+//            this.headerBuffer.position(10);
+//            this.headerBuffer.get(this.headerArray);
+//            this.pushCounter = Integer.parseInt((new String(this.headerArray)).trim());
+//        } catch(Exception e) {
+//            throw e;
+//        }
+//    }
+//    public void close() throws IOException {
+//        try {
+//            if(channel != null && channel.isOpen()) {
+//                channel.close();
+//            }
+//        } catch(IOException e) {
+//            throw e;
+//        }
+//    }
+//    public void initHeaderBuffer(){
+//        this.headerBuffer.clear();
+//        for(int loopCnt=0;loopCnt<this.QUEUE_HEADER_LENGTH;loopCnt++){
+//            this.headerBuffer.put(QueueVariable.SET_DEFAULT_BYTE);
+//        }
+//        this.headerBuffer.position(0);
+//    }
+//    public void initReadBuffer(){
+//        this.readBuffer.clear();
+//        for(int loopCnt=0;loopCnt<this.queueInfo.getQueueDataLength();loopCnt++){
+//            this.readBuffer.put(QueueVariable.SET_DEFAULT_BYTE);
+//        }
+//        this.readBuffer.position(0);
+//    }
+//    public String getQueueName(){
+//        if(this.queueInfo == null)
+//            return null;
+//        else
+//            return this.queueInfo.getQueueName();
+//    }
+//    public String getCreateDate() {
+//        return createDate;
+//    }
+//    public String getReadXMLDate() {
+//        return readXMLDate;
+//    }
+//    public int getPushCounter() {
+//        return pushCounter;
+//    }
+//    public int getPopCounter() {
+//        return popCounter;
+//    }
+}
src/main/java/com/munjaon/server/queue/service/SmsWriteQueue.java
--- src/main/java/com/munjaon/server/queue/service/SmsWriteQueue.java
+++ src/main/java/com/munjaon/server/queue/service/SmsWriteQueue.java
@@ -1,9 +1,63 @@
 package com.munjaon.server.queue.service;
 
+import com.munjaon.server.config.ServiceCode;
+import com.munjaon.server.queue.config.QueueConstants;
+import com.munjaon.server.queue.config.SmsBodyConfig;
 import com.munjaon.server.queue.dto.BasicMessageDto;
+import com.munjaon.server.queue.dto.QueueInfo;
+import com.munjaon.server.util.MessageUtil;
+
+import java.nio.ByteBuffer;
 
 public class SmsWriteQueue extends WriteQueue {
-    public void pushBuffer(BasicMessageDto data) throws Exception {
+    public SmsWriteQueue(QueueInfo queueInfo) throws Exception {
+        this.queueInfo = queueInfo;
+        /* 큐초기화 */
+        initQueue();
+    }
 
+    @Override
+    public int isisValidateMessageForExtend(BasicMessageDto messageDto) {
+        /* 13. 메시지 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserMessage(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserMessage(), SmsBodyConfig.SMS_MSG_BYTE_LENGTH, false)) {
+            return ServiceCode.MSG_ERROR_SMS_MESSAGE.getCode();
+        }
+
+        return ServiceCode.OK.getCode();
+    }
+
+    @Override
+    public void pushMessageToBuffer(BasicMessageDto messageDto) throws Exception {
+        if (isValidateMessage(messageDto) == ServiceCode.OK.getCode()) {
+            /* 1. dataBuffer 초기화 */
+            initDataBuffer();
+            /* 2. messageDto >> dataBuffer */
+            MessageUtil.setBytesForCommonMessage(this.dataBuffer, messageDto);
+            MessageUtil.setBytesForSmsMessage(this.dataBuffer, messageDto);
+            /* 3. 파일큐에 적재 */
+            /* 3.1 Header 정보 다시 일기 */
+            readHeader();
+            if (this.dataBuffer != null){
+                this.channel.position(MessageUtil.calcWritePosition(this.pushCounter, SmsBodyConfig.SMS_SUM_BYTE_LENGTH));
+                this.dataBuffer.flip();
+                this.channel.write(this.dataBuffer);
+                /* 3.2 Push 카운터 증가 */
+                this.pushCounter = this.pushCounter + 1;
+                /* 3.3 Header 정보 변경 */
+                writeHeader();
+            }
+        }
+    }
+
+    @Override
+    public void initDataBuffer() {
+        if (this.dataBuffer == null) {
+            this.dataBuffer = ByteBuffer.allocateDirect(SmsBodyConfig.SMS_SUM_BYTE_LENGTH);
+        }
+        this.dataBuffer.clear();
+        for(int loopCnt = 0; loopCnt < SmsBodyConfig.SMS_SUM_BYTE_LENGTH; loopCnt++){
+            this.dataBuffer.put(QueueConstants.SET_DEFAULT_BYTE);
+        }
+        this.dataBuffer.position(0);
     }
 }
src/main/java/com/munjaon/server/queue/service/WriteQueue.java
--- src/main/java/com/munjaon/server/queue/service/WriteQueue.java
+++ src/main/java/com/munjaon/server/queue/service/WriteQueue.java
@@ -1,8 +1,13 @@
 package com.munjaon.server.queue.service;
 
+import com.munjaon.server.config.ServiceCode;
+import com.munjaon.server.queue.config.BodyCommonConfig;
 import com.munjaon.server.queue.config.QueueConstants;
 import com.munjaon.server.queue.config.QueueHeaderConfig;
+import com.munjaon.server.queue.dto.BasicMessageDto;
 import com.munjaon.server.queue.dto.QueueInfo;
+import com.munjaon.server.util.MessageUtil;
+import lombok.Getter;
 
 import java.io.File;
 import java.io.IOException;
@@ -13,20 +18,22 @@
 import java.time.format.DateTimeFormatter;
 
 public abstract class WriteQueue {
-    /** Queue Header Size - [Create Date:10 Byte, Push Count:10 Byte] */
-    protected static final int QUEUE_HEADER_LENGTH = 20;
-    /** Queue Create Date - [Format:YYYYMMDD] */
-    protected String createDate = "";
-    /** Queue Push Counter */
-    protected int pushCounter = 0;
     /** Queue Header Buffer */
     protected ByteBuffer headerBuffer = null;
-    /** Queue Information */
-    protected QueueInfo queueInfo = null;
-    /** Queue File Channel */
-    protected FileChannel channel = null;
     /** Header 에서 사용하는 변수 */
     protected byte[] headerArray = null;
+    /** Queue Create Date - [Format:YYYYMMDD] */
+    @Getter
+    protected String createDate = "";
+    /** Queue Push Counter */
+    @Getter
+    protected int pushCounter = 0;
+
+    /** Queue File Channel */
+    protected FileChannel channel = null;
+    /** Queue Information */
+    @Getter
+    protected QueueInfo queueInfo = null;
     /** pushBuffer() 함수에서 사용하는 변수 */
     protected ByteBuffer dataBuffer = null;
 
@@ -37,13 +44,13 @@
             this.channel = new RandomAccessFile(file, "rw").getChannel();
             //this.lock = this.channel.lock();
 
-            if(file.length() == 0) {
+            if (file.length() == 0) {
                 // Push 및 Pop 카운트 초기화
                 this.createDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                 this.pushCounter = 0;
                 // 헤더 초기화
                 writeHeader();
-            }else{
+            } else {
                 readHeader();
             }
         }catch(Exception e){
@@ -53,19 +60,19 @@
         }
     }
 
-    public void readHeader() throws Exception {
+    protected void readHeader() throws Exception {
         try {
             initHeaderBuffer();
             this.channel.position(0);
             this.channel.read(this.headerBuffer);
-            this.headerArray = new byte[10];
+            this.headerArray = new byte[QueueHeaderConfig.CREATE_DATE_LENGTH];
             // 생성날짜 가져오기 - 생성날짜(10) / 읽은카운트(10) / 쓴카운트(10)
-            this.headerBuffer.position(0);
+            this.headerBuffer.position(QueueHeaderConfig.CREATE_DATE_POSITION);
             this.headerBuffer.get(this.headerArray);
             this.createDate = (new String(this.headerArray)).trim();
             // 쓴 카운트 가져오기
-            this.headerArray = new byte[10];
-            this.headerBuffer.position(10);
+            this.headerArray = new byte[QueueHeaderConfig.PUSH_COUNT_LENGTH];
+            this.headerBuffer.position(QueueHeaderConfig.PUSH_COUNT_POSITION);
             this.headerBuffer.get(this.headerArray);
             this.pushCounter = Integer.parseInt((new String(this.headerArray)).trim());
         } catch(Exception e) {
@@ -73,12 +80,12 @@
         }
     }
 
-    public void writeHeader() throws Exception {
+    protected void writeHeader() throws Exception {
         try {
             initHeaderBuffer();
-            this.channel.position(0);
+            this.channel.position(QueueHeaderConfig.CREATE_DATE_POSITION);
             this.headerBuffer.put(this.createDate.getBytes());
-            this.headerBuffer.position(10);
+            this.headerBuffer.position(QueueHeaderConfig.PUSH_COUNT_POSITION);
             this.headerBuffer.put(Integer.toString(this.pushCounter).getBytes());
             this.headerBuffer.flip();
             this.channel.write(this.headerBuffer);
@@ -87,7 +94,7 @@
         }
     }
 
-    public void initHeaderBuffer(){
+    protected void initHeaderBuffer(){
         this.headerBuffer.clear();
         for(int loopCnt = 0; loopCnt < QueueHeaderConfig.QUEUE_HEADER_LENGTH; loopCnt++){
             this.headerBuffer.put(QueueConstants.SET_DEFAULT_BYTE);
@@ -95,9 +102,9 @@
         this.headerBuffer.position(0);
     }
 
-    public void close() throws IOException {
+    protected void close() throws IOException {
         try {
-            if(channel != null && channel.isOpen()) {
+            if (isOpen()) {
                 channel.close();
             }
         } catch(IOException e) {
@@ -105,27 +112,108 @@
         }
     }
 
-    public void truncateQueue() throws Exception{
-        try {
-            //this.lock = this.channel.lock();
+    protected boolean isOpen() {
+        if (this.channel == null) {
+            return false;
+        }
 
-            if(channel != null && channel.isOpen()) {
-                // 헤더정보 읽기
+        return this.channel.isOpen();
+    }
+
+    protected void truncateQueue() throws Exception{
+        try {
+            /* 1. 날짜가 지난경우와 더이상 읽을 데이터가 없을 경우 큐를 초기화 */
+            String thisDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+            if (this.createDate.equals(thisDate)) {
+                return;
+            }
+
+            if (isOpen()) {
+                /* 2. 헤더정보 읽기 */
                 readHeader();
-                String thisDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
-                // 날짜가 지난경우와 더이상 읽을 데이터가 없을 경우 큐를 초기화
-                if((this.createDate.equals(thisDate) == false)){
-                    // 파일 내용을 모두 지운다.
-                    channel.truncate(0);
-                    // 헤더 정보를 초기화한다.
-                    this.createDate = thisDate;
-                    this.pushCounter = 0;
-                    // 헤더에 초기데이터를 저장
-                    writeHeader();
-                }
+                /* 3. 파일 내용을 모두 지운다. */
+                channel.truncate(0);
+                /* 4. 헤더 정보를 초기화한다. */
+                this.createDate = thisDate;
+                this.pushCounter = 0;
+                /* 5. 헤더에 초기데이터를 저장 */
+                writeHeader();
             }
         } catch(Exception e) {
             throw e;
         }
     }
+
+    public String getQueueName(){
+        if(this.queueInfo == null)
+            return null;
+        else
+            return this.queueInfo.getQueueName();
+    }
+
+    protected int isValidateMessage(BasicMessageDto messageDto) {
+        int result = isValidateMessageForCommon(messageDto);
+        if (result != ServiceCode.OK.getCode()) {
+            return result;
+        }
+
+        return isisValidateMessageForExtend(messageDto);
+    }
+
+    protected int isValidateMessageForCommon(BasicMessageDto messageDto) {
+        /* 1. 사용자 아이디 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserId(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserId(), BodyCommonConfig.USERID_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_USERID.getCode();
+        }
+        /* 2. 요금제(선불 : P / 후불 : A) */
+        if (MessageUtil.isEmptyForMessage(messageDto.getFeeType(), true) || MessageUtil.isOverByteForMessage(messageDto.getFeeType(), BodyCommonConfig.FEETYPE_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_FEETYPE.getCode();
+        }
+        /* 3. 단가 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUnitCost(), true) || MessageUtil.isOverByteForMessage(messageDto.getUnitCost(), BodyCommonConfig.UNITCOST_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_UNITCOST.getCode();
+        }
+        /* 4. MSG Group ID */
+        if (MessageUtil.isEmptyForMessage(messageDto.getMsgGroupID(), true) || MessageUtil.isOverByteForMessage(messageDto.getMsgGroupID(), BodyCommonConfig.MSGGROUPID_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_MSGGROUPID.getCode();
+        }
+        /* 5. MSG ID */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserMsgID(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserMsgID(), BodyCommonConfig.MSGID_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_USERMSGID.getCode();
+        }
+        /* 6. Service Type */
+        if (MessageUtil.isEmptyForMessage(messageDto.getServiceType(), true) || MessageUtil.isOverByteForMessage(messageDto.getServiceType(), BodyCommonConfig.SERVICETYPE_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_SERVICETYPE.getCode();
+        }
+        /* 7. 메시지 전송 결과 >> 성공 : 0 / 필터링 : 기타값  */
+        if (MessageUtil.isEmptyForMessage(messageDto.getSendStatus(), true) || MessageUtil.isOverByteForMessage(messageDto.getSendStatus(), BodyCommonConfig.SENDSTATUS_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_SENDSTATUS.getCode();
+        }
+        /* 8. 회신번호 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserSender(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserSender(), BodyCommonConfig.SENDER_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_USERSENDER.getCode();
+        }
+        /* 9. 수신번호 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getUserReceiver(), true) || MessageUtil.isOverByteForMessage(messageDto.getUserReceiver(), BodyCommonConfig.RECEIVER_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_USERRECEIVER.getCode();
+        }
+        /* 10. 요청시간 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getRequestDt(), true) || MessageUtil.isOverByteForMessage(messageDto.getRequestDt(), BodyCommonConfig.REQUESTDT_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_REQUESTDT.getCode();
+        }
+        /* 11. 원격 주소 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getRemoteIP(), true) || MessageUtil.isOverByteForMessage(messageDto.getRemoteIP(), BodyCommonConfig.REMOTEIP_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_REMOTEIP.getCode();
+        }
+        /* 12. 발송망 */
+        if (MessageUtil.isEmptyForMessage(messageDto.getRouterSeq(), true) || MessageUtil.isOverByteForMessage(messageDto.getRouterSeq(), BodyCommonConfig.AGENT_CODE_BYTE_LENGTH, true)) {
+            return ServiceCode.MSG_ERROR_ROUTERSEQ.getCode();
+        }
+
+        return ServiceCode.OK.getCode();
+    }
+
+    abstract int isisValidateMessageForExtend(BasicMessageDto messageDto);
+    abstract void pushMessageToBuffer(BasicMessageDto messageDto) throws Exception;
+    abstract void initDataBuffer();
 }
 
src/main/java/com/munjaon/server/server/service/BaseService.java (added)
+++ src/main/java/com/munjaon/server/server/service/BaseService.java
@@ -0,0 +1,208 @@
+package com.munjaon.server.server.service;
+
+import com.munjaon.server.util.LogUtil;
+
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public abstract class BaseService extends Thread {
+    boolean bEndProcess = false;
+
+    public static SimpleDateFormat sdf = new SimpleDateFormat("[MM-dd HH:mm:ss]");
+    public static String LOG_DATE_FORMAT = "[MM-dd HH:mm:ss]";
+
+    public boolean ready;
+    private boolean KILL_FLAG;
+    private boolean STOP_FLAG;
+    private boolean RUN_FLAG;
+    private String LOG_FILE;
+    public LogUtil logger;
+
+    public BaseService() {}
+
+    public BaseService(String ServiceID) {
+        super(ServiceID);
+
+        LOG_FILE = getProp("LOG_FILE");
+    }
+
+    protected void checkRun() {
+        RUN_FLAG = "1".equals(getProp("RUN_FLAG")) ? true : false;
+    }
+
+    protected boolean isRun() {
+        return RUN_FLAG && !STOP_FLAG && !KILL_FLAG;
+    }
+
+    protected void setLogFile(String sLogFile) {
+        if( logger != null ) {
+            logger.close();
+            logger = null;
+        }
+
+        logger = new LogUtil( sLogFile );
+    }
+
+    protected void Init() throws Exception {
+        LOG_FILE = getProp("LOG_FILE");
+
+        setLogFile( LOG_FILE );
+
+        SystemLog("Service Initializing...");
+
+        ready = true;
+    }
+
+    public synchronized void Start() {
+        super.start();
+    }
+
+    protected synchronized void Stop() {
+        STOP_FLAG = true;
+
+        SystemLog("Service Stoping...");
+    }
+
+    protected synchronized void Kill() {
+        if( !KILL_FLAG ) SystemLog("Service Killing...");
+
+        KILL_FLAG = true;
+    }
+
+    protected void startService() throws Exception {
+        Log("startService() called.");
+    }
+
+    protected void stopService() throws Exception {
+        Log("stopService() called.");
+    }
+
+    protected synchronized void Reload() throws Exception {
+    }
+
+    @Override
+    public void run() {
+        while (!KILL_FLAG) {
+            STOP_FLAG = false;
+
+            if (isRun()) {
+                try {
+                    Init();
+
+                    SystemLog("Service Starting.");
+
+                    startService();
+                } catch (SQLException e) {
+                    STOP_FLAG = true;
+                    SystemLog("SQLErrorCode = "+e.getErrorCode());
+                    SystemLog(e);
+                } catch (Exception e) {
+                    STOP_FLAG = true;
+                    SystemLog(e);
+                } finally {
+                    ready = false;
+                    SystemLog("Service Stoped.");
+                    if( logger != null ) { logger.close(); logger = null; }
+                }
+            }
+
+            if( !KILL_FLAG ) {
+                try {
+                    Thread.sleep(5000);
+                } catch (Exception e) {
+                }
+            }
+        }
+
+        try {
+            stopService();
+        } catch (Exception e) {
+
+        }
+        SystemLog("Service Killed.");
+
+        ServiceRunner.SERVICES.remove(getName());
+        bEndProcess = true;
+    }
+
+    public void stopThread() {
+        SystemLog("kill signal has been received.");
+        SystemLog("remaining tasks are handled.");
+
+        bEndProcess = true;
+        Kill();
+
+        int i=0;
+        while (true) {
+            try {
+                Thread.sleep(1*1000);
+            } catch(InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            if(bEndProcess) {
+                break;
+            }
+
+            SystemLog("remaining tasks - processing " + (++i) + " secs.");
+        }
+
+        this.interrupt();
+        try {
+            Thread.sleep(100);
+        } catch(InterruptedException e) {
+            e.printStackTrace();
+        }
+        SystemLog("Service was interrupted.");
+    }
+
+    protected void SystemLog(Object obj) {
+        Log(obj, true);
+    }
+
+    protected void Log(Object obj) {
+        Log(obj, false);
+    }
+
+    protected void Log(Object obj, boolean bOut) {
+        if( bOut ) {
+            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern(LOG_DATE_FORMAT)) + " {{"+ getName() +"}} "+obj);
+        }
+
+        if( logger != null ) {
+            logger.log(obj);
+        }
+        else {
+            if( obj instanceof Throwable ) {
+                LogUtil.log(LOG_FILE, obj);
+            }
+            else {
+                LogUtil.log(LOG_FILE, "{{"+ getName() +"}} "+obj);
+            }
+        }
+    }
+
+    protected String getProp(String name) {
+        return getProp(getName(), name);
+    }
+
+    public static String getProp(String svc, String name) {
+        return PropertyLoader.getProp(svc, name);
+    }
+}
+
+class ShutdownService extends Thread {
+    private BaseService service = null;
+
+    public ShutdownService(BaseService service) {
+        super();
+        this.service = service;
+    }
+
+    @Override
+    public void run() {
+        service.stopThread();
+    }
+}
 
src/main/java/com/munjaon/server/server/service/PropertyLoader.java (added)
+++ src/main/java/com/munjaon/server/server/service/PropertyLoader.java
@@ -0,0 +1,79 @@
+package com.munjaon.server.server.service;
+
+import java.io.FileInputStream;
+import java.util.Properties;
+
+/**
+ * PropertyLoader
+ * @author JDS
+ */
+public class PropertyLoader extends Thread {
+
+    private static Properties props = load();
+    private static PropertyLoader loader;
+
+    public static String getProp(String key, String sub) {
+        return get(key+"."+sub);
+    }
+
+    public static String get(String key) {
+        return get(key, null);
+    }
+
+    public static String get(String key, String dflt) {
+        if( props == null ) return null;
+
+        String value = props.getProperty(key, dflt);
+
+        if( value == null ) {
+            value = dflt;
+            System.err.println("Not Defined : [" + key + "]");
+        }
+        else {
+            value = value.replaceAll("\\$WORK_HOME", System.getProperty("WORK_HOME"));
+        }
+
+        return value;
+    }
+
+    public synchronized static Properties load() {
+        String propFile = System.getProperty("PROPS");
+        try {
+            Properties properties = new Properties();
+            properties.load( new FileInputStream (propFile) );
+
+            props = properties;
+        } catch(Exception e) {
+            Log(e);
+        }
+        
+        if( loader == null ) {
+            loader = new PropertyLoader();
+            loader.start();
+        }
+
+        return props;
+    }
+
+    private synchronized static void Log(Object oLog) {
+        if ( oLog instanceof Exception ) {
+            System.out.println( (new java.util.Date()) );
+            ((Exception)oLog).printStackTrace();
+        } else {
+            System.out.println( (new java.util.Date()) + (String) oLog );
+        }
+    }
+
+    @Override
+    public void run() {
+        while( true ) {
+            try {
+                Thread.sleep(1000);
+                load();
+            } catch(Exception e) {
+                Log(e);
+            }
+        }
+    }
+
+}
 
src/main/java/com/munjaon/server/server/service/ServiceRunner.java (added)
+++ src/main/java/com/munjaon/server/server/service/ServiceRunner.java
@@ -0,0 +1,124 @@
+package com.munjaon.server.server.service;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ *
+ * @author JDS
+ */
+public class ServiceRunner extends Thread {
+
+    public static String CLASS_DIR = PropertyLoader.get("SERVICE.CLASS_DIR");
+
+    public static Hashtable SERVICES = new Hashtable();
+
+    public void run() {
+        while(true) {
+            check();
+            
+            try {
+                int iCheckCycle = Integer.parseInt(PropertyLoader.get("SERVICE.CHECK_CYCLE","3000"));
+                Thread.sleep( iCheckCycle );
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    private void check() {
+        try {
+            String[] svcs = PropertyLoader.get("SERVICE.LISTS").split(",");
+            String svc_name;
+
+            Hashtable map = new Hashtable();
+            
+            for( int i=0; i<svcs.length; i++ ) {
+                svc_name = svcs[i].trim();
+                
+                if( svc_name.length() == 0 || svc_name.startsWith("#") ) {
+                    continue;
+                }
+
+                map.put( svc_name, svc_name );
+            }
+
+            Enumeration enums = SERVICES.elements();
+            
+            while( enums.hasMoreElements() ) {
+                BaseService svc = (BaseService) enums.nextElement();
+                svc_name = svc.getName();
+
+                if( map.containsKey(svc_name) ) {
+                    svc.checkRun();
+                    if( svc.isRun() && svc.ready ) {
+                        svc.Reload();
+                    }
+
+                    map.remove(svc_name);
+                }
+                else {
+                    svc.Kill();
+                }
+            }
+
+            enums = map.elements();
+
+            ShutdownService shutdownService = null;
+            while ( enums.hasMoreElements() ) {
+                svc_name = (String) enums.nextElement();
+
+                if( SERVICES.containsKey(svc_name) ) {
+                    System.err.println("Already Started Service: "+ svc_name);
+                    continue;
+                }
+
+                String className = PropertyLoader.get(svc_name + ".CLASS");
+
+                Class cls = LoadClass( CLASS_DIR, className );
+
+                BaseService svc = (BaseService) cls.newInstance();
+                svc.setName(svc_name);
+                svc.checkRun();
+                if( svc.isRun() && svc.ready ) svc.Reload();
+
+                SERVICES.put(svc_name, svc);
+
+                shutdownService = new ShutdownService(svc);
+                Runtime.getRuntime().addShutdownHook(shutdownService);
+                svc.Start();
+
+                Thread.sleep(500);
+            }
+        } catch(Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static Class LoadClass(String className) throws Exception {
+        Class cls = Class.forName(className.trim());
+        
+        return cls;
+    }
+
+    public static Class LoadClass(String path, String className) throws Exception {
+        /**
+        URL url = new File(path).toURL();
+        URL[] urls = new URL[]{url};
+        ClassLoader loader = new URLClassLoader(urls);
+         */
+        URI uri = new File(path).toURI();
+        URL[] urls = new URL[]{uri.toURL()};
+        ClassLoader loader = new URLClassLoader(urls);
+
+        return loader.loadClass(className);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ServiceRunner().start();
+    }
+    
+}
 
src/main/java/com/munjaon/server/util/FileUtil.java (added)
+++ src/main/java/com/munjaon/server/util/FileUtil.java
@@ -0,0 +1,37 @@
+package com.munjaon.server.util;
+
+import java.io.File;
+
+/**
+ * 파일 관련 유틸리티 클래스
+ * @author JDS
+ */
+public class FileUtil {
+
+    public static boolean exists(String sFile) {
+        return exists( new File(sFile) );
+    }
+
+    public static boolean exists(File file) {
+        return file.exists();
+    }
+
+    public static boolean mkdirs(String sPath) {
+        return mkdirs(sPath, false);
+    }
+
+    public static boolean mkdirs(String sPath, boolean isFilePath) {
+        File file = new File(sPath);
+
+        if( isFilePath ) {
+            file = file.getParentFile();
+        }
+
+        if( file.exists() ) {
+            return true;
+        }
+
+        return file.mkdirs();
+    }
+
+}
 
src/main/java/com/munjaon/server/util/LogUtil.java (added)
+++ src/main/java/com/munjaon/server/util/LogUtil.java
@@ -0,0 +1,95 @@
+package com.munjaon.server.util;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 로깅 관련 유틸리티 클래스
+ * @author JDS
+ */
+public class LogUtil {
+
+    private final static String sTimeFormat = "[HH:mm:ss.SSS] ";
+    private final static String sDateFormat = "_yyyyMMdd";
+    private final static String sFileExt = ".log";
+
+    private PrintWriter out;
+    private String sLogFile;
+    private String sDate;
+
+    public LogUtil(String sLogFile) {
+        this.sLogFile = sLogFile;
+
+        if ( sLogFile != null ) {
+            FileUtil.mkdirs(sLogFile, true);
+        }
+    }
+
+    private void open() {
+        close();
+
+        if (sLogFile != null) {
+            try {
+                out = new PrintWriter( new BufferedWriter( new FileWriter(sLogFile + sDate + sFileExt, true) ), true );
+            } catch(Exception e) {
+                out = null;
+            }
+        }
+
+        if( out == null ) {
+            out = new PrintWriter(System.out, true);
+        }
+    }
+
+    public void close() {
+        if (sLogFile != null && out != null) {
+            try {
+                out.close();
+                out = null;
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    public static void log(String sFile, Object oLog) {
+        LogUtil logger = new LogUtil(sFile);
+        logger.log(oLog);
+        logger.close();
+    }
+
+    public synchronized void log(Object oLog) {
+        SimpleDateFormat sdf = new SimpleDateFormat();
+        Date date = new Date();
+
+        sdf.applyPattern(sDateFormat);
+        String sDates = sdf.format(date);
+
+        sdf.applyPattern(sTimeFormat);
+        String sTime = sdf.format(date);
+
+        try {
+            if (!sDates.equals(this.sDate)) {
+                this.sDate = sDates;
+                open();
+            }
+
+            if (oLog instanceof Exception) {
+                out.print( sTime );
+                ((Exception)oLog).printStackTrace(out);
+
+                if (sLogFile == null) {
+                    ((Exception)oLog).printStackTrace();
+                }
+            } else {
+                out.println( sTime + oLog );
+            }
+
+            out.flush();
+        } catch ( Exception e ) {
+            close();
+        }
+    }
+}
src/main/java/com/munjaon/server/util/MessageUtil.java
--- src/main/java/com/munjaon/server/util/MessageUtil.java
+++ src/main/java/com/munjaon/server/util/MessageUtil.java
@@ -1,5 +1,12 @@
 package com.munjaon.server.util;
 
+import com.munjaon.server.queue.config.BodyCommonConfig;
+import com.munjaon.server.queue.config.MediaBodyConfig;
+import com.munjaon.server.queue.config.QueueHeaderConfig;
+import com.munjaon.server.queue.config.SmsBodyConfig;
+import com.munjaon.server.queue.dto.BasicMessageDto;
+
+import java.nio.ByteBuffer;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 
@@ -25,22 +32,22 @@
     }
 
     public static String doNumber(String spell){
-        String phoneNumber = "";
-        if(spell == null){
-            return phoneNumber;
+        StringBuilder phoneNumber = new StringBuilder();
+        if (spell == null){
+            return phoneNumber.toString();
         }
         spell = spell.trim();
         int spell_Length = spell.length();
-        if(spell_Length < 1){
-            return phoneNumber;
+        if (spell_Length < 1){
+            return phoneNumber.toString();
         }
-        for(int i=0;i<spell_Length;i++){
+        for (int i=0; i<spell_Length; i++){
             char eachChar = spell.charAt(i);
             if( 0x30 <= eachChar && eachChar <= 0x39 ){
-                phoneNumber += eachChar;
+                phoneNumber.append(eachChar);
             }
         }
-        return phoneNumber;
+        return phoneNumber.toString();
     }
 
     // 소수점 뒤에 해당하는 자리만큼 자르기
@@ -49,15 +56,15 @@
         String tailNum = "";
         String retNum = "";
 
-        if(!(srcNum == null || srcNum.trim().equals(""))){
+        if(!(srcNum == null || srcNum.trim().isEmpty())){
             srcNum = srcNum.trim();
             int index = srcNum.indexOf(".");
             // 소수점 위치가 0보다 큰경우만 처리
             if(index > 0){
                 headNum = srcNum.substring(0, index);
-                tailNum = srcNum.substring((index + 1), srcNum.length());
+                tailNum = srcNum.substring((index + 1));
 
-                if(tailNum.length() == 0){
+                if (tailNum.isEmpty()) {
                     tailNum = "0";
                 }
                 if(tailNum.length() > digit){
@@ -71,19 +78,120 @@
     }
 
     // 수신번호 체크하기
-    public static boolean CheckPhone(String src) {
+    public static boolean checkPhone(String src) {
         if(src == null || src.trim().length() < 10) {
             return false;
         }
 
-        if(!src.startsWith("0")) {
-            return false;
-        }
-
-        return true;
+        return src.startsWith("0");
     }
     // 문자열 공백 제거
     public static String trim(String obj) {
         return StringUtil.trim(obj);
     }
+
+    public static boolean isEmptyForMessage(String obj, boolean trimFlag) {
+        if (trimFlag)
+            return obj == null || obj.trim().isEmpty();
+        else
+            return obj == null || obj.isEmpty();
+    }
+
+    public static boolean isEmptyForMessage(String obj) {
+        return isEmptyForMessage(obj, false);
+    }
+
+    public static boolean isOverByteForMessage(String obj, int limitCount, boolean trimFlag) {
+        if (isEmptyForMessage(obj, trimFlag)) {
+            return true;
+        }
+
+        return obj.getBytes().length > limitCount;
+    }
+
+    public static boolean isOverByteForMessage(String obj, int limitCount) {
+        return isOverByteForMessage(obj, limitCount, false);
+    }
+
+    public static int calcWritePosition(int pushCounter, int dataByteLength) {
+        return pushCounter < 0 ? QueueHeaderConfig.QUEUE_HEADER_LENGTH : (QueueHeaderConfig.QUEUE_HEADER_LENGTH + pushCounter + dataByteLength);
+    }
+
+    public static void setBytesForCommonMessage(ByteBuffer buffer, BasicMessageDto messageDto) {
+        /* 1. 사용자 아이디 */
+        buffer.position(BodyCommonConfig.USERID_BYTE_POSITION);
+        buffer.put(messageDto.getUserId().getBytes());
+        /* 2. 요금제(선불 : P / 후불 : A) */
+        buffer.position(BodyCommonConfig.FEETYPE_BYTE_POSITION);
+        buffer.put(messageDto.getFeeType().getBytes());
+        /* 3. 단가 */
+        buffer.position(BodyCommonConfig.UNITCOST_BYTE_POSITION);
+        buffer.put(messageDto.getUnitCost().getBytes());
+        /* 4. MSG Group ID */
+        buffer.position(BodyCommonConfig.MSGGROUPID_BYTE_POSITION);
+        buffer.put(messageDto.getMsgGroupID().getBytes());
+        /* 5. MSG ID */
+        buffer.position(BodyCommonConfig.MSGID_BYTE_POSITION);
+        buffer.put(messageDto.getUserMsgID().getBytes());
+        /* 6. Service Type */
+        buffer.position(BodyCommonConfig.SERVICETYPE_BYTE_POSITION);
+        buffer.put(messageDto.getServiceType().getBytes());
+        /* 7. 메시지 전송 결과 >> 성공 : 0 / 필터링 : 기타값  */
+        buffer.position(BodyCommonConfig.SENDSTATUS_BYTE_POSITION);
+        buffer.put(messageDto.getSendStatus().getBytes());
+        /* 8. 회신번호 */
+        buffer.position(BodyCommonConfig.SENDER_BYTE_POSITION);
+        buffer.put(messageDto.getUserSender().getBytes());
+        /* 9. 수신번호 */
+        buffer.position(BodyCommonConfig.RECEIVER_BYTE_POSITION);
+        buffer.put(messageDto.getUserReceiver().getBytes());
+        /* 10. 예약시간 */
+        buffer.position(BodyCommonConfig.RESERVEDT_BYTE_POSITION);
+        buffer.put(messageDto.getReserveDt().getBytes());
+        /* 11. 요청시간 */
+        buffer.position(BodyCommonConfig.REQUESTDT_BYTE_POSITION);
+        buffer.put(messageDto.getRequestDt().getBytes());
+        /* 12. 원격 주소 */
+        buffer.position(BodyCommonConfig.REMOTEIP_BYTE_POSITION);
+        buffer.put(messageDto.getRemoteIP().getBytes());
+        /* 13. 발송망 */
+        buffer.position(BodyCommonConfig.AGENT_CODE_BYTE_POSITION);
+        buffer.put(messageDto.getRouterSeq().getBytes());
+    }
+
+    public static void setBytesForSmsMessage(ByteBuffer buffer, BasicMessageDto messageDto) {
+        /* 14. 메시지 */
+        buffer.position(SmsBodyConfig.SMS_MSG_BYTE_POSITION);
+        buffer.put(messageDto.getUserMessage().getBytes());
+    }
+
+    public static void setBytesForMediaMessage(ByteBuffer buffer, BasicMessageDto messageDto) {
+        /* 14. 제목 */
+        buffer.position(MediaBodyConfig.SUBJECT_BYTE_POSITION);
+        buffer.put(messageDto.getUserSubject().getBytes());
+        /* 15. 메시지 */
+        buffer.position(MediaBodyConfig.MEDIA_MSG_BYTE_POSITION);
+        buffer.put(messageDto.getUserMessage().getBytes());
+    }
+
+    public static void setBytesForMmsMessage(ByteBuffer buffer, BasicMessageDto messageDto) {
+        /* 16. 파일카운트 */
+        buffer.position(MediaBodyConfig.FILECNT_BYTE_POSITION);
+        buffer.put(Integer.toString(messageDto.getUserFileCnt()).getBytes());
+        /* 17. 파일명 #1 */
+        buffer.position(MediaBodyConfig.FILENAME_ONE_BYTE_POSITION);
+        if (messageDto.getUserFileName01() != null) {
+            buffer.put(messageDto.getUserFileName01().getBytes());
+        }
+        /* 18. 파일명 #2 */
+        buffer.position(MediaBodyConfig.FILENAME_TWO_BYTE_POSITION);
+        if (messageDto.getUserFileName02() != null) {
+            buffer.put(messageDto.getUserFileName02().getBytes());
+        }
+        /* 19. 파일명 #3 */
+        buffer.position(MediaBodyConfig.FILENAME_THREE_BYTE_POSITION);
+        if (messageDto.getUserFileName03() != null) {
+            buffer.put(messageDto.getUserFileName03().getBytes());
+        }
+    }
 }
 
src/main/java/com/munjaon/server/util/XmlUtil.java (added)
+++ src/main/java/com/munjaon/server/util/XmlUtil.java
@@ -0,0 +1,31 @@
+package com.munjaon.server.util;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+
+public class XmlUtil {
+    private static Document getDOMParsedDocument(final String fileName) {
+        Document document = null;
+        try {
+
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            //If want to make namespace aware.
+            //factory.setNamespaceAware(true);
+            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
+            document = documentBuilder.parse(new File("employee.xml"));
+        }
+        catch (IOException | SAXException | ParserConfigurationException e) {
+            e.printStackTrace();
+        }
+        return document;
+    }
+    public static void main(String[] args) {
+
+    }
+}
Add a comment
List