참고사항 : 개발자가 되는 법(http://wiki.kldp.org/wiki.php/HowToBeAProgrammer#s-2.1.4)

2.1.4 로그를 이용해서 디버그 하는 방법 

  로그 기록(logging)이란 정보를 제공하는 일련의 기록인 로그(log)를 생성하도록 시스템을 작성하는 활동을 말한다. 프린트 줄 넣기(printlining)는 간단한, 보통은 일시적인, 로그를 생성하기만 한다. 완전한 초보자들은 프로그래밍에 대해 아는 것에 한계가 있기 때문에 로그를 이해하고 사용해야 한다. 시스템 설계자들은 시스템의 복잡성 때문에 로그를 이해하고 사용해야 한다. 로그가 제공하는 정보의 양은, 이상적으로는 프로그램이 실행되는 중에도, 설정 가능해야 한다. 일반적으로 로그 기록은 다음의 이점이 있다.
  • 로그는 재현하기 힘든 (예를 들어, 개발 완료된 환경에서는 발생하지만 테스트 환경에서는 재현할 수 없는) 버그에 대한 유용한 정보를 제공할 수 있다.
  • 로그는, 예를 들어, 구문(statement)들 사이에 걸리는 시간과 같이, 성능에 관한 통계와 정보를 제공할 수 있다.
  • 설정이 가능할 때, 로그는 예기치 못한 특정 문제들을 디버그하기 위해, 그 문제들을 처리하도록 코드를 수정하여 다시 적용하지(redeploy) 않아도, 일반적인 정보를 갈무리할 수 있게 한다. 

  로그에 남기는 정보의 양항상 정보성과 간결성 사이의 타협으로 결정된다. 정보를 너무 많이 남긴다면 로그가 낭비적이 되고 스크롤에 가려지게(scroll blindness) 되어, 필요한 정보를 찾기 어려워질 것이다. 너무 조금 남긴다면 필요한 정보가 남지 않을 것이다. 이런 점에서, 무엇이 출력될지 설정할 수 있게 하는 것은 매우 유용하다. 일반적으로 로그에 남는 기록을 통해, 그 기록을 남긴 소스 코드의 위치, (적용 가능하다면) 문제가 되는 작업을 실행한 쓰레드, 정확한 실행 시각, 그리고 일반적으로, 어떤 변수의 값, 여유 메모리의 양, 데이터 객체의 개수 등 그 밖의 유용한 정보를 알 수 있다. 이러한 로그 생성 구문들은 소스 코드 전체에 흩어져 있는데, 특히 주요 기능이 있는 지점과 위험 부담이 있는 코드 근처에 있다. 구문마다 수준이 정해질 수 있으면 시스템의 현재 설정에 따라 그 수준에 해당하는 기록만 남기게 될 것이다. 로그 생성 구문을 설계할 때에는 어디에서 문제가 생길지 예상해서 그것을 기록으로 남길 수 있게 해야 한다. 성능을 측정할 필요성도 예상하고 있어야 한다.

영구적인 로그를 남긴다면, 로그 기록이 프린트 줄 넣기(printlining)를 대신 할 수 있을 것이고, 디버그 구문들 중에도 로그 기록 시스템에 영구적으로 추가할 것들이 있을 것이다.

로그(Logging) 과 관련된 글이 올라온 것을 보고,
급하게 내용을 찾아서 정리해본다.


  개발하는 과정에서 데이터의 처리 과정이나 발생한 오류에 대한 기록을 남기는 용도로 많이 활용하는 기능이다. 제대로 읽고 분석할 수 있는 능력을 갖춘다면, 개발실력이 한단계 향상될 것이라 믿어 의심치 않는다. 개발자가 갖춰야할 능력 중 하나는 '로그 분석' 능력!


저작자 표시
Posted by 허니몬

작업파일 : miniProject(090612)_VideoShop_RMI.zip


서버용 인터페이스 : Server.java

  • 클라이언트에서 사용하는 메소드 정의
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.rmi.*;
    import java.util.Vector;

    public interface Server extends Remote {
        // 공지사항 관련 메소드
        public void showNoticeDB() throws RemoteException;
        public Vector noticeTitle() throws RemoteException;
        public Vector noticeContent() throws RemoteException;
        public void broadcastNotice() throws RemoteException;
       
        //인기비디오 관련 메소드
        public void showFavoriteVideoDB() throws RemoteException;
        public Vector favoriteTitle() throws RemoteException;
        public Vector broadcastFavoriteContent() throws RemoteException;
       
        //신작 비디오 관련 메소드
        public void showNewVideoDB() throws RemoteException;
        public Vector newTitle() throws RemoteException;
        public Vector newContent() throws RemoteException;
        public void broadcastNewVideo() throws RemoteException; // 신작비디오(본사 등록시 실행)
       
        // 각 지점의 로그인 관리
        public void register(Client client, String name) throws RemoteException;
        public void unregister(Client client, String name) throws RemoteException;   
       
    }

 

원격객체 : ServerImpl.java

  • RMI 등록되고 실행되고 있으면, 원격접속 클라이언트들에게 관련한 작업들 처리해줌
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.rmi.Naming;
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.Statement;
    import java.util.Enumeration;
    import java.util.Vector;

    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.SingleSelectionModel;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableModel;

    public class ServerImpl extends UnicastRemoteObject implements Server, ActionListener {
        private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
        private String user = "scott";
        private String passwd = "tiger";
        private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
        private Vector ntitle = new Vector();
        private Vector ncontent = new Vector();
        private Vector newtitle = new Vector();
        private Vector newcontent = new Vector();
        private Vector ftitle = new Vector();
        private Vector fcontent = new Vector();
        private Vector ltitle = new Vector();
        private Vector lcontent = new Vector();
        private Vector clientList = new Vector();
        private JTextField ntfield, listTitleTfield, listGenreTfield;
        private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton;
        private JComboBox listcbox;
        private String who = "관리자";
       
        Connection con;
        Statement stat;
        private JTable ntable;
        private JTextField numtfield;
        private JPasswordField pw;
        private JButton login;
        private JTextField idt;
        private CardLayout card;
        private JPanel cpane;
        private JTable ltable;
       
       
        public ServerImpl() throws RemoteException  {
            database();
            makeGui();
           
           
            //창이 닫힐 경우 자원들을 종료하는 Listner
    /*        addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent x){
                   try {
                   Window w = (Window)x.getSource();
                   w.setVisible(false);
                   w.dispose();//화면에 썼던 자원을 해지하는것.
                
                     close();
                   System.exit(0); //프로세스 종료
                   }catch(Exception e){}
                  }
             });*/
        }
       
        //DB연결관련 처리
        public  void database(){
            try {
                Class.forName("oracle.jdbc.driver.OracleDriver");
                con = DriverManager.getConnection( url, user, passwd );
                stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            } catch( Exception e) {
                e.printStackTrace();
            }
        }
       
        public void makeGui() throws RemoteException{
            JFrame frame = new JFrame("Fun Video Company");
            frame.pack();
            frame.setDefaultCloseOperation(3);
            frame.setSize(800,800);
            frame.setVisible(true);       
            final JTabbedPane tab = new JTabbedPane();
            frame.add(tab);
           

            //noticePanel
            nmodel = new DefaultTableModel();
            ntable = new JTable(nmodel);
            JScrollPane nspane = new JScrollPane(ntable);
            //nmodel.setDataVector(dataVector, columnIdentifiers);
           
            ntable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ntable.getSelectedRow();
                    Vector in = (Vector)ncontent.elementAt(row);
                    numtfield.setText((String)in.elementAt(0));
                    ntfield.setText((String)in.elementAt(1));
                }
            });
            //DB 연동해주기.
            showNoticeDB();       
            JLabel numlabel = new JLabel("번호");
            numtfield = new JTextField(3);
            JLabel nlabel = new JLabel("내용");
            ntfield = new JTextField(30);
            nwrite = new JButton("작성");
            ndel = new JButton("삭제");
            nwrite.addActionListener(this);
            ndel.addActionListener(this);
           
            JPanel noticePanel = new JPanel();
            noticePanel.add(numlabel);
            noticePanel.add(numtfield);
            noticePanel.add(nlabel);
            noticePanel.add(ntfield);
            noticePanel.add(nwrite);
            noticePanel.add(ndel);
                   
            JPanel notice = new JPanel();
            notice.setLayout(new BorderLayout());
            notice.add(nspane, "Center");
            notice.add(noticePanel, "South");
           

           
            //newVideo Panel
            newmodel = new DefaultTableModel();
            JTable newtable = new JTable(newmodel);
            JScrollPane newspane = new JScrollPane(newtable);
            //newmodel.setDataVector(dataVector, columnIdentifiers);
            showNewVideoDB();
           
            JPanel newVideo = new JPanel();
            newVideo.setLayout(new BorderLayout());
            newVideo.add(newspane, "Center");
           
           
            //favoriteVideo Panel
            fmodel = new DefaultTableModel();
            JTable ftable = new JTable(fmodel);
            JScrollPane fspane = new JScrollPane(ftable);
            //fmodel.setDataVector(dataVector, columnIdentifiers);
           
            JPanel favoritePanel = new JPanel();
            favoritePanel.setLayout(new BorderLayout());
            fbutton = new JButton("집계");
            fbutton.addActionListener(this);
            favoritePanel.add(fbutton, "East");
           
            JPanel favoriteVideo = new JPanel();
            favoriteVideo.setLayout(new BorderLayout());
            favoriteVideo.add(fspane, "Center");
            favoriteVideo.add(favoritePanel, "South");
           
           
            //listVideo Panel
            lmodel = new DefaultTableModel();
            ltable = new JTable(lmodel);
            JScrollPane lspane = new JScrollPane(ltable);
            //lmodel.setDataVector(dataVector, columnIdentifiers);
            showListVideoDB("servervideo");
            ltable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ltable.getSelectedRow();
                    Vector in = (Vector)lcontent.elementAt(row);
                    listTitleTfield.setText((String)in.elementAt(1));
                    listGenreTfield.setText((String)in.elementAt(2));   
                }
            });
           
            JPanel listPanel = new JPanel();
            String data[] = {"본사","양재", "강남", "논현"};
            listcbox = new JComboBox(data);
            listcbox.addActionListener(this);
            JLabel listTitle = new JLabel("제목");
            listTitleTfield = new JTextField(30);
            JLabel listGenre = new JLabel("장르");
            listGenreTfield = new JTextField(10);
            listInsert = new JButton("추가");
            listInsert.addActionListener(this);
            listDelete = new JButton("삭제");
            listDelete.addActionListener(this);
           
            listPanel.add(listcbox);
            listPanel.add(listTitle);
            listPanel.add(listTitleTfield);
            listPanel.add(listGenre);
            listPanel.add(listGenreTfield);
            listPanel.add(listInsert);
            listPanel.add(listDelete);
           
            JPanel listVideo = new JPanel();
            listVideo.setLayout(new BorderLayout());
            listVideo.add(lspane, "Center");
            listVideo.add(listPanel, "South");
           
                   
            //tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
            tab.add(notice,"공지사항");
            tab.add(newVideo,"신작비디오");
            tab.add(favoriteVideo, "인기비디오");
            tab.add(listVideo, "비디오목록");
         
              
             tab.getModel().addChangeListener(
                new ChangeListener() {
                   public void stateChanged(ChangeEvent e) {
                   SingleSelectionModel model = (SingleSelectionModel) e.getSource();
                   if(model.getSelectedIndex() == tab.getTabCount()-1) {
                   }
                   }
                }
             );
            
        }
       
        // ------------------------------------------------------------------------------------------- //   
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
       
        public void showNoticeDB() throws RemoteException {
            ncontent.clear();
            ntitle = noticeTitle();
            ncontent = noticeContent();
            nmodel.setDataVector(ncontent, ntitle);
        }
       
        public Vector noticeTitle() throws RemoteException {
            String sql = "SELECT num as 번호, content as 내용, writer as 작성자, TO_CHAR(indate, 'YYYY / MM / DD') as 작성일 FROM notice ORDER BY num desc";
            try {
                ntitle.clear();
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                ntitle.clear();
                for ( int i = 1 ; i <= count ; i++){
                    String t = rsmd.getColumnName(i);
                    ntitle.add(t);               
                }
           
            } catch( Exception e) {
                e.printStackTrace();
            }
            return ntitle;
        }
       
        public Vector noticeContent() throws RemoteException {
            String sql = "SELECT num, content, writer, TO_CHAR(indate, 'YYYY / MM / DD') FROM notice ORDER BY num desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                ncontent.clear();
                while( rs.next() ){
                    Vector in = new Vector();
                    in.add(rs.getString(1));
                    in.add(rs.getString(2));
                    in.add(rs.getString(3));
                    in.add(rs.getString(4));
                    ncontent.add(in);
                }
                rs.close();
            } catch( Exception e) {
                e.printStackTrace();
            }   
            return ncontent;
        }
       
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
        // ------------------------------------------------------------------------------------------- //
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
       
        public void showNewVideoDB(){
            newtitle.clear();
            newcontent.clear();
            newtitle = newTitle();
            newcontent = newContent();
            newmodel.setDataVector(newcontent, newtitle);
        }

        public Vector newTitle(){
            newtitle.clear();
            String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                newtitle.clear();
                for ( int i = 1; i <= count; i++ ){
                    String t = rsmd.getColumnName(i);
                    newtitle.add(t);
                }   
            } catch ( Exception e ){
                e.printStackTrace();
            }
           
            return newtitle;
        }
       
        //신작 비디오의 기준은 입고일 14일 이내의 작품들 : 기간 설정변수 int limitday
        public Vector newContent(){
            newcontent.clear();
            int limitday = 14;
            String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo WHERE indate > sysdate - " + limitday + "ORDER BY indate desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                while( rs.next() ){
                    Vector in = new Vector();
                    for ( int i = 1; i <= count; i++){
                        in.add(rs.getString(i));
                    }
                    newcontent.add(in);
                }
            } catch ( Exception e ) {
                e.printStackTrace();
            }       
            return newcontent;
        }
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
        // ------------------------------------------------------------------------------------------- //
       

       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //
        // ------------------- 집계버튼 클릭시 접속된 모든 클라이언트에 영향을 끼침 ------------------ //
        public void showFavoriteVideoDB() throws RemoteException  {
            ftitle.clear();
            ftitle = favoriteTitle();
            fcontent = favoriteContent();
            fmodel.setDataVector(fcontent, ftitle);
        }
       
        public Vector favoriteTitle()throws RemoteException{
            ftitle.clear();
            ftitle.add("번호");
            ftitle.add("제목");
            ftitle.add("장르");
            ftitle.add("지점");
            return ftitle;
        }

        public Vector favoriteContent() throws RemoteException{
            System.out.println("집계 자료를 요청받았음");
            fcontent = broadcastFavoriteContent();
            System.out.println("집계자료 반납, 가져!!");
            return fcontent;
        }
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
        // ------------------------------------------------------------------------------------------- //
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        public void showListVideoDB(String shop){
            lcontent.clear();
            ltitle.clear();
            ltitle = listTitle(shop);
            lcontent = listContent(shop);
            lmodel.setDataVector(lcontent, ltitle);
        }
       
        public Vector listTitle(String shop){
            if ( shop == "servervideo"){
               
                String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    ltitle.clear();
                    for ( int  i = 1 ; i <= count ; i++ ){
                        String t = rsmd.getColumnName(i);
                        ltitle.add(t);
                    }
                } catch ( Exception e ){
                    e.printStackTrace();
                }
               
            } else {
               
                String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    for ( int  i = 1 ; i <= count ; i++ ){       
                        String t = rsmd.getColumnName(i);
                        ltitle.add(t);
                    }   
                } catch ( Exception e ){
                    e.printStackTrace();
                }       
               
            }
            return ltitle;
        }
       
        public Vector listContent(String shop){
            if ( shop == "servervideo") {
                String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM " + shop + " ORDER BY indate desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            } else {
                String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            }
            return lcontent;
        }
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        // ------------------------------------------------------------------------------------------- //
       
        public void broadcastNotice() throws RemoteException{
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    c.showNoticeDB();
                }
                showNoticeDB();
            }
           
        }
        public void broadcastNewVideo() throws RemoteException{
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()){
                    Vector in = new Vector();
                    Client c = (Client)e.nextElement();
                    c.showNewVideoDB();
                }
            }
        }
       
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
        public Vector broadcastFavoriteContent() throws RemoteException{
            fcontent.clear();
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    fcontent.add(c.sendfavoriteContent());
                }                   
            }
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    c.showFavoriteVideoDB(fcontent);
                }                   
            }
            System.out.println("집계처리 완료");
            fmodel.setDataVector(fcontent, ftitle);
            return fcontent;
        }

        public synchronized void register(Client client, String name) throws RemoteException{
            clientList.add(client);
            System.out.println(name + "지점이 접속하였습니다.");
        }
       
        public synchronized void unregister(Client client, String name) throws RemoteException{
            clientList.removeElement(client);
            System.out.println(name + " 지점이 접속을 종료하였습니다.");
        }
       
        public void close(){
            try {
                stat.close();
                con.close();
            } catch ( Exception e ){
                e.printStackTrace();
            }
        }


       
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = e.getSource();
            if ( o == nwrite ){
                noticeInsert();
               
            } else if ( o == ndel ) {
                noticeDelete();
           
            }else if ( o == fbutton ){
                try {
                    //broadcastFavorite();
                    Vector v = broadcastFavoriteContent();
                    fmodel.setDataVector(v,ftitle );
                } catch (RemoteException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            } else if ( o == listcbox ){
                listShopChange();
               
            } else if ( o == listInsert ){
                insertVideo(returnShop());
            } else if ( o == listDelete ){
                deleteVideo(returnShop());
                try {
                    broadcastNewVideo();
                } catch (RemoteException e1) {
                    e1.printStackTrace();
                }
            }
           
        }

        //notice 관련 Query 처리 : 서버는 추가/삭제 자유롭게, 지점은 추가만 가능
        // 서버, 지점 공지사항 추가 가능 가능
        public void noticeInsert(){
            int num = incrementNum("notice");
            String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
            try {
                stat.executeQuery(sql);
            } catch( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            try {
                showNoticeDB();
                broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }       
        //
        }

        // 서버에서만 공지사항 삭제 가능 가능
        public void noticeDelete(){
            String num = numtfield.getText();
            String sql = "DELETE notice WHERE num ='" + num + "'";
            try {
                stat.executeUpdate(sql);
            } catch ( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            numtfield.setText("");
            try {
                showNoticeDB();
                broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }
           
        }

        //------------------------ 서버에 접속한 클라이언트들 호출하기 ---------------------//   
        //--------------   listVideo 에서 추가 버튼 눌렀을 때 발생하는 이벤트 --------------//
        public void insertVideo(String shop){
            String sql = "";
            int id = incrementNum(shop);
            String name = listTitleTfield.getText();
            String genre = listGenreTfield.getText();
            if (shop == "servervideo" ){
                sql = "INSERT INTO " + shop + " VALUES(" + id + ",'" + name + "','" + genre + "',sysdate)";
            } else {
                sql = "INSERT INTO " + shop + " VALUES(" + id +", '" + name + "','" + genre +"',0,'대여가능')";
            }
            try {
                stat.executeUpdate(sql);
                showListVideoDB(shop);
                broadcastNewVideo();
                listTitleTfield.setText("");
                listGenreTfield.setText("");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
       
        }

        //listVideo에서 삭제 버튼을 눌렀을 때 발생하는 이벤트
        public void deleteVideo(String shop){
            String sql = "";
            int id = incrementNum(shop);
            String name = listTitleTfield.getText();
            String genre = listGenreTfield.getText();
            if (shop == "servervideo" ){
                sql = "DELETE " + shop + " WHERE title = '" + name + "' AND sgroup = '" + genre +"'";
            } else {
                sql = "DELETE " + shop + " WHERE name = '" + name + "' AND genre = '" + genre + "'";
            }
            try {
                stat.executeUpdate(sql);
                showListVideoDB(shop);
                listTitleTfield.setText("");
                listGenreTfield.setText("");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }

        //listvideo listcbox 값 변경시 발생되는 이벤트.
        public void listShopChange(){
            String shop = returnShop();
            showListVideoDB(shop);
        }

        public String returnShop(){
            String shop = (String)listcbox.getSelectedItem();
            if (shop == "본사"){
                shop = "servervideo";
            } else if ( shop == "강남") {
                shop = "client1";
            } else if ( shop == "논현") {
                shop = "client2";
            } else if ( shop == "양재"){
                shop = "client3";
            }
            return shop;
        }

        //DB 등록시 최고 번호가 반환됨(조회된 것 + 1);
        public int incrementNum(String table){
            String sql = "SELECT max(id) FROM " + table;
            int num=0;
            try {
                if( table == "notice") {
                    sql = "SELECT max(num) FROM " + table;
                }
                ResultSet rs = stat.executeQuery(sql);
                rs.next();
                num = rs.getInt(1);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            return num + 1 ;
        }

        public static void main(String args[]) {
            try {
                ServerImpl s = new ServerImpl();
                Naming.rebind("rmi://61.103.103.184/video",s);
                System.out.println("Fun Video Company Server is Ready!!");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
       
    }

 

인터페이스 : Client.java

  • 서버에서 사용할 클라이언트 메소드들 호출
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.rmi.*;
    import java.util.Vector;

    public interface Client extends Remote {
        public void showNoticeDB() throws RemoteException;
        public Vector sendfavoriteContent() throws RemoteException;
        public void showFavoriteVideoDB(Vector v) throws RemoteException;
        public void showNewVideoDB() throws RemoteException;
        public void showListVideoDB(String shop) throws RemoteException;
    }

 

원격접속 클라이언트 : ClientImpl.java

  1. import java.awt.BorderLayout;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.rmi.*;
    import java.rmi.server.*;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.Statement;
    import java.util.Vector;

    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.SingleSelectionModel;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableModel;

    public class ClientImpl implements Client, ActionListener {
        private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
        private String user = "scott";
        private String passwd = "tiger";
        private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
        private Vector ntitle = new Vector();
        private Vector ncontent = new Vector();
        private Vector newtitle = new Vector();
        private Vector newcontent = new Vector();
        private Vector ftitle = new Vector();
        private Vector fcontent = new Vector();
        private Vector ltitle = new Vector();
        private Vector lcontent = new Vector();
        private JTextField ntfield, listTitleTfield, listGenreTfield;
        private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton, rent, receive;
        private JComboBox listcbox;
        private String server, selectNum, state, selectNo;
        private JTable ntable,ltable;
        private JTextField numtfield, idt;
        private JPasswordField pw;
        private JButton login;
        private JPanel cpane;
        private int rentcount;
        final String who;
        Server s;
       
        Connection con;
        Statement stat;
        private JButton retry;
       
           
        public ClientImpl(final String who, String server) throws RemoteException {
           
            try {
                UnicastRemoteObject.exportObject(this);
                s = (Server)Naming.lookup("rmi://61.103.103.184/video");
                s.register(this, who);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            this.who = who;
            this.server = server;
            database();
            makeGui();
           
           
        }
       

        //DB연결관련 처리
        public  void database(){
            try {
                Class.forName("oracle.jdbc.driver.OracleDriver");
                con = DriverManager.getConnection( url, user, passwd );
                stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            } catch( Exception e) {
                e.printStackTrace();
            }
        }
       
        public void makeGui() throws RemoteException{
            JFrame frame = new JFrame(who + "점 Video SHOP");
            frame.pack();
            //frame.setDefaultCloseOperation(3);
            frame.setSize(800,800);
            frame.setVisible(true);       
            final JTabbedPane tab = new JTabbedPane();
            frame.add(tab);
            //창이 닫힐 경우 자원들을 종료하는 Listner
            frame.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent x){
                   try {
                   Window w = (Window)x.getSource();
                   w.setVisible(false);
                   w.dispose();//화면에 썼던 자원을 해지하는것.
                   s.unregister(ClientImpl.this, who);
                     close();
                   System.exit(0); //프로세스 종료
                   }catch(Exception e){}
                  }
             });

           
            //noticePanel
            nmodel = new DefaultTableModel();
            ntable = new JTable(nmodel);
            JScrollPane nspane = new JScrollPane(ntable);
            //nmodel.setDataVector(dataVector, coflumnIdentifiers);
            //DB 연동해주기.
            ntable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ntable.getSelectedRow();
                    Vector in = (Vector)ncontent.elementAt(row);
                    numtfield.setText((String)in.elementAt(0));
                    ntfield.setText((String)in.elementAt(1));
                   
                }
            });
            showNoticeDB();
            JLabel numlabel = new JLabel("번호");
            numtfield = new JTextField(3);
            JLabel nlabel = new JLabel("내용");
            ntfield = new JTextField(30);
            nwrite = new JButton("작성");
            nwrite.addActionListener(this);
           
            JPanel noticePanel = new JPanel();
            noticePanel.add(numlabel);
            noticePanel.add(numtfield);
            noticePanel.add(nlabel);
            noticePanel.add(ntfield);
            noticePanel.add(nwrite);
                           
            JPanel notice = new JPanel();
            notice.setLayout(new BorderLayout());
            notice.add(nspane, "Center");
            notice.add(noticePanel, "South");
           

           
            //newVideo Panel
            newmodel = new DefaultTableModel();
            JTable newtable = new JTable(newmodel);
            JScrollPane newspane = new JScrollPane(newtable);
            //newmodel.setDataVector(dataVector, columnIdentifiers);
            showNewVideoDB();
           
            JPanel newVideo = new JPanel();
            newVideo.setLayout(new BorderLayout());
            newVideo.add(newspane, "Center");
           
           
            //favoriteVideo Panel
            fmodel = new DefaultTableModel();
            JTable ftable = new JTable(fmodel);
            JScrollPane fspane = new JScrollPane(ftable);
            //fmodel.setDataVector(dataVector, columnIdentifiers);
           
            JPanel favoritePanel = new JPanel();
            favoritePanel.setLayout(new BorderLayout());
            fbutton = new JButton("집계");
            fbutton.addActionListener(this);
            favoritePanel.add(fbutton, "East");
           
            JPanel favoriteVideo = new JPanel();
            favoriteVideo.setLayout(new BorderLayout());
            favoriteVideo.add(fspane, "Center");
            favoriteVideo.add(favoritePanel, "South");
           
           
            //listVideo Panel
            lmodel = new DefaultTableModel();
            ltable = new JTable(lmodel);
            JScrollPane lspane = new JScrollPane(ltable);
            //lmodel.setDataVector(dataVector, columnIdentifiers);
            showListVideoDB(server);
            ltable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ltable.getSelectedRow();
                    Vector in = (Vector)lcontent.elementAt(row);
                    selectNum = (String)in.elementAt(0);
                    rentcount  = Integer.parseInt((String)in.elementAt(3));
                    state = (String)in.elementAt(4);
                }
            });
           
            JPanel listPanel = new JPanel();
            rent = new JButton("대여");
            receive = new JButton("반납");
            retry = new JButton("다시 읽기");
            rent.addActionListener(this);
            receive.addActionListener(this);
            retry.addActionListener(this);
            listPanel.add(rent);
            listPanel.add(receive);
            listPanel.add(retry);
           
           
            JPanel listVideo = new JPanel();
            listVideo.setLayout(new BorderLayout());
            listVideo.add(lspane, "Center");
            listVideo.add(listPanel, "South");
           
                   
            //tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
            tab.add(notice,"공지사항");
            tab.add(newVideo,"신작비디오");
            tab.add(favoriteVideo, "인기비디오");
            tab.add(listVideo, "비디오목록");
         
              
             tab.getModel().addChangeListener(
                new ChangeListener() {
                   public void stateChanged(ChangeEvent e) {
                   SingleSelectionModel model = (SingleSelectionModel) e.getSource();
                   if(model.getSelectedIndex() == tab.getTabCount()-1) {
                   }
                   }
                }
             );
            
        }
       
        // ------------------------------------------------------------------------------------------- //   
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
       
        public synchronized void showNoticeDB() throws RemoteException {
            ntitle = s.noticeTitle();
            ncontent = s.noticeContent();
            nmodel.setDataVector(ncontent, ntitle);
        }

        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
        // ------------------------------------------------------------------------------------------- //
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
       
        public synchronized void showNewVideoDB() throws RemoteException{
            try {
            newcontent.clear();
            newtitle.clear();
            newtitle = s.newTitle();
            newcontent = s.newContent();
            newmodel.setDataVector(newcontent, newtitle);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //

        public void showFavoriteVideoDB(Vector v) throws RemoteException  {
            //System.out.println("집계된 자료 가져가겠음");
        ftitle.clear();
        ftitle = s.favoriteTitle();
        //    System.out.println("집계제목 수신중");
        //    fcontent = s.favoriteContent();
        //    System.out.println("집계자료 전송중");
           
            fmodel.setDataVector(v, ftitle);
        }
       
       
        public Vector sendfavoriteContent()throws RemoteException  {
            fcontent.clear();
            String sql = "SELECT id, name, genre FROM " + server + " where rentcount = (SELECT max(rentcount) FROM " + server + ")";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                rs.next();
                           
                for ( int i = 1; i <= count ; i++ ){
                    fcontent.add(rs.getString(i));           
                }
                fcontent.add(who);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return fcontent;
        }
       
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        public void showListVideoDB(String shop){
            lcontent.clear();
            ltitle.clear();
            ltitle = listTitle(shop);
            lcontent = listContent(shop);
            lmodel.setDataVector(lcontent, ltitle);
        }
       
        public Vector listTitle(String shop){
            String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    for ( int  i = 1 ; i <= count ; i++ ){
                        Vector in = new Vector();
                        String t = rsmd.getColumnName(i);
                        in.add(t);
                        ltitle.add(in);
                    }   
                } catch ( Exception e ){
                    e.printStackTrace();
                }       
            return ltitle;
        }
       
        public Vector listContent(String shop){
            String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            return lcontent;
        }
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        // ------------------------------------------------------------------------------------------- //
       
       
       
        //notice 관련 Query 처리 : 서버는 추가/삭제 가능, 지점은 추가만 가능
        public void noticeInsert(){
            int num = incrementNum("notice");
            String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
            try {
                stat.executeQuery(sql);
            } catch( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            try {
                s.broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
       
        public int incrementNum(String table){
            String sql = "SELECT max(id) FROM " + table;
            int num=0;
            try {
                if( table == "notice") {
                    sql = "SELECT max(num) FROM " + table;
                }
                ResultSet rs = stat.executeQuery(sql);
                rs.next();
                num = rs.getInt(1);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            return num + 1 ;
        }
       
        public void close(){
            try {
                stat.close();
                con.close();
            } catch ( Exception e ){
                e.printStackTrace();
            }
        }
       
       
        //listVideo에서 대여 버튼을 눌렀을 때 발생하는 이벤트
        public void rentVideo(){
            if (state.equals("대여가능")){
                String sql = "UPDATE " + server + " SET state = '대여중', rentcount = "+ (rentcount + 1) +" WHERE id = "+ selectNum;
                try {
                    stat.executeUpdate(sql);
                    showListVideoDB(server);
                } catch ( Exception e ) {
                    e.printStackTrace();
                }
            }
           
        }

        //listVideo에서 반납 버튼을 눌렀을 때 발생하는 이벤트
        public void receiveVideo(){
            if (state.equals("대여중")){
                String sql = "UPDATE " + server +" SET state = '대여가능' WHERE id = "+ selectNum;
                try {
                    stat.executeUpdate(sql);
                    showListVideoDB(server);
                } catch ( Exception e ) {
                    e.printStackTrace();
                }
            }
        }
       


       
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = e.getSource();
            if ( o == nwrite ){
                noticeInsert();
                try {
                    s.broadcastNotice();
                } catch (Exception ex){
                    ex.printStackTrace();
                }
            }else if ( o == fbutton ){
                    try {
                        s.broadcastFavoriteContent();
                    } catch (RemoteException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
            } else if ( o == rent ){
                rentVideo();
            } else if ( o == receive ){
                receiveVideo();
            } else if ( o == retry ){
                showListVideoDB(server);
            }
           
           
        }
       
        public static void main(String args[]) {
            try {
                String who = args[0];
                String server = args[1];
                ClientImpl c = new ClientImpl(who, server);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }   
    }

 

ServerImpl 실행화면

ClientImpl 실행화면

 

ServerImplFavoriteex.jpg ServerImplFavoriteUnex.jpg ServerImplList.jpg ServerImplListSelcect.jpg ServerImplNew.jpg

 

ServerImplNotice.jpg ClientImplFavorite.jpg ClientImplList.jpg ClientImplNew.jpg ClientImplNotice.jpg

 

 

 

 


제일 어려웠던 부분은, 인기비디오 목록 처리 부분.


처음에는 인기비디오 수집시, synchronized 처리로 인한 락이 걸리면서 작업이 중지되는 현상을 보였다.

이를 해결하기 위해 하나의 메소드 안에서 자료 수집과 뿌려주는 작업을 순차적으로 진행시키도록 하였다.


화면구성 자체는 간결하다.


추후에 유사한 작업을 진행할 때에는, 각 화면별 구성과 컴포넌트들의 이름을 기록하고 이를 구분하기 쉽도록 해야겠다.

스스로 해결하지 못해서, 선생님께 조언을 구했다. 어려울 때 도움을 요청할 수도 있겠지만, 스스로 깊게 사색하고,

문제점을 찾아 해결할 수 있는 능력을 길러보도록 하자. 너는 할 수 있다. ㅡㅅ-)b

이 글은 스프링노트에서 작성되었습니다.

Posted by 허니몬
이전버튼 1 이전버튼