shjung 3 жил өмнө
parent
commit
4d5f4588be

+ 10 - 0
pom.xml

@@ -186,6 +186,16 @@
             <artifactId>forms_rt</artifactId>
             <version>7.0.3</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
 
     </dependencies>
 

+ 389 - 0
src/main/java/com/its/app/utils/ItsUtils.java

@@ -0,0 +1,389 @@
+package com.its.app.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletRequest;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+public final class ItsUtils
+{
+	// 요일유형
+	public static final String UNKNOWN_WEEK = "DTW0";
+	public static final String MONDAY       = "DTW1";
+	public static final String TUESDAY      = "DTW2";
+	public static final String WEDNESDAY    = "DTW3";
+	public static final String THURSDAY     = "DTW4";
+	public static final String FRIDAY       = "DTW5";
+	public static final String SATURDAY     = "DTW6";
+	public static final String SUNDAY       = "DTW7";
+
+	public static String getCurrFiveMinString() {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(new Date());
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		int min = cal.get(Calendar.MINUTE);
+		cal.add(Calendar.MINUTE, -(min % 5));
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	public static Date getPrcsDt(String prcsDt) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date to = null;
+		try {
+			to = transFormat.parse(prcsDt);
+		} catch (ParseException e) {
+			log.error("getPrcsDt: ParseException");
+		}
+		return to;
+	}
+
+	public static String getMissSttsYn(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "Y";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "Y";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "Y" : "N";
+	}
+
+	public static String getRseCommStts(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "CMS1";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "CMS1";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 30 ? "CMS1" : "CMS0";
+	}
+
+	public static String getServiceYn(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "N";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "N";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "N" : "Y";
+	}
+
+	public static String getMissYn(String prcsDt, String CMTR_GRAD_CD) {
+
+		if (("LTC0").equals(CMTR_GRAD_CD)) {
+			return "Y";
+		}
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "Y";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "Y";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "Y" : "N";
+	}
+	public static Date stringToDate(String paramTime) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date to = null;
+		try {
+			to = transFormat.parse(paramTime);
+		} catch (ParseException e) {
+			log.error("stringToDate: ParseException");
+		}
+
+		return to;
+	}
+
+	public static int getDiffMinutes(String fromDt, String toDt) {
+		Date dtFrom = stringToDate(fromDt);
+		Date dtTo = stringToDate(toDt);
+		GregorianCalendar gcFromDt= new GregorianCalendar();
+		GregorianCalendar gcToDt = new GregorianCalendar();
+		gcFromDt.setTime(dtFrom);
+		gcToDt.setTime(dtTo);
+		long gap = gcToDt.getTimeInMillis() - gcFromDt.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return (int)min;
+	}
+
+	// 0--6: Sunday = 0, C/C++ struct tm, tm_wday
+	// 1--7: oracle, SELECT TO_CHAR(SYSDATE, 'D') FROM DUAL;, 주중의 일을 1~7로 표시(일요일이 1)
+	//     : java, Calendar cal; cal.get(Calendar.DAY_OF_WEEK, sunday=1, monday=2, ...)
+	public static String getDayOfWeek() {
+		Date dtNow = new Date();
+		int week = getDayWeek(dtNow);
+		return getDayOfWeek(week);
+	}
+	public static String getDayOfWeek(int week) {
+
+		String sWeek = UNKNOWN_WEEK;
+		switch(week)
+		{
+			case 1: sWeek = SUNDAY; 	break;
+			case 2: sWeek = MONDAY; 	break;
+			case 3: sWeek = TUESDAY; 	break;
+			case 4: sWeek = WEDNESDAY; 	break;
+			case 5: sWeek = THURSDAY; 	break;
+			case 6: sWeek = FRIDAY; 	break;
+			case 7: sWeek = SATURDAY; 	break;
+		}
+		return sWeek;
+	}
+	public static int getDayWeek(String paramDt) {
+		return getDayWeek(stringToDate(paramDt));
+	}
+	public static int getDayWeek(Date paramDt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		return cal.get(Calendar.DAY_OF_WEEK);		/* DAY_OF_WEEK 리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다. */
+	}
+
+	public static String getFromToday()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow)+"000000";
+	}
+
+	public static String getSysTime()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+
+	public static String getSysTime(String format)
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat(format);
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	public static String getSysMonth()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMM");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	public static String getSysDay()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	/**
+	 * 월 마지막날 가져오기 * @param yyyyMM
+	 * @return : yyyyMMdd
+	 */
+	public static String getLastDayOfMonth(String yyyyMMdd) {
+
+		String year  = yyyyMMdd.substring(0, 4);
+		String month = yyyyMMdd.substring(4, 6);
+
+		Calendar cal = Calendar.getInstance();
+		cal.set(Integer.parseInt(year), Integer.parseInt(month) - 1, 1);
+		String lastDay = year + month + Integer.toString(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+		return lastDay;
+	}
+
+	public static void saveByteArrayToFile(String filePath, byte[] byteArrayData) {
+		try {
+			FileUtils.writeByteArrayToFile(new File(filePath), byteArrayData);
+		}
+		catch (IOException e) {
+			log.error("saveByteArrayToFile: IOException");
+		}
+	}
+
+	public static byte[] convertBmpToPng(byte[] bmpArrayData) {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		ByteArrayInputStream inStream = new ByteArrayInputStream(bmpArrayData);
+
+		try {
+			BufferedImage newImage = ImageIO.read(inStream);
+			ImageIO.write(newImage, "png", out);
+			return out.toByteArray();
+		}
+		catch (IOException e) {
+			log.error("saveByteArrayToFile: IOException");
+		}
+		finally {
+			try {
+				out.close();
+				inStream.close();
+			} catch (IOException e) {
+				log.error("saveByteArrayToFile: out close IOException");
+			}
+		}
+		return null;
+	}
+
+	public static String createUserDir(String userDir) {
+
+		final String sysDir = System.getProperty("user.dir");
+		String createdDir = sysDir + userDir;
+		try {
+			Path path = Paths.get(createdDir);
+			//java.nio.file.Files;
+			Files.createDirectories(path);
+
+		}
+		catch (IOException e) {
+			log.error("createUserDir: IOException");
+		}
+		return createdDir;
+	}
+	public static synchronized void saveImageFile(BufferedImage image, String extension, String fullPath)
+	{
+		try (
+			OutputStream out2 = new FileOutputStream(fullPath);
+		) {
+			ImageIO.write(image, extension, out2);
+			out2.close();
+			//RenderedImage rendImage = image;
+			//ImageIO.write(image, "bmp", new File(fullPath));
+		}
+		catch (IOException e) {
+			log.error("saveImageFile: IOException");
+		}
+	}
+
+/*
+	public static byte[] bitmapToByteArray( Bitmap bitmap ) {
+		ByteArrayOutputStream stream = new ByteArrayOutputStream() ;
+		bitmap.compress( Bitmap.CompressFormat.PNG, 100, stream) ;
+		byte[] byteArray = stream.toByteArray() ;
+		return byteArray ;
+	}
+	public static Bitmap byteArrayToBitmap(byte[] bytearr) {
+		return BitmapFactory.decodeByteArray(bytearr, 0, bytearr.length);
+	}*/
+
+/**
+ * Bitmap bitmap;
+ *
+ * ByteBuffer buffer= ByteBuffer.Allocate(bitmap.ByteCount);
+ * bitmap.copyPixelsToBuffer(buffer);
+ * byte[] byteArray = buffer.ToArray<byte>();
+ *
+ * byte[] byteArray;
+ * Bitmap bitmap;
+ *
+ * int width = 112;
+ * int height = 112;
+ *
+ * bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ * ByteBuffer buffer = ByteBuffer.wrap(byteArray);
+ * buffer.rewind();
+ * bitmap.copyPixelsFromBuffer(buffer);
+ */
+
+	public static List<String> split(String value, String delim) {
+
+		List<String> list = new ArrayList<String>();
+
+		StringTokenizer stringTokenizer = new StringTokenizer(value, delim);
+		while (stringTokenizer.hasMoreTokens()) {
+			list.add(stringTokenizer.nextToken().trim());
+		}
+
+		return list;
+	}
+
+	public static int swapEndian(int x) {
+		return swapEndian((short)x) << 16 | swapEndian((short)(x >> 16)) & 0xFFFF;
+	}
+
+	public static short swapEndian(short x) {
+		return (short)(x << 8 | x >> 8 & 0xFF);
+	}
+
+
+	public static String getHttpServletRemoteIP(HttpServletRequest request) {
+		if (request == null) {
+			return "";
+		}
+
+		String ipAddress = request.getHeader("X-FORWARDED-FOR");
+		// proxy 환경일 경우
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("Proxy-Client-IP");
+		}
+		// 웹로직 서버일 경우
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("WL-Proxy-Client-IP");
+		}
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("HTTP_CLIENT_IP");
+		}
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
+		}
+		// 기타
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getRemoteAddr() ;
+		}
+		//-Djava.net.preferIPv4Stack=true
+		if (ipAddress.equals("0:0:0:0:0:0:0:1"))   //==> ipv6 <== default
+		{
+			ipAddress = "127.0.0.1";   //==> localhost
+		}
+		return ipAddress;
+	}
+}

+ 2 - 3
src/main/java/com/its/vds/VdsCommServerApplication.java

@@ -80,9 +80,9 @@ public class VdsCommServerApplication implements CommandLineRunner, ApplicationL
         SwingUtilities.invokeLater(() -> {
             String pathOfImage = "C:\\DEV\\ITS\\01.WINDOWS\\22.01.YONGIN\\JAVA\\vds-comm-server\\src\\main\\resources\\static\\image\\application.png";
             String sysTime = SysUtils.getSysTimeStr();
+            //JFrame.setDefaultLookAndFeelDecorated(true);
             JFrame frame = new JFrame("VDS 통신 서버 - [" + sysTime + "]");
             MainUI UI = new MainUI();
-            //JFrame.setDefaultLookAndFeelDecorated(true);
             frame.setIconImage(Toolkit.getDefaultToolkit().getImage(pathOfImage));
             frame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
             frame.setContentPane(UI.getRootPanel());
@@ -90,8 +90,7 @@ public class VdsCommServerApplication implements CommandLineRunner, ApplicationL
             frame.addWindowListener(new WindowAdapter() {
                 @Override
                 public void windowClosing(WindowEvent e) {
-                    if (JOptionPane.showConfirmDialog(UI.getRootPanel(), "시스템을 종료 하시겠습니까?", "시스템 종료", 0) == 0){
-                        //terminateApplication();
+                    if (JOptionPane.showConfirmDialog(UI.getRootPanel(), "시스템을 종료 하시겠습니까?", "시스템 종료", 0) == 0) {
                         System.exit(0);
                     } else {
                         frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

+ 68 - 0
src/main/java/com/its/vds/entity/TbVdsCtlr.java

@@ -2,6 +2,7 @@ package com.its.vds.entity;
 
 import com.its.app.utils.SysUtils;
 import com.its.vds.domain.NET;
+import com.its.vds.xnettcp.vds.handler.VdsTcpClientIdleHandler;
 import com.its.vds.xnettcp.vds.protocol.*;
 import com.its.vds.xnetudp.protocol.voVdsState;
 import io.netty.channel.Channel;
@@ -138,6 +139,8 @@ public class TbVdsCtlr {
 		this.requestStopImage = false;
 		this.cameraNo = 0;
 		this.frameNo = 0;
+		this.requestImageList.clear();
+		this.requestImageList = new ArrayList<>();
 	}
 
 	public TbVdsCtlr() {
@@ -273,4 +276,69 @@ public class TbVdsCtlr {
 
 		return ss;
 	}
+
+	public boolean channelClose() {
+		if (getChannel() == null || getNetState() == NET.CLOSED) {
+			log.error("Close Request: channel not connected: [{}]", this);
+			return false;
+		}
+		VdsTcpClientIdleHandler.disconnectChannel(getChannel());
+		return true;
+	}
+
+	public boolean reset() {
+		if (getChannel() == null || getNetState() == NET.CLOSED) {
+			log.error("Reset Request: channel not connected: [{}]", this);
+			return false;
+		}
+		VdsReqReset vdsReq = new VdsReqReset((short)getGROUP_NO(), (short)getVDS_CTLR_LOCAL_NO());
+		vdsReq.makeCRC();
+		ByteBuffer sendBuffer = vdsReq.getByteBuffer();
+		if (!sendData(sendBuffer, 0, "vds_Reset")) {
+			log.error("Reset Data Send Failed: [{}]", this);
+			return false;
+		} else {
+			log.error("Reset Data Send Failed: [{}]", this);
+			return true;
+		}
+	}
+
+	public boolean initialize() {
+		if (getChannel() == null || getNetState() == NET.CLOSED) {
+			log.error("Initialize Request: channel not connected: [{}]", this);
+			return false;
+		}
+		VdsReqInitialize vdsReq = new VdsReqInitialize((short)getGROUP_NO(), (short)getVDS_CTLR_LOCAL_NO());
+		vdsReq.makeCRC();
+		ByteBuffer sendBuffer = vdsReq.getByteBuffer();
+		if (!sendData(sendBuffer, 0, "vds_Initialize")) {
+			log.error("Initialize Data Send Failed: [{}]", this);
+			return false;
+		} else {
+			log.error("Initialize Data Send Failed: [{}]", this);
+			return true;
+		}
+	}
+
+	public boolean stopImage(byte cameraNo) {
+		if (getChannel() == null || getNetState() == NET.CLOSED) {
+			log.error("StopImage Request: channel not connected: [{}]", this);
+			return false;
+		}
+		int frameNo = 0;    // first image request
+		setStopImageRequest(getChannel(), cameraNo, frameNo);
+		VdsReqImage reqImage = new VdsReqImage((short)getGROUP_NO(), (short)getVDS_CTLR_LOCAL_NO());
+		reqImage.setCameraNo(cameraNo);
+		reqImage.setFrameNo(frameNo);
+		reqImage.makeCRC();
+		ByteBuffer sendBuffer = reqImage.getByteBuffer();
+		if (!sendData(sendBuffer, 0, "vds_Image")) {
+			setStopImageResponse();
+			log.error("StopImage Data Send Failed: [{}]", this);
+			return false;
+		} else {
+			log.error("StopImage Data Send Failed: [{}]", this);
+			return true;
+		}
+	}
 }

+ 5 - 0
src/main/java/com/its/vds/ui/CtlrSttsTableModel.java

@@ -73,6 +73,11 @@ public class CtlrSttsTableModel extends AbstractTableModel {
         return getValueAt(0, columnIndex).getClass();
     }
 
+    public TbVdsCtlr getControllerInfo(int row) {
+        TbVdsCtlr info = this.ctlrList.get(row);
+        return info;
+    }
+
     @Override
     public Object getValueAt(int rowIndex, int columnIndex) {
         Object returnValue = null;

+ 0 - 6
src/main/java/com/its/vds/ui/JTextAreaOutputStream.java

@@ -49,12 +49,6 @@ public class JTextAreaOutputStream extends OutputStream {
             public void run()
             {
                 synchronized (logArea) {
-//                    if (logArea.getDocument().getLength() > 50000) {
-//                        try {
-//                            logArea.getDocument().remove(0,5000);
-//                        } catch (BadLocationException e) {
-//                        }
-//                    }
                     if (logArea.getLineCount() > 2000) {
                         logArea.setText(null);
                     }

+ 92 - 1
src/main/java/com/its/vds/ui/MainUI.form

@@ -8,7 +8,7 @@
     <properties/>
     <border type="none"/>
     <children>
-      <grid id="d0095" binding="pnlCtlr" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+      <grid id="d0095" binding="pnlCtlr" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
         <margin top="10" left="4" bottom="0" right="4"/>
         <constraints>
           <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -99,6 +99,97 @@
               </component>
             </children>
           </scrollpane>
+          <grid id="17544" binding="pnlControl" layout-manager="GridLayoutManager" row-count="1" column-count="8" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="660a8" class="javax.swing.JButton" binding="btnImage">
+                <constraints>
+                  <grid row="0" column="7" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="정지영상"/>
+                </properties>
+              </component>
+              <hspacer id="60c19">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="3d84f" class="javax.swing.JButton" binding="btnInitialize">
+                <constraints>
+                  <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="초기화"/>
+                </properties>
+              </component>
+              <component id="7c99b" class="javax.swing.JButton" binding="btnReset">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="리셋"/>
+                </properties>
+              </component>
+              <component id="a85f9" class="javax.swing.JButton" binding="btnDisconnect">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="연결끊기"/>
+                </properties>
+              </component>
+              <component id="a6a03" class="javax.swing.JTextField" binding="txtName">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="200" height="-1"/>
+                    <preferred-size width="200" height="-1"/>
+                    <maximum-size width="200" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <text value="제어기 명칭"/>
+                </properties>
+              </component>
+              <component id="6d1e0" class="javax.swing.JTextField" binding="txtId">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="100" height="-1"/>
+                    <preferred-size width="100" height="-1"/>
+                    <maximum-size width="100" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <text value="ID"/>
+                </properties>
+              </component>
+              <component id="7eb53" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <icon value="static/image/select.png"/>
+                  <text value="선택한 제어기 "/>
+                </properties>
+              </component>
+            </children>
+          </grid>
         </children>
       </grid>
       <grid id="1a658" binding="pnlLog" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">

+ 192 - 25
src/main/java/com/its/vds/ui/MainUI.java

@@ -4,6 +4,7 @@ import com.intellij.uiDesigner.core.GridConstraints;
 import com.intellij.uiDesigner.core.GridLayoutManager;
 import com.intellij.uiDesigner.core.Spacer;
 import com.its.app.utils.SysUtils;
+import com.its.vds.domain.NET;
 import com.its.vds.entity.TbVdsCtlr;
 import com.its.vds.global.AppRepository;
 import com.its.vds.service.VdsCtlrService;
@@ -25,6 +26,8 @@ import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.io.File;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
@@ -39,6 +42,7 @@ public class MainUI {
     OperatingSystemMXBean osBean = null;
     private Timer timer;
     private Long tick = Long.valueOf(0);
+    private TbVdsCtlr selObj = null;
 
     private CtlrSttsTableModel ctlrSttsTableModel;
     private TableCellRenderer cellRenderer = new CtlrSttsTableCellRenderer();
@@ -60,6 +64,13 @@ public class MainUI {
     private JLabel lblError;
     private JLabel lblCpuRate;
     private JLabel lblMemoryUsage;
+    private JPanel pnlControl;
+    private JButton btnImage;
+    private JButton btnInitialize;
+    private JButton btnReset;
+    private JButton btnDisconnect;
+    private JTextField txtName;
+    private JTextField txtId;
 
     public static MainUI getInstance() {
         return _instance;
@@ -159,6 +170,117 @@ public class MainUI {
                 clpBrd.setContents(stringSelection, null);
             }
         });
+
+        tblCtlrList.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent me) {
+                // double click
+                if (me.getClickCount() == 2) {
+                    updateControllerInfo();
+
+                }
+            }
+        });
+        btnDisconnect.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(1);
+            }
+        });
+        btnReset.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(2);
+            }
+        });
+        btnInitialize.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(3);
+            }
+        });
+        btnImage.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(4);
+            }
+        });
+    }
+
+    /**
+     * 제어기 명령 처리
+     *
+     * @param type
+     */
+    public void controlController(int type) {
+        if (selObj == null) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 선택되지 않았습니다. 목록을 더블클릭하여 제어기를 선택하세요.", "제어기 선택", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (selObj.getNetState() == NET.CLOSED) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 현재 연결이 되어 있지 않습니다.", "제어기 연결 상태", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        String message, title;
+        switch (type) {
+            case 1:
+                message = "제어기와의 연결을 종료 하시겠습니까?";
+                title = "제어기 연결 종료";
+                break;
+            case 2:
+                message = "제어기를 리셋 하시겠습니까?";
+                title = "제어기 리셋";
+                break;
+            case 3:
+                message = "제어기를 초기화 하시겠습니까?";
+                title = "제어기 초기화";
+                break;
+            case 4:
+                message = "제어기의 정지영상 정보를 요청하시겠습니까?";
+                title = "제어기 정지영상 요청";
+                break;
+            default:
+                return;
+        }
+        if (JOptionPane.showConfirmDialog(getRootPanel(), message, title, JOptionPane.YES_NO_OPTION) != 0) {
+            return;
+        }
+
+        boolean result = false;
+        switch (type) {
+            case 1:
+                result = selObj.channelClose();
+                break;
+            case 2:
+                result = selObj.reset();
+                break;
+            case 3:
+                result = selObj.initialize();
+                break;
+            case 4:
+                result = selObj.stopImage((byte) 0x01);
+                break;
+            default:
+                return;
+        }
+        if (!result) {
+            JOptionPane.showMessageDialog(getRootPanel(), "명령 전송이 실패 하였습니다.", title, JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void updateControllerInfo() {
+        int row = tblCtlrList.getSelectedRow();
+        if (row < 0) {
+            return;
+        }
+
+        txtId.setText("");
+        txtName.setText("");
+        CtlrSttsTableModel tableModel = (CtlrSttsTableModel) tblCtlrList.getModel();
+        selObj = tableModel.getControllerInfo(row);
+        if (selObj != null) {
+            txtId.setText(selObj.getVDS_CTLR_ID());
+            txtName.setText(selObj.getVDS_NM());
+        }
     }
 
     /**
@@ -280,7 +402,7 @@ public class MainUI {
         rootPanel = new JPanel();
         rootPanel.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
         pnlCtlr = new JPanel();
-        pnlCtlr.setLayout(new GridLayoutManager(2, 1, new Insets(10, 4, 0, 4), -1, -1));
+        pnlCtlr.setLayout(new GridLayoutManager(3, 1, new Insets(10, 4, 0, 4), -1, -1));
         rootPanel.add(pnlCtlr, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
         pnlCtlrTitle = new JPanel();
         pnlCtlrTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), -1, -1));
@@ -326,21 +448,66 @@ public class MainUI {
         Font tblCtlrListFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, tblCtlrList.getFont());
         if (tblCtlrListFont != null) tblCtlrList.setFont(tblCtlrListFont);
         scrollPane1.setViewportView(tblCtlrList);
+        pnlControl = new JPanel();
+        pnlControl.setLayout(new GridLayoutManager(1, 8, new Insets(0, 0, 0, 2), 1, 1));
+        pnlCtlr.add(pnlControl, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        btnImage = new JButton();
+        Font btnImageFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnImage.getFont());
+        if (btnImageFont != null) btnImage.setFont(btnImageFont);
+        btnImage.setText("정지영상");
+        pnlControl.add(btnImage, new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer2 = new Spacer();
+        pnlControl.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnInitialize = new JButton();
+        Font btnInitializeFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnInitialize.getFont());
+        if (btnInitializeFont != null) btnInitialize.setFont(btnInitializeFont);
+        btnInitialize.setText("초기화");
+        pnlControl.add(btnInitialize, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnReset = new JButton();
+        Font btnResetFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnReset.getFont());
+        if (btnResetFont != null) btnReset.setFont(btnResetFont);
+        btnReset.setText("리셋");
+        pnlControl.add(btnReset, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnDisconnect = new JButton();
+        Font btnDisconnectFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnDisconnect.getFont());
+        if (btnDisconnectFont != null) btnDisconnect.setFont(btnDisconnectFont);
+        btnDisconnect.setText("연결끊기");
+        pnlControl.add(btnDisconnect, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        txtName = new JTextField();
+        txtName.setEditable(false);
+        Font txtNameFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtName.getFont());
+        if (txtNameFont != null) txtName.setFont(txtNameFont);
+        txtName.setHorizontalAlignment(2);
+        txtName.setText("제어기 명칭");
+        pnlControl.add(txtName, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(200, -1), new Dimension(200, -1), new Dimension(200, -1), 0, false));
+        txtId = new JTextField();
+        txtId.setEditable(false);
+        Font txtIdFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtId.getFont());
+        if (txtIdFont != null) txtId.setFont(txtIdFont);
+        txtId.setHorizontalAlignment(0);
+        txtId.setText("ID");
+        pnlControl.add(txtId, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), new Dimension(100, -1), new Dimension(100, -1), 0, false));
+        final JLabel label4 = new JLabel();
+        Font label4Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label4.getFont());
+        if (label4Font != null) label4.setFont(label4Font);
+        label4.setIcon(new ImageIcon(getClass().getResource("/static/image/select.png")));
+        label4.setText("선택한 제어기 ");
+        pnlControl.add(label4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         pnlLog = new JPanel();
         pnlLog.setLayout(new GridLayoutManager(2, 1, new Insets(0, 4, 0, 4), -1, -1));
         rootPanel.add(pnlLog, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(-1, 300), new Dimension(-1, 300), new Dimension(-1, 300), 0, false));
         pnlLogTitle = new JPanel();
         pnlLogTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), 1, 1));
         pnlLog.add(pnlLogTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
-        final JLabel label4 = new JLabel();
-        Font label4Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label4.getFont());
-        if (label4Font != null) label4.setFont(label4Font);
-        label4.setHorizontalAlignment(2);
-        label4.setIcon(new ImageIcon(getClass().getResource("/static/image/logging.png")));
-        label4.setText("시스템 로그");
-        pnlLogTitle.add(label4, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
-        final Spacer spacer2 = new Spacer();
-        pnlLogTitle.add(spacer2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        final JLabel label5 = new JLabel();
+        Font label5Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label5.getFont());
+        if (label5Font != null) label5.setFont(label5Font);
+        label5.setHorizontalAlignment(2);
+        label5.setIcon(new ImageIcon(getClass().getResource("/static/image/logging.png")));
+        label5.setText("시스템 로그");
+        pnlLogTitle.add(label5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer3 = new Spacer();
+        pnlLogTitle.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
         btnLogDirOpen = new JButton();
         Font btnLogDirOpenFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogDirOpen.getFont());
         if (btnLogDirOpenFont != null) btnLogDirOpen.setFont(btnLogDirOpenFont);
@@ -382,8 +549,8 @@ public class MainUI {
         pnlStatusBar = new JPanel();
         pnlStatusBar.setLayout(new GridLayoutManager(1, 7, new Insets(0, 4, 4, 4), -1, -1));
         rootPanel.add(pnlStatusBar, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
-        final Spacer spacer3 = new Spacer();
-        pnlStatusBar.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        final Spacer spacer4 = new Spacer();
+        pnlStatusBar.add(spacer4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
         lblSystime = new JLabel();
         Font lblSystimeFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblSystime.getFont());
         if (lblSystimeFont != null) lblSystime.setFont(lblSystimeFont);
@@ -391,10 +558,10 @@ public class MainUI {
         lblSystime.setHorizontalTextPosition(0);
         lblSystime.setText(" 2022-08-04 13:24:33 ");
         pnlStatusBar.add(lblSystime, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
-        final JLabel label5 = new JLabel();
-        label5.setIcon(new ImageIcon(getClass().getResource("/static/image/on.png")));
-        label5.setText(" ");
-        pnlStatusBar.add(label5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label6 = new JLabel();
+        label6.setIcon(new ImageIcon(getClass().getResource("/static/image/on.png")));
+        label6.setText(" ");
+        pnlStatusBar.add(label6, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         lblCpuRate = new JLabel();
         Font lblCpuRateFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblCpuRate.getFont());
         if (lblCpuRateFont != null) lblCpuRate.setFont(lblCpuRateFont);
@@ -409,20 +576,20 @@ public class MainUI {
         lblMemoryUsage.setHorizontalTextPosition(0);
         lblMemoryUsage.setText("    ");
         pnlStatusBar.add(lblMemoryUsage, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
-        final JLabel label6 = new JLabel();
-        Font label6Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label6.getFont());
-        if (label6Font != null) label6.setFont(label6Font);
-        label6.setHorizontalAlignment(0);
-        label6.setHorizontalTextPosition(0);
-        label6.setText("  CPU 사용율(%):");
-        pnlStatusBar.add(label6, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         final JLabel label7 = new JLabel();
         Font label7Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label7.getFont());
         if (label7Font != null) label7.setFont(label7Font);
         label7.setHorizontalAlignment(0);
         label7.setHorizontalTextPosition(0);
-        label7.setText("  메모리 사용율(%):");
-        pnlStatusBar.add(label7, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        label7.setText("  CPU 사용율(%):");
+        pnlStatusBar.add(label7, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label8 = new JLabel();
+        Font label8Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label8.getFont());
+        if (label8Font != null) label8.setFont(label8Font);
+        label8.setHorizontalAlignment(0);
+        label8.setHorizontalTextPosition(0);
+        label8.setText("  메모리 사용율(%):");
+        pnlStatusBar.add(label8, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
     }
 
     /**

+ 387 - 0
src/main/java/com/its/vds/ui/SubUI.form

@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.its.vds.ui.SubUI">
+  <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="979" height="620"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="d0095" binding="pnlCtlr" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="10" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="d1b2f" binding="pnlCtlrTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="25222" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <horizontalTextPosition value="11"/>
+                  <icon value="static/image/controller.png"/>
+                  <text value="제어기 정보"/>
+                </properties>
+              </component>
+              <hspacer id="e90f6">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="c9b9" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="제어기 전체: "/>
+                </properties>
+              </component>
+              <component id="20b88" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="통신 이상: "/>
+                </properties>
+              </component>
+              <component id="baf10" class="javax.swing.JLabel" binding="lblTotal">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+              <component id="1c841" class="javax.swing.JLabel" binding="lblError">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <foreground color="-65536"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="b21be">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="a0dd1" class="javax.swing.JTable" binding="tblCtlrList">
+                <constraints/>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+          <grid id="17544" binding="pnlControl" layout-manager="GridLayoutManager" row-count="1" column-count="8" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="660a8" class="javax.swing.JButton" binding="btnImage">
+                <constraints>
+                  <grid row="0" column="7" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="정지영상"/>
+                </properties>
+              </component>
+              <hspacer id="60c19">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="3d84f" class="javax.swing.JButton" binding="btnInitialize">
+                <constraints>
+                  <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="초기화"/>
+                </properties>
+              </component>
+              <component id="7c99b" class="javax.swing.JButton" binding="btnReset">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="리셋"/>
+                </properties>
+              </component>
+              <component id="a85f9" class="javax.swing.JButton" binding="btnDisconnect">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="연결끊기"/>
+                </properties>
+              </component>
+              <component id="a6a03" class="javax.swing.JTextField" binding="txtName">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="200" height="-1"/>
+                    <preferred-size width="200" height="-1"/>
+                    <maximum-size width="200" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <text value="제어기 명칭"/>
+                </properties>
+              </component>
+              <component id="6d1e0" class="javax.swing.JTextField" binding="txtId">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="100" height="-1"/>
+                    <preferred-size width="100" height="-1"/>
+                    <maximum-size width="100" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <text value="ID"/>
+                </properties>
+              </component>
+              <component id="7eb53" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <icon value="static/image/select.png"/>
+                  <text value="선택한 제어기 "/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+        </children>
+      </grid>
+      <grid id="1a658" binding="pnlLog" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+            <minimum-size width="-1" height="300"/>
+            <preferred-size width="-1" height="300"/>
+            <maximum-size width="-1" height="300"/>
+          </grid>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="dbb05" binding="pnlLogTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="9ac90" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <icon value="static/image/logging.png"/>
+                  <text value="시스템 로그"/>
+                </properties>
+              </component>
+              <hspacer id="656fd">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="df2a0" class="javax.swing.JButton" binding="btnLogDirOpen">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="로그 폴더"/>
+                </properties>
+              </component>
+              <component id="69a98" class="javax.swing.JButton" binding="btnLogPause">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="지우기"/>
+                </properties>
+              </component>
+              <component id="1e9e7" class="javax.swing.JCheckBox" binding="chkLogPause">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="11"/>
+                  <text value="멈춤"/>
+                </properties>
+              </component>
+              <component id="ba97c" class="javax.swing.JButton" binding="btnLogCopy">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="복사"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="a6866">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="D2Coding" size="12" style="0"/>
+            </properties>
+            <border type="none"/>
+            <children>
+              <component id="8ce8a" class="javax.swing.JTextArea" binding="taLog">
+                <constraints/>
+                <properties>
+                  <background color="-16777216"/>
+                  <caretColor color="-1"/>
+                  <editable value="false"/>
+                  <font name="D2Coding" size="14" style="0"/>
+                  <foreground color="-1"/>
+                  <margin top="4" left="4" bottom="4" right="4"/>
+                  <text value="[10:50:08.561] [ INFO] ************************************************************************************&#10;[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **&#10;[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0&#10;[10:50:08.561] [ INFO] **      listenPort: 9901&#10;[10:50:08.561] [ INFO] **         backlog: 1024&#10;[10:50:08.561] [ INFO] **   acceptThreads: 16&#10;[10:50:08.561] [ INFO] **   workerThreads: 16&#10;[10:50:08.561] [ INFO] ************************************************************************************&#10;"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+        </children>
+      </grid>
+      <grid id="e0774" binding="pnlStatusBar" layout-manager="GridLayoutManager" row-count="1" column-count="7" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="4" right="4"/>
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <hspacer id="653ec">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+          </hspacer>
+          <component id="20f9" class="javax.swing.JLabel" binding="lblSystime">
+            <constraints>
+              <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value=" 2022-08-04 13:24:33 "/>
+            </properties>
+          </component>
+          <component id="a516b" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <icon value="static/image/on.png"/>
+              <text value=" "/>
+            </properties>
+          </component>
+          <component id="94189" class="javax.swing.JLabel" binding="lblCpuRate">
+            <constraints>
+              <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="19dbe" class="javax.swing.JLabel" binding="lblMemoryUsage">
+            <constraints>
+              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="f6d5e" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  CPU 사용율(%):"/>
+            </properties>
+          </component>
+          <component id="d8ff5" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  메모리 사용율(%):"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>

+ 624 - 0
src/main/java/com/its/vds/ui/SubUI.java

@@ -0,0 +1,624 @@
+package com.its.vds.ui;
+
+import com.intellij.uiDesigner.core.GridConstraints;
+import com.intellij.uiDesigner.core.GridLayoutManager;
+import com.intellij.uiDesigner.core.Spacer;
+import com.its.app.utils.SysUtils;
+import com.its.vds.domain.NET;
+import com.its.vds.entity.TbVdsCtlr;
+import com.its.vds.global.AppRepository;
+import com.its.vds.service.VdsCtlrService;
+import com.sun.management.OperatingSystemMXBean;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.Timer;
+import javax.swing.*;
+import javax.swing.border.MatteBorder;
+import javax.swing.plaf.FontUIResource;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
+import javax.swing.text.StyleContext;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.*;
+
+@Slf4j
+@Getter
+public class SubUI {
+    private static SubUI _instance = null;
+    private VdsCtlrService vdsCtlrService = null;
+    OperatingSystemMXBean osBean = null;
+    private Timer timer;
+    private Long tick = Long.valueOf(0);
+    private TbVdsCtlr selObj = null;
+
+    private CtlrSttsTableModel ctlrSttsTableModel;
+    private TableCellRenderer cellRenderer = new CtlrSttsTableCellRenderer();
+
+    private JPanel rootPanel;
+    private JPanel pnlCtlr;
+    private JPanel pnlLog;
+    private JPanel pnlLogTitle;
+    private JPanel pnlCtlrTitle;
+    private JButton btnLogDirOpen;
+    private JButton btnLogPause;
+    private JCheckBox chkLogPause;
+    private JLabel lblSystime;
+    private JPanel pnlStatusBar;
+    private JTable tblCtlrList;
+    private JTextArea taLog;
+    private JButton btnLogCopy;
+    private JLabel lblTotal;
+    private JLabel lblError;
+    private JLabel lblCpuRate;
+    private JLabel lblMemoryUsage;
+    private JPanel pnlControl;
+    private JButton btnImage;
+    private JButton btnInitialize;
+    private JButton btnReset;
+    private JButton btnDisconnect;
+    private JTextField txtName;
+    private JTextField txtId;
+
+    public static SubUI getInstance() {
+        return _instance;
+    }
+
+    public void displaySystime() {
+        lblSystime.setText(" " + SysUtils.getSysTimeStr() + "  ");
+        updateCommSttsTotal();
+    }
+
+    public void displayResource() {
+        long memoryUsage = Math.round(((double) (osBean.getTotalPhysicalMemorySize() - osBean.getFreePhysicalMemorySize())) / (double) osBean.getTotalPhysicalMemorySize() * 100.0);
+        lblMemoryUsage.setText(String.valueOf(memoryUsage));
+        double cpuLoad = osBean.getSystemCpuLoad();
+        lblCpuRate.setText(String.valueOf(Math.round(cpuLoad * 100.0)));
+    }
+
+    public SubUI() {
+        System.setProperty("awt.useSystemAAFontSettings", "false"); // AntiAliasing false
+
+        if (_instance == null) {
+            _instance = this;
+        }
+        osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
+        try {
+            Font font = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/D2Coding.ttc"));
+            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+            ge.registerFont(font);
+        } catch (FontFormatException e) {
+        } catch (IOException e) {
+        }
+
+        //taLog.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
+        Font d2font = new Font("D2Coding", Font.PLAIN, 14);
+        if (d2font != null) {
+            taLog.setFont(d2font);
+        }
+
+//        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+//        String fontNames[] = ge.getAvailableFontFamilyNames();
+//        for (int ii = 0; ii < fontNames.length; ii++) {
+//            log.error("GraphicsEnvironment Fonts: {}", fontNames[ii]);
+//        }
+//        final Font fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+//        for (Font font : fonts) {
+//            log.error("FONTS: {}", font);
+//        }
+
+        displaySystime();
+        displayResource();
+        timer = new Timer(1000, new ActionListener() {
+            public void actionPerformed(ActionEvent evt) {
+                displaySystime();
+                tick++;
+                if (tick % 5 == 0) {
+                    displayResource();
+                }
+            }
+        });
+        timer.start();
+
+        chkLogPause.setFocusable(false);
+        btnLogPause.setFocusable(false);
+        btnLogDirOpen.setFocusable(false);
+        btnLogCopy.setFocusable(false);
+
+        //initTblListUI();
+
+        btnLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                taLog.setText(null);
+            }
+        });
+        btnLogDirOpen.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Runtime rt = Runtime.getRuntime();
+                try {
+                    rt.exec("explorer.exe logs");
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        });
+        chkLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JTextAreaOutputStream.isLoggingPause = chkLogPause.isSelected();
+            }
+        });
+        btnLogCopy.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                StringSelection stringSelection = new StringSelection(taLog.getText());
+                Clipboard clpBrd = Toolkit.getDefaultToolkit().getSystemClipboard();
+                clpBrd.setContents(stringSelection, null);
+            }
+        });
+
+        tblCtlrList.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent me) {
+                // double click
+                if (me.getClickCount() == 2) {
+                    updateControllerInfo();
+
+                }
+            }
+        });
+        btnDisconnect.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(1);
+            }
+        });
+        btnReset.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(2);
+            }
+        });
+        btnInitialize.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(3);
+            }
+        });
+        btnImage.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(4);
+            }
+        });
+    }
+
+    /**
+     * 제어기 명령 처리
+     *
+     * @param type
+     */
+    public void controlController(int type) {
+        if (selObj == null) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 선택되지 않았습니다. 목록을 더블클릭하여 제어기를 선택하세요.", "제어기 선택", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (selObj.getNetState() == NET.CLOSED) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 현재 연결이 되어 있지 않습니다.", "제어기 연결 상태", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        String message, title;
+        switch (type) {
+            case 1:
+                message = "제어기와의 연결을 종료 하시겠습니까?";
+                title = "제어기 연결 종료";
+                break;
+            case 2:
+                message = "제어기를 리셋 하시겠습니까?";
+                title = "제어기 리셋";
+                break;
+            case 3:
+                message = "제어기를 초기화 하시겠습니까?";
+                title = "제어기 초기화";
+                break;
+            case 4:
+                message = "제어기의 정지영상 정보를 요청하시겠습니까?";
+                title = "제어기 정지영상 요청";
+                break;
+            default:
+                return;
+        }
+        if (JOptionPane.showConfirmDialog(getRootPanel(), message, title, JOptionPane.YES_NO_OPTION) != 0) {
+            return;
+        }
+
+        boolean result = false;
+        switch (type) {
+            case 1:
+                result = selObj.channelClose();
+                break;
+            case 2:
+                result = selObj.reset();
+                break;
+            case 3:
+                result = selObj.initialize();
+                break;
+            case 4:
+                result = selObj.stopImage((byte) 0x01);
+                break;
+            default:
+                return;
+        }
+        if (!result) {
+            JOptionPane.showMessageDialog(getRootPanel(), "명령 전송이 실패 하였습니다.", title, JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void updateControllerInfo() {
+        int row = tblCtlrList.getSelectedRow();
+        if (row < 0) {
+            return;
+        }
+
+        txtId.setText("");
+        txtName.setText("");
+        CtlrSttsTableModel tableModel = (CtlrSttsTableModel) tblCtlrList.getModel();
+        selObj = tableModel.getControllerInfo(row);
+        if (selObj != null) {
+            txtId.setText(selObj.getVDS_CTLR_ID());
+            txtName.setText(selObj.getVDS_NM());
+        }
+    }
+
+    /**
+     * 목록 헤더 생성
+     */
+    private void initTblListUI(List<TbVdsCtlr> ctlrList) {
+
+        tblCtlrList.getTableHeader().setOpaque(false);
+        tblCtlrList.getTableHeader().setBackground(Color.LIGHT_GRAY);
+        tblCtlrList.setRowMargin(1);
+        //tblCtlrList.setGridColor(Color.LIGHT_GRAY);
+        tblCtlrList.setRowHeight(tblCtlrList.getRowHeight() + 5);
+        //tblCtlrList.setRowSelectionAllowed(true);
+        //tblCtlrList.setColumnSelectionAllowed(false);
+
+        ctlrSttsTableModel = new CtlrSttsTableModel(ctlrList);
+        tblCtlrList.setModel(ctlrSttsTableModel);
+        tblCtlrList.setBackground(Color.WHITE);
+        tblCtlrList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        //tblCtlrList.setAutoCreateRowSorter(true); // sorting
+
+        //tblCtlrList.addMouseListener(new ListMouseListener(null));
+
+        TableColumnModel getColumnModel = tblCtlrList.getColumnModel();
+        getColumnModel.getColumn(0).setPreferredWidth(30);  //  "S",
+        getColumnModel.getColumn(1).setPreferredWidth(75);  //  "번호",
+        getColumnModel.getColumn(2).setPreferredWidth(75);  //  "시설물ID",
+        getColumnModel.getColumn(3).setPreferredWidth(260); //  "명칭",
+        getColumnModel.getColumn(4).setPreferredWidth(120); //  "IP",
+        getColumnModel.getColumn(5).setPreferredWidth(55);  //  "PORT",
+        getColumnModel.getColumn(6).setPreferredWidth(70);  //  "연결상태",
+        getColumnModel.getColumn(7).setPreferredWidth(50);  //  "도어",
+        getColumnModel.getColumn(8).setPreferredWidth(50);  //  "팬",
+        getColumnModel.getColumn(9).setPreferredWidth(50);  //  "히터",
+        getColumnModel.getColumn(10).setPreferredWidth(50);  //  "온도",
+        getColumnModel.getColumn(11).setPreferredWidth(50); //  "Video",
+        getColumnModel.getColumn(12).setPreferredWidth(120);
+        getColumnModel.getColumn(13).setPreferredWidth(120);
+        getColumnModel.getColumn(0).setMaxWidth(30);
+        getColumnModel.getColumn(0).setMinWidth(30);
+        getColumnModel.getColumn(0).setResizable(false);
+        Color color = UIManager.getColor("Table.gridColor");
+        MatteBorder border = new MatteBorder(1, 1, 0, 0, color);
+        tblCtlrList.setBorder(border);
+
+        DefaultTableCellRenderer centerAlign = new DefaultTableCellRenderer();
+        centerAlign.setHorizontalAlignment(JLabel.CENTER);
+        for (int ii = 0; ii < getColumnModel.getColumnCount(); ii++) {
+            getColumnModel.getColumn(ii).setCellRenderer(cellRenderer);
+        }
+    }
+
+    public void updateCommSttsTotal() {
+        int ctlrTotal = 0;
+        int ctlrError = 0;
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrTotal++;
+                if (!"CMS0".equals(obj.getStts().getCMNC_STTS_CD())) {
+                    ctlrError++;
+                }
+            }
+        }
+        lblTotal.setText(" " + ctlrTotal + " ");
+        lblError.setText(" " + ctlrError + " ");
+    }
+
+    public void LoadControllerInfo(VdsCtlrService vdsCtlrService) {
+        this.vdsCtlrService = vdsCtlrService;
+
+        SortedMap<Integer, TbVdsCtlr> ctlrMap = new TreeMap<>();
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrMap.put(Integer.valueOf(obj.getVDS_CTLR_NMBR()), obj);
+            }
+        }
+        List<TbVdsCtlr> ctlrList = new ArrayList<TbVdsCtlr>(ctlrMap.values());
+        initTblListUI(ctlrList);
+//        for (Map.Entry<Integer, TbVdsCtlr> e : ctlrMap.entrySet()) {
+//            TbVdsCtlr obj = e.getValue();
+//            ctlrSttsTableModel.Add(obj);
+//        }
+        updateCommSttsTotal();
+    }
+
+    public void updateCtlrStts(TbVdsCtlr obj) {
+
+        //CtlrSttsTableModel ctlrSttsTableModel = (CtlrSttsTableModel)tblCtlrList.getModel();
+        for (int ii = 0; ii < ctlrSttsTableModel.getRowCount(); ii++) {
+            if (obj.getVDS_CTLR_ID().equals(ctlrSttsTableModel.getValueAt(ii, 2).toString())) {
+                int modelRow = tblCtlrList.convertRowIndexToModel(ii);
+//                //int viewColumn = tblCtlrList.getSelectedColumn();
+//                int modelColumn = tblCtlrList.convertColumnIndexToModel(4);
+//                Object cell = tblCtlrList.getValueAt(modelRow, modelColumn);
+//                log.error("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: {}", cell);
+                ctlrSttsTableModel.setValue(obj, ii, modelRow);
+                break;
+            }
+        }
+    }
+
+    {
+// GUI initializer generated by IntelliJ IDEA GUI Designer
+// >>> IMPORTANT!! <<<
+// DO NOT EDIT OR ADD ANY CODE HERE!
+        $$$setupUI$$$();
+    }
+
+    /**
+     * Method generated by IntelliJ IDEA GUI Designer
+     * >>> IMPORTANT!! <<<
+     * DO NOT edit this method OR call it in your code!
+     *
+     * @noinspection ALL
+     */
+    private void $$$setupUI$$$() {
+        rootPanel = new JPanel();
+        rootPanel.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
+        pnlCtlr = new JPanel();
+        pnlCtlr.setLayout(new GridLayoutManager(3, 1, new Insets(10, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlCtlr, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        pnlCtlrTitle = new JPanel();
+        pnlCtlrTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), -1, -1));
+        pnlCtlr.add(pnlCtlrTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label1 = new JLabel();
+        Font label1Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label1.getFont());
+        if (label1Font != null) label1.setFont(label1Font);
+        label1.setHorizontalAlignment(2);
+        label1.setHorizontalTextPosition(11);
+        label1.setIcon(new ImageIcon(getClass().getResource("/static/image/controller.png")));
+        label1.setText("제어기 정보");
+        pnlCtlrTitle.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer1 = new Spacer();
+        pnlCtlrTitle.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        final JLabel label2 = new JLabel();
+        Font label2Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label2.getFont());
+        if (label2Font != null) label2.setFont(label2Font);
+        label2.setText("제어기 전체: ");
+        pnlCtlrTitle.add(label2, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label3 = new JLabel();
+        Font label3Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label3.getFont());
+        if (label3Font != null) label3.setFont(label3Font);
+        label3.setText("통신 이상: ");
+        pnlCtlrTitle.add(label3, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblTotal = new JLabel();
+        Font lblTotalFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblTotal.getFont());
+        if (lblTotalFont != null) lblTotal.setFont(lblTotalFont);
+        lblTotal.setHorizontalAlignment(0);
+        lblTotal.setHorizontalTextPosition(0);
+        lblTotal.setText("   -");
+        pnlCtlrTitle.add(lblTotal, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblError = new JLabel();
+        Font lblErrorFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblError.getFont());
+        if (lblErrorFont != null) lblError.setFont(lblErrorFont);
+        lblError.setForeground(new Color(-65536));
+        lblError.setHorizontalAlignment(0);
+        lblError.setHorizontalTextPosition(0);
+        lblError.setText("   -");
+        pnlCtlrTitle.add(lblError, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane1 = new JScrollPane();
+        pnlCtlr.add(scrollPane1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        tblCtlrList = new JTable();
+        Font tblCtlrListFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, tblCtlrList.getFont());
+        if (tblCtlrListFont != null) tblCtlrList.setFont(tblCtlrListFont);
+        scrollPane1.setViewportView(tblCtlrList);
+        pnlControl = new JPanel();
+        pnlControl.setLayout(new GridLayoutManager(1, 8, new Insets(0, 0, 0, 2), 1, 1));
+        pnlCtlr.add(pnlControl, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        btnImage = new JButton();
+        Font btnImageFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnImage.getFont());
+        if (btnImageFont != null) btnImage.setFont(btnImageFont);
+        btnImage.setText("정지영상");
+        pnlControl.add(btnImage, new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer2 = new Spacer();
+        pnlControl.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnInitialize = new JButton();
+        Font btnInitializeFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnInitialize.getFont());
+        if (btnInitializeFont != null) btnInitialize.setFont(btnInitializeFont);
+        btnInitialize.setText("초기화");
+        pnlControl.add(btnInitialize, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnReset = new JButton();
+        Font btnResetFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnReset.getFont());
+        if (btnResetFont != null) btnReset.setFont(btnResetFont);
+        btnReset.setText("리셋");
+        pnlControl.add(btnReset, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnDisconnect = new JButton();
+        Font btnDisconnectFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnDisconnect.getFont());
+        if (btnDisconnectFont != null) btnDisconnect.setFont(btnDisconnectFont);
+        btnDisconnect.setText("연결끊기");
+        pnlControl.add(btnDisconnect, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        txtName = new JTextField();
+        txtName.setEditable(false);
+        Font txtNameFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtName.getFont());
+        if (txtNameFont != null) txtName.setFont(txtNameFont);
+        txtName.setHorizontalAlignment(2);
+        txtName.setText("제어기 명칭");
+        pnlControl.add(txtName, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(200, -1), new Dimension(200, -1), new Dimension(200, -1), 0, false));
+        txtId = new JTextField();
+        txtId.setEditable(false);
+        Font txtIdFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtId.getFont());
+        if (txtIdFont != null) txtId.setFont(txtIdFont);
+        txtId.setHorizontalAlignment(0);
+        txtId.setText("ID");
+        pnlControl.add(txtId, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), new Dimension(100, -1), new Dimension(100, -1), 0, false));
+        final JLabel label4 = new JLabel();
+        Font label4Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label4.getFont());
+        if (label4Font != null) label4.setFont(label4Font);
+        label4.setIcon(new ImageIcon(getClass().getResource("/static/image/select.png")));
+        label4.setText("선택한 제어기 ");
+        pnlControl.add(label4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        pnlLog = new JPanel();
+        pnlLog.setLayout(new GridLayoutManager(2, 1, new Insets(0, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlLog, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(-1, 300), new Dimension(-1, 300), new Dimension(-1, 300), 0, false));
+        pnlLogTitle = new JPanel();
+        pnlLogTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), 1, 1));
+        pnlLog.add(pnlLogTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label5 = new JLabel();
+        Font label5Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label5.getFont());
+        if (label5Font != null) label5.setFont(label5Font);
+        label5.setHorizontalAlignment(2);
+        label5.setIcon(new ImageIcon(getClass().getResource("/static/image/logging.png")));
+        label5.setText("시스템 로그");
+        pnlLogTitle.add(label5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer3 = new Spacer();
+        pnlLogTitle.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnLogDirOpen = new JButton();
+        Font btnLogDirOpenFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogDirOpen.getFont());
+        if (btnLogDirOpenFont != null) btnLogDirOpen.setFont(btnLogDirOpenFont);
+        btnLogDirOpen.setHorizontalTextPosition(0);
+        btnLogDirOpen.setText("로그 폴더");
+        pnlLogTitle.add(btnLogDirOpen, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogPause = new JButton();
+        Font btnLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogPause.getFont());
+        if (btnLogPauseFont != null) btnLogPause.setFont(btnLogPauseFont);
+        btnLogPause.setHorizontalTextPosition(0);
+        btnLogPause.setText("지우기");
+        pnlLogTitle.add(btnLogPause, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        chkLogPause = new JCheckBox();
+        Font chkLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, chkLogPause.getFont());
+        if (chkLogPauseFont != null) chkLogPause.setFont(chkLogPauseFont);
+        chkLogPause.setHorizontalAlignment(0);
+        chkLogPause.setHorizontalTextPosition(11);
+        chkLogPause.setText("멈춤");
+        pnlLogTitle.add(chkLogPause, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogCopy = new JButton();
+        Font btnLogCopyFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogCopy.getFont());
+        if (btnLogCopyFont != null) btnLogCopy.setFont(btnLogCopyFont);
+        btnLogCopy.setText("복사");
+        pnlLogTitle.add(btnLogCopy, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane2 = new JScrollPane();
+        Font scrollPane2Font = this.$$$getFont$$$("D2Coding", Font.PLAIN, 12, scrollPane2.getFont());
+        if (scrollPane2Font != null) scrollPane2.setFont(scrollPane2Font);
+        pnlLog.add(scrollPane2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        taLog = new JTextArea();
+        taLog.setBackground(new Color(-16777216));
+        taLog.setCaretColor(new Color(-1));
+        taLog.setEditable(false);
+        Font taLogFont = this.$$$getFont$$$("D2Coding", Font.PLAIN, 14, taLog.getFont());
+        if (taLogFont != null) taLog.setFont(taLogFont);
+        taLog.setForeground(new Color(-1));
+        taLog.setMargin(new Insets(4, 4, 4, 4));
+        taLog.setText("[10:50:08.561] [ INFO] ************************************************************************************\n[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **\n[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0\n[10:50:08.561] [ INFO] **      listenPort: 9901\n[10:50:08.561] [ INFO] **         backlog: 1024\n[10:50:08.561] [ INFO] **   acceptThreads: 16\n[10:50:08.561] [ INFO] **   workerThreads: 16\n[10:50:08.561] [ INFO] ************************************************************************************\n");
+        scrollPane2.setViewportView(taLog);
+        pnlStatusBar = new JPanel();
+        pnlStatusBar.setLayout(new GridLayoutManager(1, 7, new Insets(0, 4, 4, 4), -1, -1));
+        rootPanel.add(pnlStatusBar, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final Spacer spacer4 = new Spacer();
+        pnlStatusBar.add(spacer4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        lblSystime = new JLabel();
+        Font lblSystimeFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblSystime.getFont());
+        if (lblSystimeFont != null) lblSystime.setFont(lblSystimeFont);
+        lblSystime.setHorizontalAlignment(0);
+        lblSystime.setHorizontalTextPosition(0);
+        lblSystime.setText(" 2022-08-04 13:24:33 ");
+        pnlStatusBar.add(lblSystime, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label6 = new JLabel();
+        label6.setIcon(new ImageIcon(getClass().getResource("/static/image/on.png")));
+        label6.setText(" ");
+        pnlStatusBar.add(label6, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblCpuRate = new JLabel();
+        Font lblCpuRateFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblCpuRate.getFont());
+        if (lblCpuRateFont != null) lblCpuRate.setFont(lblCpuRateFont);
+        lblCpuRate.setHorizontalAlignment(2);
+        lblCpuRate.setHorizontalTextPosition(0);
+        lblCpuRate.setText("    ");
+        pnlStatusBar.add(lblCpuRate, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        lblMemoryUsage = new JLabel();
+        Font lblMemoryUsageFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblMemoryUsage.getFont());
+        if (lblMemoryUsageFont != null) lblMemoryUsage.setFont(lblMemoryUsageFont);
+        lblMemoryUsage.setHorizontalAlignment(2);
+        lblMemoryUsage.setHorizontalTextPosition(0);
+        lblMemoryUsage.setText("    ");
+        pnlStatusBar.add(lblMemoryUsage, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        final JLabel label7 = new JLabel();
+        Font label7Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label7.getFont());
+        if (label7Font != null) label7.setFont(label7Font);
+        label7.setHorizontalAlignment(0);
+        label7.setHorizontalTextPosition(0);
+        label7.setText("  CPU 사용율(%):");
+        pnlStatusBar.add(label7, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label8 = new JLabel();
+        Font label8Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label8.getFont());
+        if (label8Font != null) label8.setFont(label8Font);
+        label8.setHorizontalAlignment(0);
+        label8.setHorizontalTextPosition(0);
+        label8.setText("  메모리 사용율(%):");
+        pnlStatusBar.add(label8, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
+        if (currentFont == null) return null;
+        String resultName;
+        if (fontName == null) {
+            resultName = currentFont.getName();
+        } else {
+            Font testFont = new Font(fontName, Font.PLAIN, 10);
+            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
+                resultName = fontName;
+            } else {
+                resultName = currentFont.getName();
+            }
+        }
+        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
+        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
+        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
+        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    public JComponent $$$getRootComponent$$$() {
+        return rootPanel;
+    }
+
+}

+ 33 - 0
src/main/java/com/its/vds/ui/ui/CtlrSttsDetlTableCellRenderer.java

@@ -0,0 +1,33 @@
+package com.its.vds.ui.ui;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
+
+public class CtlrSttsDetlTableCellRenderer extends DefaultTableCellRenderer {
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+
+        Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        String commStts = table.getModel().getValueAt(row, 6).toString();
+        if (commStts.equals("Connect")) {
+            cell.setBackground(new Color(255, 255, 255, 255));
+            String door = table.getModel().getValueAt(row, 7).toString();
+            String fan = table.getModel().getValueAt(row, 8).toString();
+            String heater = table.getModel().getValueAt(row, 9).toString();
+            String video = table.getModel().getValueAt(row, 11).toString();
+        } else if (commStts.equals("Login")) {
+            cell.setBackground(new Color(182, 175, 97, 176));
+        } else {
+            cell.setBackground(new Color(182, 97, 97, 176));
+        }
+
+        if (column != 3 && column != 4) {
+            setHorizontalAlignment(SwingConstants.CENTER);
+        } else {
+            setHorizontalAlignment(SwingConstants.LEFT);
+        }
+
+        return cell;
+    }
+}

+ 60 - 0
src/main/java/com/its/vds/ui/ui/CtlrSttsTableCellRenderer.java

@@ -0,0 +1,60 @@
+package com.its.vds.ui.ui;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
+
+public class CtlrSttsTableCellRenderer extends DefaultTableCellRenderer {
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+
+        Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        String commStts = table.getModel().getValueAt(row, 6).toString();
+        if (commStts.equals("Connect")) {
+            cell.setBackground(new Color(255, 255, 255, 255));
+            if (column == 7) {
+                String door = table.getModel().getValueAt(row, 7).toString();
+                if (door.equals("열림")) {
+                    cell.setBackground(new Color(255, 0, 0, 176));
+                    cell.setForeground(new Color(255, 255, 255, 255));
+                }
+            }
+            if (column == 8) {
+                String fan = table.getModel().getValueAt(row, 8).toString();
+                if (fan.equals("가동")) {
+                    cell.setBackground(new Color(255, 213, 0, 250));
+                    cell.setForeground(new Color(0, 0, 0, 255));
+                }
+            }
+            if (column == 9) {
+                String heater = table.getModel().getValueAt(row, 9).toString();
+                if (heater.equals("가동")) {
+                    cell.setBackground(new Color(255, 213, 0, 250));
+                    cell.setForeground(new Color(0, 0, 0, 255));
+                }
+            }
+            if (column == 11) {
+                String video = table.getModel().getValueAt(row, 11).toString();
+                if (video.equals("이상")) {
+                    cell.setBackground(new Color(255, 213, 0, 250));
+                    cell.setForeground(new Color(0, 0, 0, 255));
+                }
+            }
+        } else if (commStts.equals("Login")) {
+            cell.setBackground(new Color(182, 175, 97, 176));
+        } else {
+            cell.setBackground(new Color(182, 97, 97, 176));
+        }
+
+        if (column != 3 && column != 4) {
+            setHorizontalAlignment(SwingConstants.CENTER);
+        } else {
+            setHorizontalAlignment(SwingConstants.LEFT);
+        }
+        if (column == 0) {
+            cell.setBackground(Color.LIGHT_GRAY);
+        }
+
+        return cell;
+    }
+}

+ 192 - 0
src/main/java/com/its/vds/ui/ui/CtlrSttsTableModel.java

@@ -0,0 +1,192 @@
+package com.its.vds.ui.ui;
+
+import com.its.vds.entity.TbVdsCtlr;
+import com.its.vds.entity.TbVdsCtlrStts;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.swing.table.AbstractTableModel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class CtlrSttsTableModel extends AbstractTableModel {
+    private static final long serialVersionUID = 1331132425472559704L;
+
+    private List<TbVdsCtlr> ctlrList = Collections.synchronizedList(new ArrayList<TbVdsCtlr>());
+    private final String[] columnNames = {
+            "#",
+            "번호",
+            "시설물ID",
+            "명칭",
+            "IP",
+            "PORT",
+            "연결상태",
+            "도어",
+            "팬",
+            "히터",
+            "온도",
+            "영상",
+            "연결 시각",
+            "연결종료 시각"
+    };
+    public static final String[] netStateStr = {
+            "Close", "Login", "Connect",
+    };
+
+    public CtlrSttsTableModel(List<TbVdsCtlr> ctlrList) {
+        this.ctlrList = ctlrList;
+
+        int indexCount = 1;
+        for (TbVdsCtlr obj : ctlrList) {
+            obj.setIndex(indexCount++);
+        }
+    }
+
+    @Override
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    @Override
+    public int getRowCount() {
+        int size = 0;
+        synchronized (this.ctlrList) {
+            size = this.ctlrList.size();
+        }
+        return size;
+    }
+
+    @Override
+    public String getColumnName(int columnIndex) {
+        if (columnIndex < columnNames.length) {
+            return columnNames[columnIndex];
+        }
+        return super.getColumnName(columnIndex);
+    }
+
+    @Override
+    public Class<?> getColumnClass(int columnIndex) {
+        if (ctlrList.isEmpty()) {
+            return Object.class;
+        }
+        return getValueAt(0, columnIndex).getClass();
+    }
+
+    public TbVdsCtlr getControllerInfo(int row) {
+        TbVdsCtlr info = this.ctlrList.get(row);
+        return info;
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        Object returnValue = null;
+        synchronized (this.ctlrList) {
+            TbVdsCtlr info = this.ctlrList.get(rowIndex);
+            if (info == null) {
+                return "";
+            }
+
+            int netState = info.getNetState();
+            TbVdsCtlrStts stts = info.getStts();
+            String door = "-";
+            String fan = "-";
+            String heater = "-";
+            String temper = "-";
+            String video = "-";
+            if ("CMS0".equals(stts.getCMNC_STTS_CD())) {
+                door = "-?-";
+                fan = "-?-";
+                heater = "-?-";
+                temper = "-?-";
+                video = "-?-";
+                if (stts.getCBOX_DOOR_STTS_CD().equals("CDS0")) {
+                    door = "닫힘";
+                } else if (stts.getCBOX_DOOR_STTS_CD().equals("CDS1")) {
+                    door = "열림";
+                }
+                if (stts.getFAN_STTS_CD().equals("PAS0")) {
+                    fan = "가동";
+                } else if (stts.getFAN_STTS_CD().equals("PAS1")) {
+                    fan = "중지";
+                }
+                if (stts.getHETR_STTS_CD().equals("HTS0")) {
+                    heater = "가동";
+                } else if (stts.getHETR_STTS_CD().equals("HTS1")) {
+                    heater = "중지";
+                }
+                if (stts.getVIDEO_INPUT().equals("VDI0")) {
+                    video = "정상";
+                } else if (stts.getHETR_STTS_CD().equals("VDI1")) {
+                    video = "이상";
+                }
+                temper = String.valueOf(stts.getCBOX_TMPR());
+            }
+            switch (columnIndex) {
+                case 0:
+                    returnValue = info.getIndex();
+                    break;
+                case 1:
+                    returnValue = info.getVDS_CTLR_NMBR();
+                    break;
+                case 2:
+                    returnValue = info.getVDS_CTLR_ID();
+                    break;
+                case 3:
+                    returnValue = info.getVDS_NM();
+                    break;
+                case 4:
+                    returnValue = info.getVDS_CTLR_IP();
+                    break;
+                case 5:
+                    returnValue = String.valueOf(info.getVDS_CTLR_PORT());
+                    break;
+                case 6:
+                    returnValue = netStateStr[netState];
+                    break;
+                case  7: returnValue = door; break;
+                case  8: returnValue = fan; break;
+                case  9: returnValue = heater; break;
+                case 10: returnValue = temper; break;
+                case 11: returnValue = video; break;
+                case 12:
+                    returnValue = info.getConnectTm();
+                    break;
+                case 13:
+                    returnValue = info.getDisConnectTm();
+                    break;
+            }
+        }
+        return returnValue;
+    }
+
+    @Override
+    public void setValueAt(Object value, int rowIndex, int columnIndex) {
+        synchronized (this.ctlrList) {
+            TbVdsCtlr obj = ctlrList.get(rowIndex);
+            if (columnIndex == 0) {
+                obj.setIndex((int) value);
+            }
+        }
+    }
+    public void setValueAt(TbVdsCtlr obj, int rowIdx, int colIdx) {
+        synchronized (this.ctlrList) {
+        }
+        fireTableCellUpdated(rowIdx, colIdx);
+        fireTableDataChanged();
+    }
+
+    public void Add(TbVdsCtlr info) {
+        int index = 0;
+        synchronized (this.ctlrList) {
+            index = this.ctlrList.size();
+            this.ctlrList.add(info);
+        }
+        fireTableRowsInserted(index, index);
+    }
+
+    public void setValue(TbVdsCtlr obj, int viewRow, int modelRow) {
+        fireTableDataChanged();
+    }
+
+}

+ 66 - 0
src/main/java/com/its/vds/ui/ui/JTextAreaOutputStream.java

@@ -0,0 +1,66 @@
+package com.its.vds.ui.ui;
+
+import javax.swing.*;
+import javax.swing.text.BadLocationException;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class JTextAreaOutputStream extends OutputStream {
+
+    private final JTextArea logArea;
+    public static boolean isLoggingPause = false;
+
+    public JTextAreaOutputStream(JTextArea logArea) {
+        if (logArea == null)
+            throw new IllegalArgumentException ("Destination is null...");
+        this.logArea = logArea;
+    }
+
+    public synchronized void logWrite(String text) {
+        Runnable  runnable = new Runnable() {
+            public void run() {
+                logArea.append(text);
+                if (logArea.getDocument().getLength() >
+                        50000) {
+                    try {
+                        logArea.getDocument().remove(0, 5000);
+                    } catch (BadLocationException e) {
+                        //log.error("Can't clean log", e);
+                    }
+                }
+                logArea.setCaretPosition(logArea.getDocument().getLength());
+            }
+        };
+        SwingUtilities.invokeLater(runnable);
+    }
+
+    @Override
+    public void write(byte[] buffer, int offset, int length) throws IOException
+    {
+        if (isLoggingPause) {
+            return;
+        }
+
+        final String text = new String(buffer, offset, length);
+        //logWrite(text);
+        SwingUtilities.invokeLater(new Runnable ()
+        {
+            @Override
+            public void run()
+            {
+                synchronized (logArea) {
+                    if (logArea.getLineCount() > 2000) {
+                        logArea.setText(null);
+                    }
+                    logArea.append(text);
+                    logArea.setCaretPosition(logArea.getDocument().getLength());
+                }
+            }
+        });
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        write (new byte [] {(byte)b}, 0, 1);
+    }
+}

+ 387 - 0
src/main/java/com/its/vds/ui/ui/MainUI.form

@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.its.vds.ui.MainUI">
+  <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="979" height="620"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="d0095" binding="pnlCtlr" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="10" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="d1b2f" binding="pnlCtlrTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="25222" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <horizontalTextPosition value="11"/>
+                  <icon value="static/image/controller.png"/>
+                  <text value="제어기 정보"/>
+                </properties>
+              </component>
+              <hspacer id="e90f6">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="c9b9" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="제어기 전체: "/>
+                </properties>
+              </component>
+              <component id="20b88" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="통신 이상: "/>
+                </properties>
+              </component>
+              <component id="baf10" class="javax.swing.JLabel" binding="lblTotal">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+              <component id="1c841" class="javax.swing.JLabel" binding="lblError">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <foreground color="-65536"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="b21be">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="a0dd1" class="javax.swing.JTable" binding="tblCtlrList">
+                <constraints/>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+          <grid id="17544" binding="pnlControl" layout-manager="GridLayoutManager" row-count="1" column-count="8" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="660a8" class="javax.swing.JButton" binding="btnImage">
+                <constraints>
+                  <grid row="0" column="7" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="정지영상"/>
+                </properties>
+              </component>
+              <hspacer id="60c19">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="3d84f" class="javax.swing.JButton" binding="btnInitialize">
+                <constraints>
+                  <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="초기화"/>
+                </properties>
+              </component>
+              <component id="7c99b" class="javax.swing.JButton" binding="btnReset">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="리셋"/>
+                </properties>
+              </component>
+              <component id="a85f9" class="javax.swing.JButton" binding="btnDisconnect">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="연결끊기"/>
+                </properties>
+              </component>
+              <component id="a6a03" class="javax.swing.JTextField" binding="txtName">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="200" height="-1"/>
+                    <preferred-size width="200" height="-1"/>
+                    <maximum-size width="200" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <text value="제어기 명칭"/>
+                </properties>
+              </component>
+              <component id="6d1e0" class="javax.swing.JTextField" binding="txtId">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="100" height="-1"/>
+                    <preferred-size width="100" height="-1"/>
+                    <maximum-size width="100" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <text value="ID"/>
+                </properties>
+              </component>
+              <component id="7eb53" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <icon value="static/image/select.png"/>
+                  <text value="선택한 제어기 "/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+        </children>
+      </grid>
+      <grid id="1a658" binding="pnlLog" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+            <minimum-size width="-1" height="300"/>
+            <preferred-size width="-1" height="300"/>
+            <maximum-size width="-1" height="300"/>
+          </grid>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="dbb05" binding="pnlLogTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="9ac90" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <icon value="static/image/logging.png"/>
+                  <text value="시스템 로그"/>
+                </properties>
+              </component>
+              <hspacer id="656fd">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="df2a0" class="javax.swing.JButton" binding="btnLogDirOpen">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="로그 폴더"/>
+                </properties>
+              </component>
+              <component id="69a98" class="javax.swing.JButton" binding="btnLogPause">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="지우기"/>
+                </properties>
+              </component>
+              <component id="1e9e7" class="javax.swing.JCheckBox" binding="chkLogPause">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="11"/>
+                  <text value="멈춤"/>
+                </properties>
+              </component>
+              <component id="ba97c" class="javax.swing.JButton" binding="btnLogCopy">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="복사"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="a6866">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="D2Coding" size="12" style="0"/>
+            </properties>
+            <border type="none"/>
+            <children>
+              <component id="8ce8a" class="javax.swing.JTextArea" binding="taLog">
+                <constraints/>
+                <properties>
+                  <background color="-16777216"/>
+                  <caretColor color="-1"/>
+                  <editable value="false"/>
+                  <font name="D2Coding" size="14" style="0"/>
+                  <foreground color="-1"/>
+                  <margin top="4" left="4" bottom="4" right="4"/>
+                  <text value="[10:50:08.561] [ INFO] ************************************************************************************&#10;[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **&#10;[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0&#10;[10:50:08.561] [ INFO] **      listenPort: 9901&#10;[10:50:08.561] [ INFO] **         backlog: 1024&#10;[10:50:08.561] [ INFO] **   acceptThreads: 16&#10;[10:50:08.561] [ INFO] **   workerThreads: 16&#10;[10:50:08.561] [ INFO] ************************************************************************************&#10;"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+        </children>
+      </grid>
+      <grid id="e0774" binding="pnlStatusBar" layout-manager="GridLayoutManager" row-count="1" column-count="7" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="4" right="4"/>
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <hspacer id="653ec">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+          </hspacer>
+          <component id="20f9" class="javax.swing.JLabel" binding="lblSystime">
+            <constraints>
+              <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value=" 2022-08-04 13:24:33 "/>
+            </properties>
+          </component>
+          <component id="a516b" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <icon value="static/image/on.png"/>
+              <text value=" "/>
+            </properties>
+          </component>
+          <component id="94189" class="javax.swing.JLabel" binding="lblCpuRate">
+            <constraints>
+              <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="19dbe" class="javax.swing.JLabel" binding="lblMemoryUsage">
+            <constraints>
+              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="f6d5e" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  CPU 사용율(%):"/>
+            </properties>
+          </component>
+          <component id="d8ff5" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  메모리 사용율(%):"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>

+ 624 - 0
src/main/java/com/its/vds/ui/ui/MainUI.java

@@ -0,0 +1,624 @@
+package com.its.vds.ui.ui;
+
+import com.intellij.uiDesigner.core.GridConstraints;
+import com.intellij.uiDesigner.core.GridLayoutManager;
+import com.intellij.uiDesigner.core.Spacer;
+import com.its.app.utils.SysUtils;
+import com.its.vds.domain.NET;
+import com.its.vds.entity.TbVdsCtlr;
+import com.its.vds.global.AppRepository;
+import com.its.vds.service.VdsCtlrService;
+import com.sun.management.OperatingSystemMXBean;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.Timer;
+import javax.swing.*;
+import javax.swing.border.MatteBorder;
+import javax.swing.plaf.FontUIResource;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
+import javax.swing.text.StyleContext;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.*;
+
+@Slf4j
+@Getter
+public class MainUI {
+    private static MainUI _instance = null;
+    private VdsCtlrService vdsCtlrService = null;
+    OperatingSystemMXBean osBean = null;
+    private Timer timer;
+    private Long tick = Long.valueOf(0);
+    private TbVdsCtlr selObj = null;
+
+    private CtlrSttsTableModel ctlrSttsTableModel;
+    private TableCellRenderer cellRenderer = new CtlrSttsTableCellRenderer();
+
+    private JPanel rootPanel;
+    private JPanel pnlCtlr;
+    private JPanel pnlLog;
+    private JPanel pnlLogTitle;
+    private JPanel pnlCtlrTitle;
+    private JButton btnLogDirOpen;
+    private JButton btnLogPause;
+    private JCheckBox chkLogPause;
+    private JLabel lblSystime;
+    private JPanel pnlStatusBar;
+    private JTable tblCtlrList;
+    private JTextArea taLog;
+    private JButton btnLogCopy;
+    private JLabel lblTotal;
+    private JLabel lblError;
+    private JLabel lblCpuRate;
+    private JLabel lblMemoryUsage;
+    private JPanel pnlControl;
+    private JButton btnImage;
+    private JButton btnInitialize;
+    private JButton btnReset;
+    private JButton btnDisconnect;
+    private JTextField txtName;
+    private JTextField txtId;
+
+    public static MainUI getInstance() {
+        return _instance;
+    }
+
+    public void displaySystime() {
+        lblSystime.setText(" " + SysUtils.getSysTimeStr() + "  ");
+        updateCommSttsTotal();
+    }
+
+    public void displayResource() {
+        long memoryUsage = Math.round(((double) (osBean.getTotalPhysicalMemorySize() - osBean.getFreePhysicalMemorySize())) / (double) osBean.getTotalPhysicalMemorySize() * 100.0);
+        lblMemoryUsage.setText(String.valueOf(memoryUsage));
+        double cpuLoad = osBean.getSystemCpuLoad();
+        lblCpuRate.setText(String.valueOf(Math.round(cpuLoad * 100.0)));
+    }
+
+    public MainUI() {
+        System.setProperty("awt.useSystemAAFontSettings", "false"); // AntiAliasing false
+
+        if (_instance == null) {
+            _instance = this;
+        }
+        osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
+        try {
+            Font font = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/D2Coding.ttc"));
+            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+            ge.registerFont(font);
+        } catch (FontFormatException e) {
+        } catch (IOException e) {
+        }
+
+        //taLog.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
+        Font d2font = new Font("D2Coding", Font.PLAIN, 14);
+        if (d2font != null) {
+            taLog.setFont(d2font);
+        }
+
+//        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+//        String fontNames[] = ge.getAvailableFontFamilyNames();
+//        for (int ii = 0; ii < fontNames.length; ii++) {
+//            log.error("GraphicsEnvironment Fonts: {}", fontNames[ii]);
+//        }
+//        final Font fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+//        for (Font font : fonts) {
+//            log.error("FONTS: {}", font);
+//        }
+
+        displaySystime();
+        displayResource();
+        timer = new Timer(1000, new ActionListener() {
+            public void actionPerformed(ActionEvent evt) {
+                displaySystime();
+                tick++;
+                if (tick % 5 == 0) {
+                    displayResource();
+                }
+            }
+        });
+        timer.start();
+
+        chkLogPause.setFocusable(false);
+        btnLogPause.setFocusable(false);
+        btnLogDirOpen.setFocusable(false);
+        btnLogCopy.setFocusable(false);
+
+        //initTblListUI();
+
+        btnLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                taLog.setText(null);
+            }
+        });
+        btnLogDirOpen.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Runtime rt = Runtime.getRuntime();
+                try {
+                    rt.exec("explorer.exe logs");
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        });
+        chkLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JTextAreaOutputStream.isLoggingPause = chkLogPause.isSelected();
+            }
+        });
+        btnLogCopy.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                StringSelection stringSelection = new StringSelection(taLog.getText());
+                Clipboard clpBrd = Toolkit.getDefaultToolkit().getSystemClipboard();
+                clpBrd.setContents(stringSelection, null);
+            }
+        });
+
+        tblCtlrList.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent me) {
+                // double click
+                if (me.getClickCount() == 2) {
+                    updateControllerInfo();
+
+                }
+            }
+        });
+        btnDisconnect.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(1);
+            }
+        });
+        btnReset.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(2);
+            }
+        });
+        btnInitialize.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(3);
+            }
+        });
+        btnImage.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(4);
+            }
+        });
+    }
+
+    /**
+     * 제어기 명령 처리
+     *
+     * @param type
+     */
+    public void controlController(int type) {
+        if (selObj == null) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 선택되지 않았습니다. 목록을 더블클릭하여 제어기를 선택하세요.", "제어기 선택", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (selObj.getNetState() == NET.CLOSED) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 현재 연결이 되어 있지 않습니다.", "제어기 연결 상태", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        String message, title;
+        switch (type) {
+            case 1:
+                message = "제어기와의 연결을 종료 하시겠습니까?";
+                title = "제어기 연결 종료";
+                break;
+            case 2:
+                message = "제어기를 리셋 하시겠습니까?";
+                title = "제어기 리셋";
+                break;
+            case 3:
+                message = "제어기를 초기화 하시겠습니까?";
+                title = "제어기 초기화";
+                break;
+            case 4:
+                message = "제어기의 정지영상 정보를 요청하시겠습니까?";
+                title = "제어기 정지영상 요청";
+                break;
+            default:
+                return;
+        }
+        if (JOptionPane.showConfirmDialog(getRootPanel(), message, title, JOptionPane.YES_NO_OPTION) != 0) {
+            return;
+        }
+
+        boolean result = false;
+        switch (type) {
+            case 1:
+                result = selObj.channelClose();
+                break;
+            case 2:
+                result = selObj.reset();
+                break;
+            case 3:
+                result = selObj.initialize();
+                break;
+            case 4:
+                result = selObj.stopImage((byte) 0x01);
+                break;
+            default:
+                return;
+        }
+        if (!result) {
+            JOptionPane.showMessageDialog(getRootPanel(), "명령 전송이 실패 하였습니다.", title, JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void updateControllerInfo() {
+        int row = tblCtlrList.getSelectedRow();
+        if (row < 0) {
+            return;
+        }
+
+        txtId.setText("");
+        txtName.setText("");
+        CtlrSttsTableModel tableModel = (CtlrSttsTableModel) tblCtlrList.getModel();
+        selObj = tableModel.getControllerInfo(row);
+        if (selObj != null) {
+            txtId.setText(selObj.getVDS_CTLR_ID());
+            txtName.setText(selObj.getVDS_NM());
+        }
+    }
+
+    /**
+     * 목록 헤더 생성
+     */
+    private void initTblListUI(List<TbVdsCtlr> ctlrList) {
+
+        tblCtlrList.getTableHeader().setOpaque(false);
+        tblCtlrList.getTableHeader().setBackground(Color.LIGHT_GRAY);
+        tblCtlrList.setRowMargin(1);
+        //tblCtlrList.setGridColor(Color.LIGHT_GRAY);
+        tblCtlrList.setRowHeight(tblCtlrList.getRowHeight() + 5);
+        //tblCtlrList.setRowSelectionAllowed(true);
+        //tblCtlrList.setColumnSelectionAllowed(false);
+
+        ctlrSttsTableModel = new CtlrSttsTableModel(ctlrList);
+        tblCtlrList.setModel(ctlrSttsTableModel);
+        tblCtlrList.setBackground(Color.WHITE);
+        tblCtlrList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        //tblCtlrList.setAutoCreateRowSorter(true); // sorting
+
+        //tblCtlrList.addMouseListener(new ListMouseListener(null));
+
+        TableColumnModel getColumnModel = tblCtlrList.getColumnModel();
+        getColumnModel.getColumn(0).setPreferredWidth(30);  //  "S",
+        getColumnModel.getColumn(1).setPreferredWidth(75);  //  "번호",
+        getColumnModel.getColumn(2).setPreferredWidth(75);  //  "시설물ID",
+        getColumnModel.getColumn(3).setPreferredWidth(260); //  "명칭",
+        getColumnModel.getColumn(4).setPreferredWidth(120); //  "IP",
+        getColumnModel.getColumn(5).setPreferredWidth(55);  //  "PORT",
+        getColumnModel.getColumn(6).setPreferredWidth(70);  //  "연결상태",
+        getColumnModel.getColumn(7).setPreferredWidth(50);  //  "도어",
+        getColumnModel.getColumn(8).setPreferredWidth(50);  //  "팬",
+        getColumnModel.getColumn(9).setPreferredWidth(50);  //  "히터",
+        getColumnModel.getColumn(10).setPreferredWidth(50);  //  "온도",
+        getColumnModel.getColumn(11).setPreferredWidth(50); //  "Video",
+        getColumnModel.getColumn(12).setPreferredWidth(120);
+        getColumnModel.getColumn(13).setPreferredWidth(120);
+        getColumnModel.getColumn(0).setMaxWidth(30);
+        getColumnModel.getColumn(0).setMinWidth(30);
+        getColumnModel.getColumn(0).setResizable(false);
+        Color color = UIManager.getColor("Table.gridColor");
+        MatteBorder border = new MatteBorder(1, 1, 0, 0, color);
+        tblCtlrList.setBorder(border);
+
+        DefaultTableCellRenderer centerAlign = new DefaultTableCellRenderer();
+        centerAlign.setHorizontalAlignment(JLabel.CENTER);
+        for (int ii = 0; ii < getColumnModel.getColumnCount(); ii++) {
+            getColumnModel.getColumn(ii).setCellRenderer(cellRenderer);
+        }
+    }
+
+    public void updateCommSttsTotal() {
+        int ctlrTotal = 0;
+        int ctlrError = 0;
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrTotal++;
+                if (!"CMS0".equals(obj.getStts().getCMNC_STTS_CD())) {
+                    ctlrError++;
+                }
+            }
+        }
+        lblTotal.setText(" " + ctlrTotal + " ");
+        lblError.setText(" " + ctlrError + " ");
+    }
+
+    public void LoadControllerInfo(VdsCtlrService vdsCtlrService) {
+        this.vdsCtlrService = vdsCtlrService;
+
+        SortedMap<Integer, TbVdsCtlr> ctlrMap = new TreeMap<>();
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrMap.put(Integer.valueOf(obj.getVDS_CTLR_NMBR()), obj);
+            }
+        }
+        List<TbVdsCtlr> ctlrList = new ArrayList<TbVdsCtlr>(ctlrMap.values());
+        initTblListUI(ctlrList);
+//        for (Map.Entry<Integer, TbVdsCtlr> e : ctlrMap.entrySet()) {
+//            TbVdsCtlr obj = e.getValue();
+//            ctlrSttsTableModel.Add(obj);
+//        }
+        updateCommSttsTotal();
+    }
+
+    public void updateCtlrStts(TbVdsCtlr obj) {
+
+        //CtlrSttsTableModel ctlrSttsTableModel = (CtlrSttsTableModel)tblCtlrList.getModel();
+        for (int ii = 0; ii < ctlrSttsTableModel.getRowCount(); ii++) {
+            if (obj.getVDS_CTLR_ID().equals(ctlrSttsTableModel.getValueAt(ii, 2).toString())) {
+                int modelRow = tblCtlrList.convertRowIndexToModel(ii);
+//                //int viewColumn = tblCtlrList.getSelectedColumn();
+//                int modelColumn = tblCtlrList.convertColumnIndexToModel(4);
+//                Object cell = tblCtlrList.getValueAt(modelRow, modelColumn);
+//                log.error("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: {}", cell);
+                ctlrSttsTableModel.setValue(obj, ii, modelRow);
+                break;
+            }
+        }
+    }
+
+    {
+// GUI initializer generated by IntelliJ IDEA GUI Designer
+// >>> IMPORTANT!! <<<
+// DO NOT EDIT OR ADD ANY CODE HERE!
+        $$$setupUI$$$();
+    }
+
+    /**
+     * Method generated by IntelliJ IDEA GUI Designer
+     * >>> IMPORTANT!! <<<
+     * DO NOT edit this method OR call it in your code!
+     *
+     * @noinspection ALL
+     */
+    private void $$$setupUI$$$() {
+        rootPanel = new JPanel();
+        rootPanel.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
+        pnlCtlr = new JPanel();
+        pnlCtlr.setLayout(new GridLayoutManager(3, 1, new Insets(10, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlCtlr, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        pnlCtlrTitle = new JPanel();
+        pnlCtlrTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), -1, -1));
+        pnlCtlr.add(pnlCtlrTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label1 = new JLabel();
+        Font label1Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label1.getFont());
+        if (label1Font != null) label1.setFont(label1Font);
+        label1.setHorizontalAlignment(2);
+        label1.setHorizontalTextPosition(11);
+        label1.setIcon(new ImageIcon(getClass().getResource("/static/image/controller.png")));
+        label1.setText("제어기 정보");
+        pnlCtlrTitle.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer1 = new Spacer();
+        pnlCtlrTitle.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        final JLabel label2 = new JLabel();
+        Font label2Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label2.getFont());
+        if (label2Font != null) label2.setFont(label2Font);
+        label2.setText("제어기 전체: ");
+        pnlCtlrTitle.add(label2, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label3 = new JLabel();
+        Font label3Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label3.getFont());
+        if (label3Font != null) label3.setFont(label3Font);
+        label3.setText("통신 이상: ");
+        pnlCtlrTitle.add(label3, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblTotal = new JLabel();
+        Font lblTotalFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblTotal.getFont());
+        if (lblTotalFont != null) lblTotal.setFont(lblTotalFont);
+        lblTotal.setHorizontalAlignment(0);
+        lblTotal.setHorizontalTextPosition(0);
+        lblTotal.setText("   -");
+        pnlCtlrTitle.add(lblTotal, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblError = new JLabel();
+        Font lblErrorFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblError.getFont());
+        if (lblErrorFont != null) lblError.setFont(lblErrorFont);
+        lblError.setForeground(new Color(-65536));
+        lblError.setHorizontalAlignment(0);
+        lblError.setHorizontalTextPosition(0);
+        lblError.setText("   -");
+        pnlCtlrTitle.add(lblError, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane1 = new JScrollPane();
+        pnlCtlr.add(scrollPane1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        tblCtlrList = new JTable();
+        Font tblCtlrListFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, tblCtlrList.getFont());
+        if (tblCtlrListFont != null) tblCtlrList.setFont(tblCtlrListFont);
+        scrollPane1.setViewportView(tblCtlrList);
+        pnlControl = new JPanel();
+        pnlControl.setLayout(new GridLayoutManager(1, 8, new Insets(0, 0, 0, 2), 1, 1));
+        pnlCtlr.add(pnlControl, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        btnImage = new JButton();
+        Font btnImageFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnImage.getFont());
+        if (btnImageFont != null) btnImage.setFont(btnImageFont);
+        btnImage.setText("정지영상");
+        pnlControl.add(btnImage, new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer2 = new Spacer();
+        pnlControl.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnInitialize = new JButton();
+        Font btnInitializeFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnInitialize.getFont());
+        if (btnInitializeFont != null) btnInitialize.setFont(btnInitializeFont);
+        btnInitialize.setText("초기화");
+        pnlControl.add(btnInitialize, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnReset = new JButton();
+        Font btnResetFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnReset.getFont());
+        if (btnResetFont != null) btnReset.setFont(btnResetFont);
+        btnReset.setText("리셋");
+        pnlControl.add(btnReset, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnDisconnect = new JButton();
+        Font btnDisconnectFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnDisconnect.getFont());
+        if (btnDisconnectFont != null) btnDisconnect.setFont(btnDisconnectFont);
+        btnDisconnect.setText("연결끊기");
+        pnlControl.add(btnDisconnect, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        txtName = new JTextField();
+        txtName.setEditable(false);
+        Font txtNameFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtName.getFont());
+        if (txtNameFont != null) txtName.setFont(txtNameFont);
+        txtName.setHorizontalAlignment(2);
+        txtName.setText("제어기 명칭");
+        pnlControl.add(txtName, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(200, -1), new Dimension(200, -1), new Dimension(200, -1), 0, false));
+        txtId = new JTextField();
+        txtId.setEditable(false);
+        Font txtIdFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtId.getFont());
+        if (txtIdFont != null) txtId.setFont(txtIdFont);
+        txtId.setHorizontalAlignment(0);
+        txtId.setText("ID");
+        pnlControl.add(txtId, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), new Dimension(100, -1), new Dimension(100, -1), 0, false));
+        final JLabel label4 = new JLabel();
+        Font label4Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label4.getFont());
+        if (label4Font != null) label4.setFont(label4Font);
+        label4.setIcon(new ImageIcon(getClass().getResource("/static/image/select.png")));
+        label4.setText("선택한 제어기 ");
+        pnlControl.add(label4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        pnlLog = new JPanel();
+        pnlLog.setLayout(new GridLayoutManager(2, 1, new Insets(0, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlLog, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(-1, 300), new Dimension(-1, 300), new Dimension(-1, 300), 0, false));
+        pnlLogTitle = new JPanel();
+        pnlLogTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), 1, 1));
+        pnlLog.add(pnlLogTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label5 = new JLabel();
+        Font label5Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label5.getFont());
+        if (label5Font != null) label5.setFont(label5Font);
+        label5.setHorizontalAlignment(2);
+        label5.setIcon(new ImageIcon(getClass().getResource("/static/image/logging.png")));
+        label5.setText("시스템 로그");
+        pnlLogTitle.add(label5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer3 = new Spacer();
+        pnlLogTitle.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnLogDirOpen = new JButton();
+        Font btnLogDirOpenFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogDirOpen.getFont());
+        if (btnLogDirOpenFont != null) btnLogDirOpen.setFont(btnLogDirOpenFont);
+        btnLogDirOpen.setHorizontalTextPosition(0);
+        btnLogDirOpen.setText("로그 폴더");
+        pnlLogTitle.add(btnLogDirOpen, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogPause = new JButton();
+        Font btnLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogPause.getFont());
+        if (btnLogPauseFont != null) btnLogPause.setFont(btnLogPauseFont);
+        btnLogPause.setHorizontalTextPosition(0);
+        btnLogPause.setText("지우기");
+        pnlLogTitle.add(btnLogPause, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        chkLogPause = new JCheckBox();
+        Font chkLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, chkLogPause.getFont());
+        if (chkLogPauseFont != null) chkLogPause.setFont(chkLogPauseFont);
+        chkLogPause.setHorizontalAlignment(0);
+        chkLogPause.setHorizontalTextPosition(11);
+        chkLogPause.setText("멈춤");
+        pnlLogTitle.add(chkLogPause, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogCopy = new JButton();
+        Font btnLogCopyFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogCopy.getFont());
+        if (btnLogCopyFont != null) btnLogCopy.setFont(btnLogCopyFont);
+        btnLogCopy.setText("복사");
+        pnlLogTitle.add(btnLogCopy, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane2 = new JScrollPane();
+        Font scrollPane2Font = this.$$$getFont$$$("D2Coding", Font.PLAIN, 12, scrollPane2.getFont());
+        if (scrollPane2Font != null) scrollPane2.setFont(scrollPane2Font);
+        pnlLog.add(scrollPane2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        taLog = new JTextArea();
+        taLog.setBackground(new Color(-16777216));
+        taLog.setCaretColor(new Color(-1));
+        taLog.setEditable(false);
+        Font taLogFont = this.$$$getFont$$$("D2Coding", Font.PLAIN, 14, taLog.getFont());
+        if (taLogFont != null) taLog.setFont(taLogFont);
+        taLog.setForeground(new Color(-1));
+        taLog.setMargin(new Insets(4, 4, 4, 4));
+        taLog.setText("[10:50:08.561] [ INFO] ************************************************************************************\n[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **\n[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0\n[10:50:08.561] [ INFO] **      listenPort: 9901\n[10:50:08.561] [ INFO] **         backlog: 1024\n[10:50:08.561] [ INFO] **   acceptThreads: 16\n[10:50:08.561] [ INFO] **   workerThreads: 16\n[10:50:08.561] [ INFO] ************************************************************************************\n");
+        scrollPane2.setViewportView(taLog);
+        pnlStatusBar = new JPanel();
+        pnlStatusBar.setLayout(new GridLayoutManager(1, 7, new Insets(0, 4, 4, 4), -1, -1));
+        rootPanel.add(pnlStatusBar, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final Spacer spacer4 = new Spacer();
+        pnlStatusBar.add(spacer4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        lblSystime = new JLabel();
+        Font lblSystimeFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblSystime.getFont());
+        if (lblSystimeFont != null) lblSystime.setFont(lblSystimeFont);
+        lblSystime.setHorizontalAlignment(0);
+        lblSystime.setHorizontalTextPosition(0);
+        lblSystime.setText(" 2022-08-04 13:24:33 ");
+        pnlStatusBar.add(lblSystime, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label6 = new JLabel();
+        label6.setIcon(new ImageIcon(getClass().getResource("/static/image/on.png")));
+        label6.setText(" ");
+        pnlStatusBar.add(label6, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblCpuRate = new JLabel();
+        Font lblCpuRateFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblCpuRate.getFont());
+        if (lblCpuRateFont != null) lblCpuRate.setFont(lblCpuRateFont);
+        lblCpuRate.setHorizontalAlignment(2);
+        lblCpuRate.setHorizontalTextPosition(0);
+        lblCpuRate.setText("    ");
+        pnlStatusBar.add(lblCpuRate, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        lblMemoryUsage = new JLabel();
+        Font lblMemoryUsageFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblMemoryUsage.getFont());
+        if (lblMemoryUsageFont != null) lblMemoryUsage.setFont(lblMemoryUsageFont);
+        lblMemoryUsage.setHorizontalAlignment(2);
+        lblMemoryUsage.setHorizontalTextPosition(0);
+        lblMemoryUsage.setText("    ");
+        pnlStatusBar.add(lblMemoryUsage, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        final JLabel label7 = new JLabel();
+        Font label7Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label7.getFont());
+        if (label7Font != null) label7.setFont(label7Font);
+        label7.setHorizontalAlignment(0);
+        label7.setHorizontalTextPosition(0);
+        label7.setText("  CPU 사용율(%):");
+        pnlStatusBar.add(label7, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label8 = new JLabel();
+        Font label8Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label8.getFont());
+        if (label8Font != null) label8.setFont(label8Font);
+        label8.setHorizontalAlignment(0);
+        label8.setHorizontalTextPosition(0);
+        label8.setText("  메모리 사용율(%):");
+        pnlStatusBar.add(label8, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
+        if (currentFont == null) return null;
+        String resultName;
+        if (fontName == null) {
+            resultName = currentFont.getName();
+        } else {
+            Font testFont = new Font(fontName, Font.PLAIN, 10);
+            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
+                resultName = fontName;
+            } else {
+                resultName = currentFont.getName();
+            }
+        }
+        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
+        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
+        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
+        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    public JComponent $$$getRootComponent$$$() {
+        return rootPanel;
+    }
+
+}

+ 93 - 0
src/main/java/com/its/vds/ui/ui/MonitoringTask.java

@@ -0,0 +1,93 @@
+package com.its.vds.ui.ui;
+
+import javax.swing.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class MonitoringTask {
+	
+	private static final int TASK_LENGTH = 1000;
+	private AtomicBoolean isStarted =  new AtomicBoolean(false);
+	private AtomicBoolean isRunning = new AtomicBoolean(false);
+	private AtomicBoolean isDone = new AtomicBoolean(false);
+	private int lengthOfTask;
+	private int current = 0;	
+	private String statMessage;
+
+	public MonitoringTask() {
+		lengthOfTask = TASK_LENGTH;
+	}
+
+	public void go() {
+		isRunning.set(true);
+		if (!isStarted.get()) {
+			isDone.set(false);
+			isStarted.set(true);
+			statMessage = null;
+			current = 0;
+			final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
+				@Override
+				protected Void doInBackground() throws Exception {
+					// Fake a long task, making a random amount of progress every second.
+					while (!isDone.get()) {
+						if (isRunning.get()) {
+							try {
+								Thread.sleep(1000); // sleep for a second
+								current += Math.random() * 100; // make some progress
+								if (current >= lengthOfTask) {
+									onDown();
+									current = lengthOfTask;
+								}
+								statMessage = "Completed " + current + " out of " + lengthOfTask + ".";
+							} catch (InterruptedException e) {
+								e.printStackTrace();
+							}
+						}
+					}
+					return null;
+				}
+			};
+			worker.execute();
+		}
+	}
+
+	public void pause() {
+		this.isRunning.set(false);
+	}
+
+	/**
+	 * Called from SwingTimerDemo to find out how much work needs to be done.
+	 */
+	public int getLengthOfTask() {
+		return lengthOfTask;
+	}
+
+	/**
+	 * Called from SwingTimerDemo to find out how much has been done.
+	 */
+	public int getCurrent() {
+		return current;
+	}
+
+	public void onDown() {
+		isDone.set(true);
+		isStarted.set(false);
+		isRunning.set(false);
+		statMessage = null;
+	}
+
+	/**
+	 * Called from SwingTimerDemo to find out if the task has completed.
+	 */
+	public boolean isDone() {
+		return isDone.get();
+	}
+
+	/**
+	 * Returns the most recent status message, or null if there is no current
+	 * status message.
+	 */
+	public String getMessage() {
+		return statMessage;
+	}
+
+}

+ 387 - 0
src/main/java/com/its/vds/ui/ui/SubUI.form

@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.its.vds.ui.SubUI">
+  <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="979" height="620"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="d0095" binding="pnlCtlr" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="10" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="d1b2f" binding="pnlCtlrTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="25222" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <horizontalTextPosition value="11"/>
+                  <icon value="static/image/controller.png"/>
+                  <text value="제어기 정보"/>
+                </properties>
+              </component>
+              <hspacer id="e90f6">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="c9b9" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="제어기 전체: "/>
+                </properties>
+              </component>
+              <component id="20b88" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="통신 이상: "/>
+                </properties>
+              </component>
+              <component id="baf10" class="javax.swing.JLabel" binding="lblTotal">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+              <component id="1c841" class="javax.swing.JLabel" binding="lblError">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="1"/>
+                  <foreground color="-65536"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="   -"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="b21be">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="a0dd1" class="javax.swing.JTable" binding="tblCtlrList">
+                <constraints/>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+          <grid id="17544" binding="pnlControl" layout-manager="GridLayoutManager" row-count="1" column-count="8" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="660a8" class="javax.swing.JButton" binding="btnImage">
+                <constraints>
+                  <grid row="0" column="7" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="정지영상"/>
+                </properties>
+              </component>
+              <hspacer id="60c19">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="3d84f" class="javax.swing.JButton" binding="btnInitialize">
+                <constraints>
+                  <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="초기화"/>
+                </properties>
+              </component>
+              <component id="7c99b" class="javax.swing.JButton" binding="btnReset">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="리셋"/>
+                </properties>
+              </component>
+              <component id="a85f9" class="javax.swing.JButton" binding="btnDisconnect">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="연결끊기"/>
+                </properties>
+              </component>
+              <component id="a6a03" class="javax.swing.JTextField" binding="txtName">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="200" height="-1"/>
+                    <preferred-size width="200" height="-1"/>
+                    <maximum-size width="200" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <text value="제어기 명칭"/>
+                </properties>
+              </component>
+              <component id="6d1e0" class="javax.swing.JTextField" binding="txtId">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                    <minimum-size width="100" height="-1"/>
+                    <preferred-size width="100" height="-1"/>
+                    <maximum-size width="100" height="-1"/>
+                  </grid>
+                </constraints>
+                <properties>
+                  <editable value="false"/>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <text value="ID"/>
+                </properties>
+              </component>
+              <component id="7eb53" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <icon value="static/image/select.png"/>
+                  <text value="선택한 제어기 "/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+        </children>
+      </grid>
+      <grid id="1a658" binding="pnlLog" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="0" right="4"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+            <minimum-size width="-1" height="300"/>
+            <preferred-size width="-1" height="300"/>
+            <maximum-size width="-1" height="300"/>
+          </grid>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="dbb05" binding="pnlLogTitle" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="1" vgap="1">
+            <margin top="0" left="0" bottom="0" right="2"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="9ac90" class="javax.swing.JLabel">
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="2"/>
+                  <icon value="static/image/logging.png"/>
+                  <text value="시스템 로그"/>
+                </properties>
+              </component>
+              <hspacer id="656fd">
+                <constraints>
+                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </hspacer>
+              <component id="df2a0" class="javax.swing.JButton" binding="btnLogDirOpen">
+                <constraints>
+                  <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="로그 폴더"/>
+                </properties>
+              </component>
+              <component id="69a98" class="javax.swing.JButton" binding="btnLogPause">
+                <constraints>
+                  <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalTextPosition value="0"/>
+                  <text value="지우기"/>
+                </properties>
+              </component>
+              <component id="1e9e7" class="javax.swing.JCheckBox" binding="chkLogPause">
+                <constraints>
+                  <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <horizontalAlignment value="0"/>
+                  <horizontalTextPosition value="11"/>
+                  <text value="멈춤"/>
+                </properties>
+              </component>
+              <component id="ba97c" class="javax.swing.JButton" binding="btnLogCopy">
+                <constraints>
+                  <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <font name="Malgun Gothic" size="12" style="0"/>
+                  <text value="복사"/>
+                </properties>
+              </component>
+            </children>
+          </grid>
+          <scrollpane id="a6866">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="D2Coding" size="12" style="0"/>
+            </properties>
+            <border type="none"/>
+            <children>
+              <component id="8ce8a" class="javax.swing.JTextArea" binding="taLog">
+                <constraints/>
+                <properties>
+                  <background color="-16777216"/>
+                  <caretColor color="-1"/>
+                  <editable value="false"/>
+                  <font name="D2Coding" size="14" style="0"/>
+                  <foreground color="-1"/>
+                  <margin top="4" left="4" bottom="4" right="4"/>
+                  <text value="[10:50:08.561] [ INFO] ************************************************************************************&#10;[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **&#10;[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0&#10;[10:50:08.561] [ INFO] **      listenPort: 9901&#10;[10:50:08.561] [ INFO] **         backlog: 1024&#10;[10:50:08.561] [ INFO] **   acceptThreads: 16&#10;[10:50:08.561] [ INFO] **   workerThreads: 16&#10;[10:50:08.561] [ INFO] ************************************************************************************&#10;"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+        </children>
+      </grid>
+      <grid id="e0774" binding="pnlStatusBar" layout-manager="GridLayoutManager" row-count="1" column-count="7" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="4" bottom="4" right="4"/>
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <hspacer id="653ec">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+          </hspacer>
+          <component id="20f9" class="javax.swing.JLabel" binding="lblSystime">
+            <constraints>
+              <grid row="0" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value=" 2022-08-04 13:24:33 "/>
+            </properties>
+          </component>
+          <component id="a516b" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <icon value="static/image/on.png"/>
+              <text value=" "/>
+            </properties>
+          </component>
+          <component id="94189" class="javax.swing.JLabel" binding="lblCpuRate">
+            <constraints>
+              <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="19dbe" class="javax.swing.JLabel" binding="lblMemoryUsage">
+            <constraints>
+              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
+                <minimum-size width="40" height="-1"/>
+                <preferred-size width="40" height="-1"/>
+                <maximum-size width="40" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="1"/>
+              <horizontalAlignment value="2"/>
+              <horizontalTextPosition value="0"/>
+              <text value="    "/>
+            </properties>
+          </component>
+          <component id="f6d5e" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  CPU 사용율(%):"/>
+            </properties>
+          </component>
+          <component id="d8ff5" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <font name="Malgun Gothic" size="12" style="0"/>
+              <horizontalAlignment value="0"/>
+              <horizontalTextPosition value="0"/>
+              <text value="  메모리 사용율(%):"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>

+ 624 - 0
src/main/java/com/its/vds/ui/ui/SubUI.java

@@ -0,0 +1,624 @@
+package com.its.vds.ui.ui;
+
+import com.intellij.uiDesigner.core.GridConstraints;
+import com.intellij.uiDesigner.core.GridLayoutManager;
+import com.intellij.uiDesigner.core.Spacer;
+import com.its.app.utils.SysUtils;
+import com.its.vds.domain.NET;
+import com.its.vds.entity.TbVdsCtlr;
+import com.its.vds.global.AppRepository;
+import com.its.vds.service.VdsCtlrService;
+import com.sun.management.OperatingSystemMXBean;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.Timer;
+import javax.swing.*;
+import javax.swing.border.MatteBorder;
+import javax.swing.plaf.FontUIResource;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
+import javax.swing.text.StyleContext;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.*;
+
+@Slf4j
+@Getter
+public class SubUI {
+    private static SubUI _instance = null;
+    private VdsCtlrService vdsCtlrService = null;
+    OperatingSystemMXBean osBean = null;
+    private Timer timer;
+    private Long tick = Long.valueOf(0);
+    private TbVdsCtlr selObj = null;
+
+    private CtlrSttsTableModel ctlrSttsTableModel;
+    private TableCellRenderer cellRenderer = new CtlrSttsTableCellRenderer();
+
+    private JPanel rootPanel;
+    private JPanel pnlCtlr;
+    private JPanel pnlLog;
+    private JPanel pnlLogTitle;
+    private JPanel pnlCtlrTitle;
+    private JButton btnLogDirOpen;
+    private JButton btnLogPause;
+    private JCheckBox chkLogPause;
+    private JLabel lblSystime;
+    private JPanel pnlStatusBar;
+    private JTable tblCtlrList;
+    private JTextArea taLog;
+    private JButton btnLogCopy;
+    private JLabel lblTotal;
+    private JLabel lblError;
+    private JLabel lblCpuRate;
+    private JLabel lblMemoryUsage;
+    private JPanel pnlControl;
+    private JButton btnImage;
+    private JButton btnInitialize;
+    private JButton btnReset;
+    private JButton btnDisconnect;
+    private JTextField txtName;
+    private JTextField txtId;
+
+    public static SubUI getInstance() {
+        return _instance;
+    }
+
+    public void displaySystime() {
+        lblSystime.setText(" " + SysUtils.getSysTimeStr() + "  ");
+        updateCommSttsTotal();
+    }
+
+    public void displayResource() {
+        long memoryUsage = Math.round(((double) (osBean.getTotalPhysicalMemorySize() - osBean.getFreePhysicalMemorySize())) / (double) osBean.getTotalPhysicalMemorySize() * 100.0);
+        lblMemoryUsage.setText(String.valueOf(memoryUsage));
+        double cpuLoad = osBean.getSystemCpuLoad();
+        lblCpuRate.setText(String.valueOf(Math.round(cpuLoad * 100.0)));
+    }
+
+    public SubUI() {
+        System.setProperty("awt.useSystemAAFontSettings", "false"); // AntiAliasing false
+
+        if (_instance == null) {
+            _instance = this;
+        }
+        osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
+        try {
+            Font font = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/D2Coding.ttc"));
+            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+            ge.registerFont(font);
+        } catch (FontFormatException e) {
+        } catch (IOException e) {
+        }
+
+        //taLog.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
+        Font d2font = new Font("D2Coding", Font.PLAIN, 14);
+        if (d2font != null) {
+            taLog.setFont(d2font);
+        }
+
+//        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+//        String fontNames[] = ge.getAvailableFontFamilyNames();
+//        for (int ii = 0; ii < fontNames.length; ii++) {
+//            log.error("GraphicsEnvironment Fonts: {}", fontNames[ii]);
+//        }
+//        final Font fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+//        for (Font font : fonts) {
+//            log.error("FONTS: {}", font);
+//        }
+
+        displaySystime();
+        displayResource();
+        timer = new Timer(1000, new ActionListener() {
+            public void actionPerformed(ActionEvent evt) {
+                displaySystime();
+                tick++;
+                if (tick % 5 == 0) {
+                    displayResource();
+                }
+            }
+        });
+        timer.start();
+
+        chkLogPause.setFocusable(false);
+        btnLogPause.setFocusable(false);
+        btnLogDirOpen.setFocusable(false);
+        btnLogCopy.setFocusable(false);
+
+        //initTblListUI();
+
+        btnLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                taLog.setText(null);
+            }
+        });
+        btnLogDirOpen.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Runtime rt = Runtime.getRuntime();
+                try {
+                    rt.exec("explorer.exe logs");
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        });
+        chkLogPause.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JTextAreaOutputStream.isLoggingPause = chkLogPause.isSelected();
+            }
+        });
+        btnLogCopy.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                StringSelection stringSelection = new StringSelection(taLog.getText());
+                Clipboard clpBrd = Toolkit.getDefaultToolkit().getSystemClipboard();
+                clpBrd.setContents(stringSelection, null);
+            }
+        });
+
+        tblCtlrList.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent me) {
+                // double click
+                if (me.getClickCount() == 2) {
+                    updateControllerInfo();
+
+                }
+            }
+        });
+        btnDisconnect.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(1);
+            }
+        });
+        btnReset.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(2);
+            }
+        });
+        btnInitialize.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(3);
+            }
+        });
+        btnImage.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controlController(4);
+            }
+        });
+    }
+
+    /**
+     * 제어기 명령 처리
+     *
+     * @param type
+     */
+    public void controlController(int type) {
+        if (selObj == null) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 선택되지 않았습니다. 목록을 더블클릭하여 제어기를 선택하세요.", "제어기 선택", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (selObj.getNetState() == NET.CLOSED) {
+            JOptionPane.showMessageDialog(getRootPanel(), "제어기가 현재 연결이 되어 있지 않습니다.", "제어기 연결 상태", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        String message, title;
+        switch (type) {
+            case 1:
+                message = "제어기와의 연결을 종료 하시겠습니까?";
+                title = "제어기 연결 종료";
+                break;
+            case 2:
+                message = "제어기를 리셋 하시겠습니까?";
+                title = "제어기 리셋";
+                break;
+            case 3:
+                message = "제어기를 초기화 하시겠습니까?";
+                title = "제어기 초기화";
+                break;
+            case 4:
+                message = "제어기의 정지영상 정보를 요청하시겠습니까?";
+                title = "제어기 정지영상 요청";
+                break;
+            default:
+                return;
+        }
+        if (JOptionPane.showConfirmDialog(getRootPanel(), message, title, JOptionPane.YES_NO_OPTION) != 0) {
+            return;
+        }
+
+        boolean result = false;
+        switch (type) {
+            case 1:
+                result = selObj.channelClose();
+                break;
+            case 2:
+                result = selObj.reset();
+                break;
+            case 3:
+                result = selObj.initialize();
+                break;
+            case 4:
+                result = selObj.stopImage((byte) 0x01);
+                break;
+            default:
+                return;
+        }
+        if (!result) {
+            JOptionPane.showMessageDialog(getRootPanel(), "명령 전송이 실패 하였습니다.", title, JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void updateControllerInfo() {
+        int row = tblCtlrList.getSelectedRow();
+        if (row < 0) {
+            return;
+        }
+
+        txtId.setText("");
+        txtName.setText("");
+        CtlrSttsTableModel tableModel = (CtlrSttsTableModel) tblCtlrList.getModel();
+        selObj = tableModel.getControllerInfo(row);
+        if (selObj != null) {
+            txtId.setText(selObj.getVDS_CTLR_ID());
+            txtName.setText(selObj.getVDS_NM());
+        }
+    }
+
+    /**
+     * 목록 헤더 생성
+     */
+    private void initTblListUI(List<TbVdsCtlr> ctlrList) {
+
+        tblCtlrList.getTableHeader().setOpaque(false);
+        tblCtlrList.getTableHeader().setBackground(Color.LIGHT_GRAY);
+        tblCtlrList.setRowMargin(1);
+        //tblCtlrList.setGridColor(Color.LIGHT_GRAY);
+        tblCtlrList.setRowHeight(tblCtlrList.getRowHeight() + 5);
+        //tblCtlrList.setRowSelectionAllowed(true);
+        //tblCtlrList.setColumnSelectionAllowed(false);
+
+        ctlrSttsTableModel = new CtlrSttsTableModel(ctlrList);
+        tblCtlrList.setModel(ctlrSttsTableModel);
+        tblCtlrList.setBackground(Color.WHITE);
+        tblCtlrList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        //tblCtlrList.setAutoCreateRowSorter(true); // sorting
+
+        //tblCtlrList.addMouseListener(new ListMouseListener(null));
+
+        TableColumnModel getColumnModel = tblCtlrList.getColumnModel();
+        getColumnModel.getColumn(0).setPreferredWidth(30);  //  "S",
+        getColumnModel.getColumn(1).setPreferredWidth(75);  //  "번호",
+        getColumnModel.getColumn(2).setPreferredWidth(75);  //  "시설물ID",
+        getColumnModel.getColumn(3).setPreferredWidth(260); //  "명칭",
+        getColumnModel.getColumn(4).setPreferredWidth(120); //  "IP",
+        getColumnModel.getColumn(5).setPreferredWidth(55);  //  "PORT",
+        getColumnModel.getColumn(6).setPreferredWidth(70);  //  "연결상태",
+        getColumnModel.getColumn(7).setPreferredWidth(50);  //  "도어",
+        getColumnModel.getColumn(8).setPreferredWidth(50);  //  "팬",
+        getColumnModel.getColumn(9).setPreferredWidth(50);  //  "히터",
+        getColumnModel.getColumn(10).setPreferredWidth(50);  //  "온도",
+        getColumnModel.getColumn(11).setPreferredWidth(50); //  "Video",
+        getColumnModel.getColumn(12).setPreferredWidth(120);
+        getColumnModel.getColumn(13).setPreferredWidth(120);
+        getColumnModel.getColumn(0).setMaxWidth(30);
+        getColumnModel.getColumn(0).setMinWidth(30);
+        getColumnModel.getColumn(0).setResizable(false);
+        Color color = UIManager.getColor("Table.gridColor");
+        MatteBorder border = new MatteBorder(1, 1, 0, 0, color);
+        tblCtlrList.setBorder(border);
+
+        DefaultTableCellRenderer centerAlign = new DefaultTableCellRenderer();
+        centerAlign.setHorizontalAlignment(JLabel.CENTER);
+        for (int ii = 0; ii < getColumnModel.getColumnCount(); ii++) {
+            getColumnModel.getColumn(ii).setCellRenderer(cellRenderer);
+        }
+    }
+
+    public void updateCommSttsTotal() {
+        int ctlrTotal = 0;
+        int ctlrError = 0;
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrTotal++;
+                if (!"CMS0".equals(obj.getStts().getCMNC_STTS_CD())) {
+                    ctlrError++;
+                }
+            }
+        }
+        lblTotal.setText(" " + ctlrTotal + " ");
+        lblError.setText(" " + ctlrError + " ");
+    }
+
+    public void LoadControllerInfo(VdsCtlrService vdsCtlrService) {
+        this.vdsCtlrService = vdsCtlrService;
+
+        SortedMap<Integer, TbVdsCtlr> ctlrMap = new TreeMap<>();
+        for (Map.Entry<String, TbVdsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVdsCtlr obj = e.getValue();
+            if (StringUtils.equals("N", obj.getDEL_YN()) && StringUtils.equals("Y", obj.getVALD_YN())) {
+                ctlrMap.put(Integer.valueOf(obj.getVDS_CTLR_NMBR()), obj);
+            }
+        }
+        List<TbVdsCtlr> ctlrList = new ArrayList<TbVdsCtlr>(ctlrMap.values());
+        initTblListUI(ctlrList);
+//        for (Map.Entry<Integer, TbVdsCtlr> e : ctlrMap.entrySet()) {
+//            TbVdsCtlr obj = e.getValue();
+//            ctlrSttsTableModel.Add(obj);
+//        }
+        updateCommSttsTotal();
+    }
+
+    public void updateCtlrStts(TbVdsCtlr obj) {
+
+        //CtlrSttsTableModel ctlrSttsTableModel = (CtlrSttsTableModel)tblCtlrList.getModel();
+        for (int ii = 0; ii < ctlrSttsTableModel.getRowCount(); ii++) {
+            if (obj.getVDS_CTLR_ID().equals(ctlrSttsTableModel.getValueAt(ii, 2).toString())) {
+                int modelRow = tblCtlrList.convertRowIndexToModel(ii);
+//                //int viewColumn = tblCtlrList.getSelectedColumn();
+//                int modelColumn = tblCtlrList.convertColumnIndexToModel(4);
+//                Object cell = tblCtlrList.getValueAt(modelRow, modelColumn);
+//                log.error("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: {}", cell);
+                ctlrSttsTableModel.setValue(obj, ii, modelRow);
+                break;
+            }
+        }
+    }
+
+    {
+// GUI initializer generated by IntelliJ IDEA GUI Designer
+// >>> IMPORTANT!! <<<
+// DO NOT EDIT OR ADD ANY CODE HERE!
+        $$$setupUI$$$();
+    }
+
+    /**
+     * Method generated by IntelliJ IDEA GUI Designer
+     * >>> IMPORTANT!! <<<
+     * DO NOT edit this method OR call it in your code!
+     *
+     * @noinspection ALL
+     */
+    private void $$$setupUI$$$() {
+        rootPanel = new JPanel();
+        rootPanel.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
+        pnlCtlr = new JPanel();
+        pnlCtlr.setLayout(new GridLayoutManager(3, 1, new Insets(10, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlCtlr, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        pnlCtlrTitle = new JPanel();
+        pnlCtlrTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), -1, -1));
+        pnlCtlr.add(pnlCtlrTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label1 = new JLabel();
+        Font label1Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label1.getFont());
+        if (label1Font != null) label1.setFont(label1Font);
+        label1.setHorizontalAlignment(2);
+        label1.setHorizontalTextPosition(11);
+        label1.setIcon(new ImageIcon(getClass().getResource("/static/image/controller.png")));
+        label1.setText("제어기 정보");
+        pnlCtlrTitle.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer1 = new Spacer();
+        pnlCtlrTitle.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        final JLabel label2 = new JLabel();
+        Font label2Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label2.getFont());
+        if (label2Font != null) label2.setFont(label2Font);
+        label2.setText("제어기 전체: ");
+        pnlCtlrTitle.add(label2, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label3 = new JLabel();
+        Font label3Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label3.getFont());
+        if (label3Font != null) label3.setFont(label3Font);
+        label3.setText("통신 이상: ");
+        pnlCtlrTitle.add(label3, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblTotal = new JLabel();
+        Font lblTotalFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblTotal.getFont());
+        if (lblTotalFont != null) lblTotal.setFont(lblTotalFont);
+        lblTotal.setHorizontalAlignment(0);
+        lblTotal.setHorizontalTextPosition(0);
+        lblTotal.setText("   -");
+        pnlCtlrTitle.add(lblTotal, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblError = new JLabel();
+        Font lblErrorFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblError.getFont());
+        if (lblErrorFont != null) lblError.setFont(lblErrorFont);
+        lblError.setForeground(new Color(-65536));
+        lblError.setHorizontalAlignment(0);
+        lblError.setHorizontalTextPosition(0);
+        lblError.setText("   -");
+        pnlCtlrTitle.add(lblError, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane1 = new JScrollPane();
+        pnlCtlr.add(scrollPane1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        tblCtlrList = new JTable();
+        Font tblCtlrListFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, tblCtlrList.getFont());
+        if (tblCtlrListFont != null) tblCtlrList.setFont(tblCtlrListFont);
+        scrollPane1.setViewportView(tblCtlrList);
+        pnlControl = new JPanel();
+        pnlControl.setLayout(new GridLayoutManager(1, 8, new Insets(0, 0, 0, 2), 1, 1));
+        pnlCtlr.add(pnlControl, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        btnImage = new JButton();
+        Font btnImageFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnImage.getFont());
+        if (btnImageFont != null) btnImage.setFont(btnImageFont);
+        btnImage.setText("정지영상");
+        pnlControl.add(btnImage, new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer2 = new Spacer();
+        pnlControl.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnInitialize = new JButton();
+        Font btnInitializeFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnInitialize.getFont());
+        if (btnInitializeFont != null) btnInitialize.setFont(btnInitializeFont);
+        btnInitialize.setText("초기화");
+        pnlControl.add(btnInitialize, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnReset = new JButton();
+        Font btnResetFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnReset.getFont());
+        if (btnResetFont != null) btnReset.setFont(btnResetFont);
+        btnReset.setText("리셋");
+        pnlControl.add(btnReset, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnDisconnect = new JButton();
+        Font btnDisconnectFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnDisconnect.getFont());
+        if (btnDisconnectFont != null) btnDisconnect.setFont(btnDisconnectFont);
+        btnDisconnect.setText("연결끊기");
+        pnlControl.add(btnDisconnect, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        txtName = new JTextField();
+        txtName.setEditable(false);
+        Font txtNameFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtName.getFont());
+        if (txtNameFont != null) txtName.setFont(txtNameFont);
+        txtName.setHorizontalAlignment(2);
+        txtName.setText("제어기 명칭");
+        pnlControl.add(txtName, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(200, -1), new Dimension(200, -1), new Dimension(200, -1), 0, false));
+        txtId = new JTextField();
+        txtId.setEditable(false);
+        Font txtIdFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, txtId.getFont());
+        if (txtIdFont != null) txtId.setFont(txtIdFont);
+        txtId.setHorizontalAlignment(0);
+        txtId.setText("ID");
+        pnlControl.add(txtId, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), new Dimension(100, -1), new Dimension(100, -1), 0, false));
+        final JLabel label4 = new JLabel();
+        Font label4Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label4.getFont());
+        if (label4Font != null) label4.setFont(label4Font);
+        label4.setIcon(new ImageIcon(getClass().getResource("/static/image/select.png")));
+        label4.setText("선택한 제어기 ");
+        pnlControl.add(label4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        pnlLog = new JPanel();
+        pnlLog.setLayout(new GridLayoutManager(2, 1, new Insets(0, 4, 0, 4), -1, -1));
+        rootPanel.add(pnlLog, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(-1, 300), new Dimension(-1, 300), new Dimension(-1, 300), 0, false));
+        pnlLogTitle = new JPanel();
+        pnlLogTitle.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 2), 1, 1));
+        pnlLog.add(pnlLogTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final JLabel label5 = new JLabel();
+        Font label5Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label5.getFont());
+        if (label5Font != null) label5.setFont(label5Font);
+        label5.setHorizontalAlignment(2);
+        label5.setIcon(new ImageIcon(getClass().getResource("/static/image/logging.png")));
+        label5.setText("시스템 로그");
+        pnlLogTitle.add(label5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final Spacer spacer3 = new Spacer();
+        pnlLogTitle.add(spacer3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        btnLogDirOpen = new JButton();
+        Font btnLogDirOpenFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogDirOpen.getFont());
+        if (btnLogDirOpenFont != null) btnLogDirOpen.setFont(btnLogDirOpenFont);
+        btnLogDirOpen.setHorizontalTextPosition(0);
+        btnLogDirOpen.setText("로그 폴더");
+        pnlLogTitle.add(btnLogDirOpen, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogPause = new JButton();
+        Font btnLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogPause.getFont());
+        if (btnLogPauseFont != null) btnLogPause.setFont(btnLogPauseFont);
+        btnLogPause.setHorizontalTextPosition(0);
+        btnLogPause.setText("지우기");
+        pnlLogTitle.add(btnLogPause, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        chkLogPause = new JCheckBox();
+        Font chkLogPauseFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, chkLogPause.getFont());
+        if (chkLogPauseFont != null) chkLogPause.setFont(chkLogPauseFont);
+        chkLogPause.setHorizontalAlignment(0);
+        chkLogPause.setHorizontalTextPosition(11);
+        chkLogPause.setText("멈춤");
+        pnlLogTitle.add(chkLogPause, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        btnLogCopy = new JButton();
+        Font btnLogCopyFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnLogCopy.getFont());
+        if (btnLogCopyFont != null) btnLogCopy.setFont(btnLogCopyFont);
+        btnLogCopy.setText("복사");
+        pnlLogTitle.add(btnLogCopy, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane2 = new JScrollPane();
+        Font scrollPane2Font = this.$$$getFont$$$("D2Coding", Font.PLAIN, 12, scrollPane2.getFont());
+        if (scrollPane2Font != null) scrollPane2.setFont(scrollPane2Font);
+        pnlLog.add(scrollPane2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
+        taLog = new JTextArea();
+        taLog.setBackground(new Color(-16777216));
+        taLog.setCaretColor(new Color(-1));
+        taLog.setEditable(false);
+        Font taLogFont = this.$$$getFont$$$("D2Coding", Font.PLAIN, 14, taLog.getFont());
+        if (taLogFont != null) taLog.setFont(taLogFont);
+        taLog.setForeground(new Color(-1));
+        taLog.setMargin(new Insets(4, 4, 4, 4));
+        taLog.setText("[10:50:08.561] [ INFO] ************************************************************************************\n[10:50:08.561] [ INFO] **                   Center Communication Server Information                      **\n[10:50:08.561] [ INFO] **     bindAddress: 0.0.0.0\n[10:50:08.561] [ INFO] **      listenPort: 9901\n[10:50:08.561] [ INFO] **         backlog: 1024\n[10:50:08.561] [ INFO] **   acceptThreads: 16\n[10:50:08.561] [ INFO] **   workerThreads: 16\n[10:50:08.561] [ INFO] ************************************************************************************\n");
+        scrollPane2.setViewportView(taLog);
+        pnlStatusBar = new JPanel();
+        pnlStatusBar.setLayout(new GridLayoutManager(1, 7, new Insets(0, 4, 4, 4), -1, -1));
+        rootPanel.add(pnlStatusBar, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        final Spacer spacer4 = new Spacer();
+        pnlStatusBar.add(spacer4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+        lblSystime = new JLabel();
+        Font lblSystimeFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblSystime.getFont());
+        if (lblSystimeFont != null) lblSystime.setFont(lblSystimeFont);
+        lblSystime.setHorizontalAlignment(0);
+        lblSystime.setHorizontalTextPosition(0);
+        lblSystime.setText(" 2022-08-04 13:24:33 ");
+        pnlStatusBar.add(lblSystime, new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label6 = new JLabel();
+        label6.setIcon(new ImageIcon(getClass().getResource("/static/image/on.png")));
+        label6.setText(" ");
+        pnlStatusBar.add(label6, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        lblCpuRate = new JLabel();
+        Font lblCpuRateFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblCpuRate.getFont());
+        if (lblCpuRateFont != null) lblCpuRate.setFont(lblCpuRateFont);
+        lblCpuRate.setHorizontalAlignment(2);
+        lblCpuRate.setHorizontalTextPosition(0);
+        lblCpuRate.setText("    ");
+        pnlStatusBar.add(lblCpuRate, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        lblMemoryUsage = new JLabel();
+        Font lblMemoryUsageFont = this.$$$getFont$$$("Malgun Gothic", Font.BOLD, 12, lblMemoryUsage.getFont());
+        if (lblMemoryUsageFont != null) lblMemoryUsage.setFont(lblMemoryUsageFont);
+        lblMemoryUsage.setHorizontalAlignment(2);
+        lblMemoryUsage.setHorizontalTextPosition(0);
+        lblMemoryUsage.setText("    ");
+        pnlStatusBar.add(lblMemoryUsage, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(40, -1), new Dimension(40, -1), new Dimension(40, -1), 0, false));
+        final JLabel label7 = new JLabel();
+        Font label7Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label7.getFont());
+        if (label7Font != null) label7.setFont(label7Font);
+        label7.setHorizontalAlignment(0);
+        label7.setHorizontalTextPosition(0);
+        label7.setText("  CPU 사용율(%):");
+        pnlStatusBar.add(label7, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JLabel label8 = new JLabel();
+        Font label8Font = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, label8.getFont());
+        if (label8Font != null) label8.setFont(label8Font);
+        label8.setHorizontalAlignment(0);
+        label8.setHorizontalTextPosition(0);
+        label8.setText("  메모리 사용율(%):");
+        pnlStatusBar.add(label8, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
+        if (currentFont == null) return null;
+        String resultName;
+        if (fontName == null) {
+            resultName = currentFont.getName();
+        } else {
+            Font testFont = new Font(fontName, Font.PLAIN, 10);
+            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
+                resultName = fontName;
+            } else {
+                resultName = currentFont.getName();
+            }
+        }
+        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
+        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
+        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
+        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
+    }
+
+    /**
+     * @noinspection ALL
+     */
+    public JComponent $$$getRootComponent$$$() {
+        return rootPanel;
+    }
+
+}

+ 27 - 6
src/main/java/com/its/vds/xnettcp/vds/process/Job_Image.java

@@ -1,6 +1,8 @@
 package com.its.vds.xnettcp.vds.process;
 
+import com.its.app.utils.ItsUtils;
 import com.its.app.utils.NettyUtils;
+import com.its.app.utils.SysUtils;
 import com.its.vds.entity.TbVdsCtlr;
 import com.its.vds.xnettcp.center.protocol.CenterResProtocol;
 import com.its.vds.xnettcp.vds.protocol.VdsProtocol;
@@ -67,20 +69,39 @@ public class Job_Image implements JobProtocol {
 			ByteBuffer buffer2 = CenterResProtocol.getImageHeader2(obj.getImageSize());
 			ByteBuffer buffer3 = obj.getImageData();
 			channels.forEach(channel -> {
-				if (sendCenterResponse(channel, buffer1, obj)) {
-					log.info("[{}]. Job_Image: send image data to center[HEAD1]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer1.array().length, NettyUtils.getRemoteAddress(channel));
+				if (channel == obj.getChannel()) {
+					// 서버 화면에서 요청한 거임
+				}
+				else {
+					if (sendCenterResponse(channel, buffer1, obj)) {
+						log.info("[{}]. Job_Image: send image data to center[HEAD1]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer1.array().length, NettyUtils.getRemoteAddress(channel));
+					}
 				}
 			});
 			channels.forEach(channel -> {
-				if (sendCenterResponse(channel, buffer2, obj)) {
-					log.info("[{}]. Job_Image: send image data to center[HEAD2]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer2.array().length, NettyUtils.getRemoteAddress(channel));
+				if (channel == obj.getChannel()) {
+					// 서버 화면에서 요청한 거임
+				}
+				else {
+					if (sendCenterResponse(channel, buffer2, obj)) {
+						log.info("[{}]. Job_Image: send image data to center[HEAD2]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer2.array().length, NettyUtils.getRemoteAddress(channel));
+					}
 				}
 			});
 			channels.forEach(channel -> {
-				if (sendCenterResponse(channel, buffer3, obj)) {
-					log.info("[{}]. Job_Image: send image data to center[DATA]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer3.array().length, NettyUtils.getRemoteAddress(channel));
+				if (channel == obj.getChannel()) {
+					// 서버 화면에서 요청한 거임
+					log.error("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+				}
+				else {
+					if (sendCenterResponse(channel, buffer3, obj)) {
+						log.info("[{}]. Job_Image: send image data to center[DATA]: {} Bytes. {}", obj.getVDS_CTLR_ID(), buffer3.array().length, NettyUtils.getRemoteAddress(channel));
+					}
 				}
 			});
+			obj.setStopImageResponse();
+			String saveDir = ItsUtils.createUserDir("/images/");
+			ItsUtils.saveByteArrayToFile(saveDir + obj.getVDS_CTLR_ID() + "_" + SysUtils.getSysTime() + ".jpg", buffer3.array());
 		}
 		else {
 			VdsReqImage reqImage = new VdsReqImage((short)obj.getGROUP_NO(), (short)obj.getVDS_CTLR_LOCAL_NO());

BIN
src/main/resources/static/image/select.png