애초 발단은..xml책을 보다가.. 


3tier를 구분하기 위한 디자인으로.. dbhandler, htmlwrapper 클래스를 만들어 서블릿의
역할을 래핑해서 분리하는 작업중.. 서블릿,디비핸들러,htmp래퍼간 어떤 방식으로 통신
하느냐에 대해 Env 클래스(HashTable파생해서 만든클래스)를 사용하겠다는 목적으로..(유연성)

디비핸들러와 html랩퍼를 만들어 두면.. sql쿼리와 html페이지만 만들어두면 쉽게 3tier app를
만들수 있다는 설명과 함께 구현을 보여주는데..(xml or 기타 파일을 이용한 스크립트 처리)


단락중에.. 환경설정을 저장하고 로딩할때 Env vs Properties 부분에서..

1.property가 문자열/문자열 이기에.. 문자열/문자배열까지 지원을 못한다는 문제점..
2.db핸들러 환경설정은 여러줄을 실행하는 sql쿼리들인 경우가 많고.. 프로퍼티의 load메소
드는 이들을 다 수용할 유연성이 없다고 하며.. (이게 오래전책이라 그런가? 1.5에서 도입된 loadFromXML 있는데..)
3.최종적으로 임의의 레벨을 갖는 환경 변수를 설정해야 하기 때문(Env가 subEnv를 가지고 subEnv가 다시 subEnv를 갖고..
트리형식)

이 말중.. 각 Env는 내부적으로 데이터를 교류하는 여러 JavaBeans들중 하나를 나타낸다. 사실 빈즈들은
끼워넣은 Env들의 구조로 변환된 XML 도큐먼트라고 할수 있고 , XML과 마찬가지로 요소들을 임의의 레벨에
넣을수 있다. 이것은 Env클래스도 마찬가지이다.

딱 요 단락을 보고.. 스윙의 컴포넌트들은 모두가 beans규약 이다는 글귀 + 내가 작업할때 컴포넌트들에 다들..
hashset형태의 테이블이 존재했었다는것.. propertyChangeSuporter를 써본 경험등.. 

그런 기억땜에 스윙 컴포넌트들의 베이스 클래스인.. jcomponent를  분석할 필요성이 느껴졌고.. 조금 살펴보다 .. 
이런저런 위임 객체들및 .. addNotify()를 보게 되었는데.. 예전에 제대로 이해 못하고 넘어간 Object클래스의
notify메서드및 옵저버 패턴이 떠올라.. 조금 살펴보던중.. 정신이 안드로메다로 떠나버렸음.. 

(아참.. Object클래스에서 notify와 wait가 있는데.. 
서로 다른 스레드간 공유되는 락객체를 만들고.. 이 락객체를 얻고, 놓아주고 하는 방법을 통해 스레드간 통신(동기화)을
하게하는 개념이다.
Object lock객체 = new Object();  syncronized(lock){lock.wait()를 해버리면.. 현재의 스레드가 대기+락객체lock를
놓아주어 다른 스레드가 락객체를 취득할수 있게 한다.}

다른 스레드에 의해 특정 이벤트 발생시.. syncronized(lock){lock.notify()식으로 하면.. 저 위에 멈췄던 스레드 다시
가동(throw InterruputException을 통해서 = 예외 핸들링 방식.. 물론 중간에 새로운 스레드를 생성및 동작시키는 등의 
처리도 가능하고.. 내 맘대로지..} => 결국 스레드간 이벤트 방식으로 동작시킬수 있음.

예전 단순 멀티스레드 서버 구현시 어셉,리드 작업의 비동기 처리를 위해 어셉 스레드에서 어셉후, 리드 스레드를
생성해서 동작시키는 방식이었지만.. wait,notify를 이용한다면.. 서버 처음 시작부터.. 어셉스레드 동작, 리드 스레드
동작시키고.. 지들끼리 내부적으로 wait/notify로서 생산자/소비자 방식으로 순차적 처리가 가능함. 

물론 위의과정은 스레드가 각각 하나씩인 단순한 경우로서.. 더 복잡해질 경우.. 어셉 스레드풀 + 어셉용 스레드 3개
리드용 스레드풀 + 리드용 스레드 10개라면.. 어셉 스레드들과 리드 스레드들간의 생산/소비자 방식의 순차적 처리+
어셉스레드는 자기들끼리, 리드스레드는 자기들끼리 동기화를 시켜줘야함.(지들끼린 코드를 공유하니.. 메서드의
선언에 synchronized를 한다던가 하는 식 또는 공유 데이터를 동기화 객체(콘커런시인가 하는 패키지)으로.. 동기화 처리)

실제 구현은 안해봄;;  결국.. 작업 시작해라=notify, 작업 잠시 멈춰라=wait 라는 .. 이벤트 객체인 셈임..
이벤트 처리 방식은 .. 전에 잠깐 살펴본 생산자/소비자 패턴임. = 예전 nio할때.. 어셉용 스레드가 큐=fifo에 클라이언트 
메세지들을 넣어두고.. 큐객체가 발송 작업용 스레드1놈만 호출해서 작업시키는 방식이랄까? 물론.. 큐의 원소 하나당
스레드 하나씩이지.. 전체를 스레드 하나가 처리하는건 아님;;)
*****************************************************************8

여튼 xml등 파일을 통한.. 설정의 저장/로드를 통한 초기화는 다른 프레임워크.. 스프링/스트럿츠등에서도 사용하는 개념
이기에 뚤어둘 필요가 있음;; ..초 간단하게 개념잡자면.. xml파일에 readObject/writeObject 함으로서 확장성 높이고,
결합성 줄이고..문자열이라 사람이 이해하기 쉽고..
(현재 xml책을 보다->grep코드를 보다->스윙책중 document부분을 보다.. -> 인터넷에서 jcomponent를 찾고있는중;;;)


결론: 자바 api클래스들중 특히 gui클래스들.. 정말 더럽게 복잡하고.. 거대하고.. 사람 환장하게 함;;

jcompent가 임포트하는 클래스만 해도.. OTL


 import java.util.HashSet;
29  import java.util.Hashtable;
30  import java.util.Dictionary;
31  import java.util.Enumeration;
32  import java.util.Locale;
33  import java.util.Vector;
34  import java.util.EventListener;
35  import java.util.Set;
36  import java.util.Map;
37  import java.util.HashMap;
38  
39  import java.awt.*;
40  import java.awt.event.*;
41  import java.awt.image.VolatileImage;
42  import java.awt.Graphics2D;
43  import java.awt.peer.LightweightPeer;
44  import java.awt.dnd.DropTarget;
45  import java.awt.font.FontRenderContext;
46  import java.beans.PropertyChangeListener;
47  import java.beans.VetoableChangeListener;
48  import java.beans.VetoableChangeSupport;
49  import java.beans.Transient;
50  
51  import java.applet.Applet;
52  
53  import java.io.Serializable;
54  import java.io.ObjectOutputStream;
55  import java.io.ObjectInputStream;
56  import java.io.IOException;
57  import java.io.ObjectInputValidation;
58  import java.io.InvalidObjectException;
59  
60  import javax.swing.border.*;
61  import javax.swing.event.*;
62  import javax.swing.plaf.*;
63  import static javax.swing.ClientPropertyKey.*;
64  import javax.accessibility.*;
65  
66  import sun.swing.SwingUtilities2;
67  import sun.swing.UIClientPropertyKey;


by givingsheart 2014. 1. 2. 09:41


Thread workHard = new Thread()
{ //익명 클래스 기법
  public void run()
  {
        doToughWork(); //이벤트처리및 페인팅 작업등.. 우선 처리 해야할 작업들 (1스레드 임으로 blocking)

        SwingUtilities.invokeLater(new Runnable()
        {
            //메서드의 매개변수로 객체를 생성해서 넘길때도 익명클래스 기법으로 재정의 가능
            public void run()
            {
                updateConponents(); //컴포넌트의 프로퍼티등 상태 수정.. 등의.. 가벼운 작업..
             }
         };
   }
};

workHard.start(); 

=>음..뭐랄까.. 일단 스레드간 병목현상을 없애기 위해서.. 가장 시간이 많이 소요되는 작업을 우선 처리한 후
   그 작업 스레드에서 새로운 스레드를 생성해 다음 작업을 처리시킴... 
   =>서버 소켓의 accept() 후  클라에 대한 i/o용 작업 스레드를 생성해서 start() 시킨것과 같음.

음.. 멀티스레드에서 병목현상이 있다면.. 전에 남궁성선생님 책에서 yield()인가를 쓰면 된다고 했었는데...
아.. yield()는 병목현상이 아니라.. 유휴시간이었던가... 글고 또 다른 방법이 생각났었는데.. 그새 까묵....OTL

하여튼.. 스레드간 순차적인 처리를 하게 한다.

*************************************************************8

음.. 사용자가 스레드 작업을 멈출수 있게.. doToughWork();를 구현

public void doToughWork()
{
  try
  {
      //작업 종료시(모든 객체를 반복해가며 while(){for(객체갯수){doUpdat(); doPaint();}})로 while의 종료조건
      //을 구성하지 말고!  while 업무 종료조건을.. 예전에 nio 헀을당시 스레드 처리 방식처럼..
      
      while(true) //예전 nio땐 클라측 스트림 객체가 not null인 동안
        for(처리할 객체의 갯수만큼)
        {
           if(Thread.interrupted() ) //현재 스레드가 인터럽트 상태인가? 
           {
              throw new IntterruptedException(); <-- 익셉션 발생을 통한 반복문 제어 처리
           }
            객체.update();
            객체.draw();
         }
       Thread.wait(1000); //현재 스레드가 한타임 뛰었으니 1초 휴식 -_-;
  }
  catch(IntterruptedException e)
  {
      //스레드 인터럽트를 알리고
      //객체들 상태가 변화했으면 
      // invokerLater를 호출한다.
   }
}

사용자용 Jbutton의 리스너에

actionPerform(Event e) 인가 에서
{
   workHard.interrrupt(); 를 해주면..
}


(추가)

스윙..컴포넌트 기반의 GUI.. 추후 자바스크립트중 프론트 영역의 MVC처리 , 안드로이드 에서.. 조립및 재사용 단위에

있어서 도움이 되었다.

'자바se api > swing' 카테고리의 다른 글

스윙..  (0) 2014.01.02
이벤트처리 스레드;;  (0) 2014.01.02
propertyEditor vs ConversionService + 토비의 스프링?  (0) 2014.01.02
자바 스윙 겁나 복잡하고 방대함...  (0) 2014.01.02
by givingsheart 2014. 1. 2. 09:28
스윙책에서 이벤트처리 스레드를 강조했기에 (java.awt.EventDispatchThread)

이번 기회에 분석하자 해서 봤더만... 머리아픔..

63 class More ...EventDispatchThread extends Thread {
64 
65     private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
66 
67     private EventQueue theQueue; // 이벤트큐 구현 코드는 제일 아래쪽에 (자기=스레드가 처리할 작업거리를 필드로
                                                         갖고있다..
68     private boolean doDispatch = true;
69     private boolean threadDeathCaught = false;
70 
71     private static final int ANY_EVENT = -1;
72 
73     private Vector<EventFilter> eventFilters = new Vector<EventFilter>();//체인오브 리스폰스빌리티처럼,.. 필터개념
//으로 이벤트 검사
74 
75     More ...EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
76         super(group, name);
77         setEventQueue(queue); //aggregation.. 내 경운 전에 worker와 work를 association으로 해서 worker.setWork(work)
78     }
79 
80     /*
81      * Must be called on EDT only, that's why no synchronization
82      */
83     public void More ...stopDispatching() {
84         doDispatch = false;
85     }
86 
//아래가 기본 동작 run()
87     public void More ...run() {
88         while (true) {
89             try {
90                 pumpEvents(new Conditional() {
91                     public boolean More ...evaluate() {
92                         return true;
93                     }
94                 });
95             } finally { //리턴을 해도 finally는 무조건 실행됨.(내가 전에 이것땜에 당황했었음)
96                 EventQueue eq = getEventQueue();
//아래는 run의 while(true) 종료 조건임 이게 finally구문 안에 있는것을 이해할것!
97                 if (eq.detachDispatchThread(this) || threadDeathCaught) {
98                     break;
99                 }
100            }
101        }
102    }
103
104    void More ...pumpEvents(Conditional cond) {
105        pumpEvents(ANY_EVENT, cond);
106    }
107
108    void More ...pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
109        pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
110    }
111
112    void More ...pumpEvents(int id, Conditional cond) {
113        pumpEventsForHierarchy(id, cond, null);
114    }
115
116    void More ...pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
117        pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
118    }
119
120    void More ...pumpEventsForFilter(Conditional cond, EventFilter filter) {
121        pumpEventsForFilter(ANY_EVENT, cond, filter);
122    }



166    boolean More ...pumpOneEventForFilters(int id) {
167        AWTEvent event = null;
168        boolean eventOK = false;
169        try {
170            EventQueue eq = null;
171            EventQueueDelegate.Delegate delegate = null;
172            do {
173                // EventQueue may change during the dispatching
174                eq = getEventQueue();

//아래는 getDelegate() 메서드에서 뭘하는지 확인 필요..(AppContext는 프로그램을 의미하는 전역
//객체라 생각하는게 편할듯)
//프로그램별로 이벤트 처리 담당하는 녀석들이 set에 들어있나봄.. swing의 컴포넌트들도 그렇던데..
39    public static Delegate More ...getDelegate() {
40        return
41          (Delegate) AppContext.getAppContext().get(EVENT_QUEUE_DELEGATE_KEY);
42    }
175                delegate = EventQueueDelegate.getDelegate();
176
//이벤트 처리할 delegate를 얻었으니.. 큐에서 이벤트 꺼내오기.
177                if (delegate != null && id == ANY_EVENT) {
178                    event = delegate.getNextEvent(eq);
179                } else {
180                    event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
181                }
182
//아래 로직을 보니.. eventOK = false; 코드가 눈에 띄는데.. 여러 필터단에서 해당 이벤트가 
//처리할 이벤트인지를 검증하는듯..
183                eventOK = true;
184                synchronized (eventFilters) {
185                    for (int i = eventFilters.size() - 1; i >= 0; i--) {
186                        EventFilter f = eventFilters.get(i);
187                        EventFilter.FilterAction accept = f.acceptEvent(event);
188                        if (accept == EventFilter.FilterAction.REJECT) {
189                            eventOK = false;
190                            break;
191                        } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
192                            break;
193                        }
194                    }
195                }
//필터로도 부족해서 다른 메서드를 통해 이벤트인지를 확인
196                eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
197                if (!eventOK) {
198                    event.consume(); //말그대로.. 이벤트를 처리한달까? 소모시키기.. 아래처럼 구현
418    protected void More ...consume() {
419        switch(id) {
420          case KeyEvent.KEY_PRESSED:
421          case KeyEvent.KEY_RELEASED:
422          case MouseEvent.MOUSE_PRESSED:
423          case MouseEvent.MOUSE_RELEASED:
424          case MouseEvent.MOUSE_MOVED:
425          case MouseEvent.MOUSE_DRAGGED:
426          case MouseEvent.MOUSE_ENTERED:
427          case MouseEvent.MOUSE_EXITED:
428          case MouseEvent.MOUSE_WHEEL:
429          case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
430          case InputMethodEvent.CARET_POSITION_CHANGED:
431              consumed = true;
432              break;
433          default:
434              // event type cannot be consumed
435        }
436    }

199                }
200            }

//처리할 이벤트가 아니면.. 무한루프 돌면서 시간 때우기.. (물론 스레드임으로 인터럽트 발생하면 
//다른 스레드에게 실행권 넘어감. 
201            while (eventOK == false);
202
203            if (eventLog.isLoggable(PlatformLogger.FINEST)) {
204                eventLog.finest("Dispatching: " + event);
205            }
206
//아래 부분이 핵심인듯 한데.. 이해가 안됨.. 저 메서드들도 숨어있고..
207            Object handle = null;
208            if (delegate != null) {
209                handle = delegate.beforeDispatch(event);
210            }
211            eq.dispatchEvent(event);
212            if (delegate != null) {
213                delegate.afterDispatch(event, handle);
214            }
215
216            return true;
217        }
218        catch (ThreadDeath death) {
219            threadDeathCaught = true;
220            return false;
221
222        }
223        catch (InterruptedException interruptedException) { //프로그램 내의 모든 스레드를 회수 = 프로그램 종료
224            return false; // AppContext.dispose() interrupts all
225                          // Threads in the AppContext
226
227        }
228        catch (Throwable e) {
229            processException(e);
230        }
231
232        return true;
233    }


**************************************************************


235    private void More ...processException(Throwable e) {
236        if (eventLog.isLoggable(PlatformLogger.FINE)) {
237            eventLog.fine("Processing exception: " + e);
238        }
239        getUncaughtExceptionHandler().uncaughtException(this, e); //분석하고 싶은데 메서드 못찾겠음..
240    }




***************************************************************


//우선순위큐로 이벤트들을 모아놓고, 스레드 세이프하게 fifo방식으로 처리
101 public class More ...EventQueue {
102 
103     // From Thread.java
104     private static int threadInitNumber;
105     private static synchronized int More ...nextThreadNum() {
106         return threadInitNumber++;
107     }
108 
109     private static final int LOW_PRIORITY = 0;
110     private static final int NORM_PRIORITY = 1;
111     private static final int HIGH_PRIORITY = 2;
112     private static final int ULTIMATE_PRIORITY = 3;
113 
114     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
115 
116     /*
117      * We maintain one Queue for each priority that the EventQueue supports.
118      * That is, the EventQueue object is actually implemented as
119      * NUM_PRIORITIES queues and all Events on a particular internal Queue
120      * have identical priority. Events are pulled off the EventQueue starting
121      * with the Queue of highest priority. We progress in decreasing order
122      * across all Queues.
123      */
124     private Queue[] queues = new Queue[NUM_PRIORITIES]; //스레드 우선순위별로 관리하는듯
125 
126     /*
127      * The next EventQueue on the stack, or null if this EventQueue is
128      * on the top of the stack.  If nextQueue is non-null, requests to post
129      * an event are forwarded to nextQueue.
130      */
131     private EventQueue nextQueue; //자신을 가리켜? 뭐지?? 연결리스트인가? 이벤트큐 연결 리스트 자료구조?
132 
133     /*
134      * The previous EventQueue on the stack, or null if this is the
135      * "base" EventQueue.
136      */
137     private EventQueue previousQueue; //이전을?? 
138 
139     /*
140      * A single lock to synchronize the push()/pop() and related operations with
141      * all the EventQueues from the AppContext. Synchronization on any particular
142      * event queue(s) is not enough: we should lock the whole stack.
143      */
144     private final Lock pushPopLock; //스레드 세이프 (동시에 pop 불가 = 하나의 이벤트당 하나의 스레드)
145     private final Condition pushPopCond;
146 
147     /*
148      * Dummy runnable to wake up EDT from getNextEvent() after
149      push/pop is performed
150      */
151     private final static Runnable dummyRunnable = new Runnable() {
152         public void More ...run() {
153         }
154     };

생략..



*****************************************************************8


249    private static class More ...HierarchyEventFilter implements EventFilter {
250        private Component modalComponent;
251        public More ...HierarchyEventFilter(Component modalComponent) {
252            this.modalComponent = modalComponent;
253        }
254        public FilterAction More ...acceptEvent(AWTEvent event) {
255            if (modalComponent != null) {
256                int eventID = event.getID();
257                boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
258                                     (eventID <= MouseEvent.MOUSE_LAST);
259                boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
260                                      (eventID <= ActionEvent.ACTION_LAST);
261                boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
262                /*
263                 * filter out MouseEvent and ActionEvent that's outside
264                 * the modalComponent hierarchy.
265                 * KeyEvent is handled by using enqueueKeyEvent
266                 * in Dialog.show
267                 */
268                if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
269                    /*
270                     * Modal internal frames are handled separately. If event is
271                     * for some component from another heavyweight than modalComp,
272                     * it is accepted. If heavyweight is the same - we still accept
273                     * event and perform further filtering in LightweightDispatcher
274                     */
275                    return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
276                }
277                if (mouseEvent || actionEvent || windowClosingEvent) {
278                    Object o = event.getSource();
279                    if (o instanceof sun.awt.ModalExclude) {
280                        // Exclude this object from modality and
281                        // continue to pump it's events.
282                        return FilterAction.ACCEPT;
283                    } else if (o instanceof Component) {
284                        Component c = (Component) o;
285                        // 5.0u3 modal exclusion
286                        boolean modalExcluded = false;
287                        if (modalComponent instanceof Container) {
288                            while (c != modalComponent && c != null) {
289                                if ((c instanceof Window) &&
290                                    (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
291                                    // Exclude this window and all its children from
292                                    //  modality and continue to pump it's events.
293                                    modalExcluded = true;
294                                    break;
295                                }
296                                c = c.getParent();
297                            }
298                        }
299                        if (!modalExcluded && (c != modalComponent)) {
300                            return FilterAction.REJECT;
301                        }
302                    }
303                }
304            }
305            return FilterAction.ACCEPT;
306        }
307    }


by givingsheart 2014. 1. 2. 09:27


툴작업중 내 서브프레임들 (dbinfo, ddl, dml, dql, console만 빼고) 각각이 사용자가 입력한 문자열들을 save/load 지원을 
해줘서 xml파일로 관리하기로 마음먹고.. 지난번에 작업해둔.. property.loadFromXml인가를 사용하려 하다가.. 

propertyEditor라는 것을 접하게 되었고 검색을 해보았다. 이번 작업도.. 스프링과 매치되는 부분이 있다니..
황당할 따름이다. 툴 작업이라.. 스레드에 전혀 관심을 안두었던 내게.. 약간의 찜찜함을 남겨준다.

property를 이용해 xml로 쏘고 읽는건 해봤으니.. 약점이 있더라도 propertyEditor를 적용해봐야겠다.

구글에서 propertyeditor sample or example 로 검색을 해봐야겠다. 아..서점도 가야하는데..

스프링 jre 다운 받기


(토비라는 유명한 분 블로그인듯)


Example 10.6: The YesNoDialogAlignmentEditor Class

package oreilly.beans.yesno;
import java.beans.*;
import java.awt.*;

public class YesNoDialogAlignmentEditor extends PropertyEditorSupport 
{  
// These two methods allow the property to be edited in a dropdown list.  
// Return the list of value names for the enumerated type.  

public String[] getTags() 
{    
return new String[] { "left", "center", "right" };  
}  
// Convert each of those value names into the actual value.  

public void setAsText(String s) 
{    
if (s.equals("left")) setValue(new Integer(YesNoDialog.LEFT));    
else if (s.equals("center")) setValue(new Integer(YesNoDialog.CENTER));    
else if (s.equals("right")) setValue(new Integer(YesNoDialog.RIGHT));    
else throw new IllegalArgumentException(s);  
}  
// This is an important method for code generation.  

public String getJavaInitializationString() 
{    
switch(((Number)getValue()).intValue()) 
{    
default:    
case YesNoDialog.LEFT:   return "oreilly.beans.yesno.YesNoDialog.LEFT";    
case YesNoDialog.CENTER: return "oreilly.beans.yesno.YesNoDialog.CENTER";    
case YesNoDialog.RIGHT:  return "oreilly.beans.yesno.YesNoDialog.RIGHT";    }  
}

}

위를를 보니 어떻게 써야할지.. 약간 감은 잡겠다
클래스 PropertyEditorSupport 그중.. 내가 써봐야 할것은.. 아래 메서드 이리라..

PropertyEditor 는, 프로퍼티치를 편집하는 완전한 커스텀 컴퍼넌트를 제공할 수가 있습니다. PropertyEditor 는, 에디터의 컴퍼넌트와 제휴해, PropertyChange 이벤트를 트리거해 프로퍼티치의 변경을 통지합니다.

getCustomEditor 를 호출하는 고레벨인 코드에서는, 컴퍼넌트를 보다 큰 프로퍼티 시트에 짜넣거나 독자적인 다이얼로그에 배치하거나 할 수가 있습니다.


정의:
인터페이스 PropertyEditor 내의 getCustomEditor


반환값:
사용자가 현재의 프로퍼티치를 직접 편집할 수 있도록(듯이) 한다 java.awt.Component. 지원되지 않는 경우는 null



'자바se api > swing' 카테고리의 다른 글

스윙..  (0) 2014.01.02
스윙의 기본적인 멀티스레드 처리방식  (0) 2014.01.02
이벤트처리 스레드;;  (0) 2014.01.02
자바 스윙 겁나 복잡하고 방대함...  (0) 2014.01.02
by givingsheart 2014. 1. 2. 09:24

간단하게 swing으로 구현? 이 말이 부끄러워진다..


예전에 간단하게 awt gui 기반에서 text 필드에 사용자가 디비 드라이버 정보, 접속url, id,pw 등을 입력하고 버튼을 
누르면, 모든 컴포넌트의 값을 읽어와 루트element에 setproperty 하는 형식으로 값들을 넣고.. 그걸 documnet에 넣어서
dbinfo.xml로 출력해주는 간단한 코드였다.

사실 awt의 기능들을 충분히 사용해보지 않은 상태로(예전엔 awt 클래스들을 디자인 패턴의 관점에서 분석만 했었고..)

현재 제대로 된 dbConnect정보,ddl,dml,dql 을 사용자가 입력하고, 실제 db와 연동시키려는 툴을 만들기 위해
툴의 디자인을 고민했었다. 

1.처음의 기본 디자인은.. 각각의 입력(커넥션,ddl,dml,dql) 페이지를 JPanel로 구분해서.. 메인 툴 프레임에 
예전에 했던대로 gridLayout을 설정해 위에서부터 순서대로 판넬을 포함 시키는 방법. add(component)

(여기서 문제가 발생. 메인 프레임이 800,800 사이즈라.. 각각의 서브 판넬이 800,200 식으로 나눠 가졌으나.. 
개별적 작업 공간이 크기도 부족했을 뿐더러.. 작업 공간이 섞여있어서 직관적이지 못했다.)

2.두번째 디자인은 메인 툴 프레임에  <-  -> 버튼을 추가해서 해당 페이지로 이동하고 작업하는 방식이었다.

첫번째 문제가 현재 겹쳐있는(위치값 동일) 패널에 대해 ->버튼을 클릭시 위치를 이동시켜서 화면 밖으로 
빼고, 다음 패널이 사용자의 입력을 받을 수 있게끔 하는 것이었는데.. 포커스 문제,위치 이동과 복귀등 생각보다 
복잡했다.(물론 시간 투자해 억지로 매달리면 구현은 가능했을테지만..)

두번째 문제가 툴 사용자가 실제 db정보를 입력하고 그것이 제대로 작동하는지 피드백을 받아볼 필요가 있었고
ex) "127.0.0.1 oracal xxx 에 접속 성공"  "create memberInfo( id number(3), name vchar2(20), address ...)
memberInfo 테이블 생성 성공"  "selete * memberInfo 성공" "결과 001,가길동,강북  002,나길동,강남" ...

이 처리를 위해서 이클립스의 콘솔창의 개념이 필요했다. (현재까지 총 5개의 구분되는 컨테이너 컴포넌트=판넬 필요)
+ 콘솔용 판넬은 db커넥션 정보 입력용 패널, ddl 입력용 패널, dml 입력용, dql 입력용 패널에서 공유되어야할 필요가
있었다.

3.그 다음 디자인이.. 메인 프레임 안에.. 각각 독립적인 정보입력용 프레임 4개 + 결과 출력용 프레임 1개를 넣는 방식
이었다. mainFrame.add(new MyFrame("ddl")); 요런 식으로.. (물론... 실행을 시키면 프로그램 창(프레임)이 2개나 
띄워졌지만.. 뻑=익셉션이났다.. 디버깅을 안해서 정확한 이유는 모른다. OTL)

나는 여전히 3번 방식이 객체 지향적이며 무엇보다 내가 원했던.. 사용자가 작업을 하면서 명확해질수 있게끔 돕는 것이
라 생각해.. 이 아이디어를 포기 할수 없었다. 그렇기에 정보를 찾아봤다.

4.LayerdPane 개념 습득. 
swing에 관하여 조금 더 인터넷 서치를 하던중..(내실 없이 아주 거지같은 광고용 블로그에도 당하고.. 욕나옴 -_-;)
알게된 개념으로서.. 아주 오래전 2d 슈팅or액션 게임 만들던때 사용하던 2d화면에 배경별(멀고,가깝고),오브젝트별,캐릭터별 
층을 구분하고 아래부터 먼저 draw 해주는 개념이었다. 

이걸 이용한다면.. 콘솔창의 문제를 제외하곤 애초에 생각했던 2번문제.. <- -> 버튼으로 작업공간 이동이 쉽게 풀릴듯 하여.. 작업을 시작하려 하였으나..

5.Intenal(내부)Frame 개념 습득..
요 클래스가 내가 3번에서 뻑이 났던.. 문제를 해결해주는 개념이었다.. (나처럼 메인 프레임 안에.. 독립적인 프레임을
만들길 원하는 수요가 있어서 java가 만들어 줬나보다. 

멋도 모르고 JFrame을 상속받은 내 메인 프레임에 ddl = new JInternalFrame(); mainFrame.add(ddl); 
요런식으로 해봤더니.. 원하던대로.. 뻑도 안나고 내부의 독립적인 프레임이 생성이 되었다. (이때의 감동이란 ㅠㅠ)

6.샘플 소스코드 입수
... 그렇다.. 이미 java의 고급 개발자들이 우리에게 은혜를 베푸시어.. core api 외에도 샘플 소스코드를
만들어주셨는데.. 왜 이생각을 못했을까? (예전에 한번, 콘솔용 겁나 복잡해진 사용자 컨트롤 처리 로또 프로젝트를 실패
하고, 하루만에 접은 gui 기반 동물 농장 프로젝트를 통해.. "다음에는 샘플 코드부터 작업을 시작하자고 생각했었는데.."

채팅이나, nio 채팅의 경우도.. 거의 맨땅에서 작업하느라 효율이 안좋았는데.. 왜 그랬을까?.. 왜그랬을까..?

에서.. internalFrame 샘플 코드를 받아본 나는.. 다시 한번 새로운 충격에 빠졌다..


7.방황하는 시간..

아래처럼 구현하는 것이.. 스윙 패키지의 기능을 90% 이상 뽑아내는 것이리라..
(내가 구현했던 것들이.. 아주 먼지처럼 느껴졌다.. 내가 한건.. gui 패키지 사용의 겉핥기..)

import javax.swing.JInternalFrame;
import javax.swing.JDesktopPane;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JFrame;
import javax.swing.KeyStroke;

import java.awt.event.*;
import java.awt.*;

/*
 * InternalFrameDemo.java requires:
 *   MyInternalFrame.java
 */
public class InternalFrameDemo extends JFrame
                               implements ActionListener {
    //내경우 JFrame을 상속받아.. add 처리만 하려 했는데.. 아래의 JDesktopPane 이란 관리용 클래스...
    //내가 구현하려던 mainFrame 클래스는 각각의 서브 프레임(db입력용,dml,ddl,dql,콘솔창용)에 대해
    //중앙 컨트롤(사용자의 개별적 입력 이벤트를 전달받아.. 처리후 각각의 서브 프레임에게 명령 전달 하는 
    //메디에이터 클래스의 개념.. ) 한마디로 씬or 페이지 매니저를 만들려고 했었는데.. 이미 만들어져 있었다.
    //즉.. 메인 프레임에서 컨테이너 관리적인 측면을 또 다른 객체에게 위임한 상태..
    //글고 중요한건 아니지만.. 내경운 지금까지 해당 컴포넌트에 대한 리스너를 component.addXXListerner( new
    // xxxAdapter(){익명 클래스 기법으로 재정의}; ) 식으로 처리했는데.. 위처럼 implements를 시키는 것에 대해
    // 고민이 필요할듯 하다.
/*
<명세>

멀티 문서 인터페이스 또는 가상 데스크탑을 생성하는 컨테이너입니다. JInternalFrame 객체를 생성해,JDesktopPane 에 추가합니다. JDesktopPane  JLayeredPane 를 확장해, 오버랩의 가능성이 있는 내부 프레임을 관리합니다. 또, 현재의 Look & Feel (L&F)에 대해서 UI 클래스에서 설정된 DesktopManager 의 인스턴스에의 참조도 유지합니다. JDesktopPane 는 경계를 지원하지 않습니다.  

이 클래스는 일반적으로,JInternalFrames 의 부모로서 사용되어 플러그 인 가능한 DesktopManager 객체를JInternalFrames 에 제공합니다. L&F 별로 구현되는 installUI 로,desktopManager 변수의 적절한 설정을 실시합니다. JInternalFrame 의 부모가 JDesktopPane 의 경우, 클로즈나 사이즈 변경등의 동작의 대부분을 desktopManager에 위양 합니다.  

상세와 사용예에 대해서는, 「The Java Tutorial」의「How to Use Internal Framesy」를 참조해 주세요.  

*/

    JDesktopPane desktop; //요것을 멤버 필드로 보관하는 이유는 좀 있다가..

    public InternalFrameDemo() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
       //내경운 일단 빠른 구현을 위해서 setSize인가로 800,600을 떄려 넣었다. 아래가 정석이다.ㅠㅠ
       //툴킷의 경운 .. 사용자의 native한 gui 데스크탑 환경이라 생각하면 된다.(os)
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        //메인프레임을 클래스 멤버필드로 관리하기에.. 아래처럼 서브프레임을 만드는 행위를 메서드로 뺄수 있게 되었다.
        //서브프레임을 동적으로 넣었다, 뺐다 할수 있다.  미리 고정된 .. mainFrame.add(subFrame1); ... 요럴 필요가 없음.
        //생성하려는 서브 프레임이 동일하다면.. 아래처럼 쓰면 될테고.. dml,dql,,ddl,console,dbinfo처럼 제각각 특징이 
        //있다면 상속받아서.. 다형성을 이용해야 한다.
        createFrame(); //create first "window" 
        
        //메디에이터? 관리용 객체(JDesktopPane)을 만들었으니 메인 Frame에 세팅하는 작업이 필요.
        setContentPane(desktop);
        //아래의 경운.. 내가 만들툴의 디자인상 각각의 서브 프레임이 사용자의 입력 데이터를 개별적으로 save/load
        //하는데 사용이 가능할듯. JMenuBar crateMenuBar()로서 메서드 단위로 개념을 분리시켰다.
        setJMenuBar(createMenuBar());

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
    }

    protected JMenuBar createMenuBar() {
        //이처럼 모듈별로 쪼개는것은 중요하다. 내가 구상한 디자인 경우에도.. ddl 프레임에서 setColumn() 이란 메서드로서
       // 반복적이고 몇개가 될지 모르는 테이블의 컬럼 정의를 메서드로 추출하려 했었으니까..
       //ex)사용자가 테이블에 대해 하나의 컬럼 정의를 완료하고 add 버튼을 누르면 다음 컬럼 정의할수 있고
       //또는 delete를 누르면 이미 정의된 컬럼 날아가고.. confirm 누르면 확정되어 데이터를 실제로 조립하고...
        JMenuBar menuBar = new JMenuBar();

        //Set up the lone menu.
        //정말..멋진 디자인이다. 메뉴바 객체에 메뉴들을 추가한다.. 컨테이너의 개념...
        JMenu menu = new JMenu("Document");
        
       //놀라울 따름이다.. 해당 메뉴객체에 키보드 alt+D 이벤트를 연결하는 작업이 이처럼 간단하다.
        menu.setMnemonic(KeyEvent.VK_D);
        menuBar.add(menu);

        //Set up the first menu item.
        //마찬가지이다. 하나의 메뉴객체는 또한 내부에 이것 저것 아이템을 가지고 있을테니.. 나는 정말로
        //자바가 제공하는 gui 프레임 워크를 1%도 이해를 못하고선.. 혼자서 대충 만들수 있다느니..하고 자만했다.
        //얼마나 직관적이고 일관성있는 인터페이스 인가?
        JMenuItem menuItem = new JMenuItem("New");
        menuItem.setMnemonic(KeyEvent.VK_N);
        //일반적인 키 이벤트야 비트마스크로 추출하는건 알고 있으니 넘어가고..
        menuItem.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_N, ActionEvent.ALT_MASK));

        //아래의 menuItem.setActionCommand("new"); menuItem.addActionListener(this);... 화룡점정이다.
        //내가 만들던 파일매니저의 서브시스템중 워커 팩토리를 구현할때 다형적인 워커와 클래스를 해쉬맵으로 
        //key,value로 묶어서 문자열로 매핑한 것을 상기하자.  

/* 리마인드용 내가 구현했던 코드 조각
workerMap = new HashMap<String,Class<?>>();
Properties pro = new Properties();
//TODO:경로까지 지정을 할까;;
pro.loadFromXML(new FileInputStream("worker.xml"));
for(Entry<Object,Object> entry : pro.entrySet())
{
try
{
workerMap.put((String)entry.getKey(), Class.forName((String)entry.getValue()));
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}


public FileWorkerImpl getWorker(String workerName)
{
assert workerName != null : "workerName 뷁:" + workerName;
assert !" ".equals(workerName): "workerName 뷁:" + workerName;
FileWorkerImpl worker = null;
try
{
worker = (FileWorkerImpl)workerMap.get(workerName).newInstance();
}
catch (InstantiationException | IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return worker;
}
*/
        //다시 생각해봐도 정말 아름다운 디자인으로, 커맨드 패턴 + 옵저버 패턴(이벤트 디스패처+리스너)의 멋진 활용
        //내가 전에 최고 수준의 코딩 기법을 따라하고 싶다고 노래를 불렀었는데.. 자바 샘플 소스중.. swing 포함 gui
        //부분.. 정말로 멋지다. 내가 아래처럼 설계하고 구현할수 있게끔 훈련된다면 얼마나 좋을까 ㅠㅠ 샘플 소스 코드
        //매일 하나씩 분석해야겠다.
        menuItem.setActionCommand("new");
        menuItem.addActionListener(this);
        menu.add(menuItem);

        //Set up the second menu item.
        //중복 됨으로 분석 생략
        menuItem = new JMenuItem("Quit");
        menuItem.setMnemonic(KeyEvent.VK_Q);
        menuItem.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_Q, ActionEvent.ALT_MASK));
        menuItem.setActionCommand("quit");
        menuItem.addActionListener(this);
        menu.add(menuItem);

        //메뉴바 란.. 하나의 프레임 속에선 서브 컴퍼넌트이지만.. 그 자신도 내부에 메뉴들과 그에 속한 아이템들을
        //갖는 객체.. 이 메뉴바란 객체를 구성하는걸 메서드 단위로 뺀 모듈화.. 배워야한다..ㅠㅠ 
        return menuBar;
    }

    //React to menu selections.
    //위에서 작업해준.. 액션이벤트란 커맨드를 문자열로 매핑하고, 액션 리스너 클래스의 actionPerformed() 메서드를
    //재정의 하여.. 아래처럼 간단하게 구현이 가능하다. 명령에 따른 처리를 메서드 단위로 추출한 것도 포인트.
    //사실.. 아래의 작업을 더 추상화하면.. 내가 파일시스템에 구현했듯.. 팩토리 + 워커를 상속계층으로 만들어
    //동일한 인터페이스인 work()로서 추상화하면.. 더 간단해진다. 
    //ex) Worker worker =  workerFactory.getInstance().getWorker("copy");
    //      Work work = workFactory.getInstance().getWork("file", srcPath, destPath);
    //      worker.setWork(work);  한마디로.. 디자인 패턴에 빠져.. 워커도 추상화, 워크도 다형적으로 추상화 해버렸다..
    //      worker.work();
    // 근데 실제로 위처럼 구현하게 되면.. 코드는 이뻐지지만, 명시적이지 않다. 예전에 코드컴플리트에서도 지적했듯
    // switch() case 문 또는 if else() 문으로 아래처럼 명시적으로 처리가 되면.. 추상화할 필요가 없다는데.. 동의한다.
    // 아래는 참으로 명시적이다.
    public void actionPerformed(ActionEvent e) {
        if ("new".equals(e.getActionCommand())) { //new
            createFrame();
        } else { //quit
            quit();
        }
    }

    //Create a new internal frame.
    protected void createFrame() {
        MyInternalFrame frame = new MyInternalFrame();
        frame.setVisible(true); //necessary as of 1.3
        //아까 JDeskTopPane(서브 프레임들의 메디에이터)을 멤버 필드로 보관한 효과가 여기서 나타남..
        desktop.add(frame);
        try {
            frame.setSelected(true); //요건 정확힌 모르겠으나.. 해당 프레임에 포커스 이동시키는 걸테지..
        } catch (java.beans.PropertyVetoException e) {} //요 빈 어쩌구 예외 클래스는 당황스럽다.. 지금은 걍 패스
    }

    //Quit the application.
    protected void quit() {
        System.exit(0);
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread. 
       위의 의미는 정확히 이해는 못하겠다.
       단지 이벤트 디스패팅 스레드란 단어를 보니.. 예전에 컴포넌트에 이벤트가 발생햇다는 것을 감지하는 이벤트 디스패처
       (내가 awt 분석떄 자주본 놈.. eventmulitcaster였나?)이 떠오른다. 
       대충 해석을 하면.. 멀티스레딩에 안전하게 gui객체를 생성하기 위해서 이벤트 감시자에게 불려가는 콜백 메서드를
       정의하는것 같은데.. 생소할 따름이다.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        InternalFrameDemo frame = new InternalFrameDemo();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Display the window.
        frame.setVisible(true);
    }

//아래를 보니.. 이해가 된다.. 위의 creatrAndShowGUI()가 특별한 의미가 있었던건 아닌.. 걍 init()메서드
//였구나..
//그보다 더욱 중요한건.. invokerLater의 매개변수로 스레드(=Runnable() + run()재정의를 익명클래스 기법을
//통해 생성과 동시에 재정의 처리) 객체를 생성하고.. run() 내부에서 InternalFrameDemo 란 gui 객체를 생성했다는 점이다.
//만약 내가 툴 프로그램을 멀티스레딩으로 처리했다면..  JFrame을 상속받은 툴 프로그램 객체에 Runnalbe을
//implements 하고 내부에 Thread 객체를 둔 다음에.. 생성자에서 thread = new Thread(this); start(){thread.start();}
//run(){} 을 구현했을 것이다. 위와 비교해 아래는 얼마나 깔끔한가..(제대로 이해는 못했지만..)
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}


ps.음.. 일단.. 멋진 코드를 보면서 감동도 받았지만, 현재 내 초라한 능력에 위축도 된다.. 툴 프로그래밍 진도가 예상보다 
늦어질지도 모른다.(자바가 제공하는 패키지를 백분 활용하여 작업을 한다는 것의 난이도를 느꼈기 때문이다.) 위와 같은 코딩 
스타일을 몸에 익혀야 할것이다. 

불행중 다행이라면.. 아직 완전히 이해는 못했지만.. 학원 1달차 부터.. 꾸준히 디자인 패턴 관련 글과 자료를 공부해 놓아서
여러 패턴들이 눈에 보이고... 왜 그렇게 설계를 했을지.. 약간의 짐작과 이해가 가능하다는 점이다. 그런고로 app를  oop를 
활용해 제대로 구현하기 위해선 디자인 패턴에 대한 이해는.. 선택이 아닌, 필수이다. 디자인 패턴은 개발중의 여러 복잡한 
이슈를 해결하기 위한 솔루션이다.

ps2.오늘 점심땐 중고 서점 가서 db책,swing책,멀티스레드책(+@스프링)


'자바se api > swing' 카테고리의 다른 글

스윙..  (0) 2014.01.02
스윙의 기본적인 멀티스레드 처리방식  (0) 2014.01.02
이벤트처리 스레드;;  (0) 2014.01.02
propertyEditor vs ConversionService + 토비의 스프링?  (0) 2014.01.02
by givingsheart 2014. 1. 2. 09:11

예전에 시스템 프로퍼티 전부 출력해보고.. 그때 awt 분석하다가..os 종속적인 부분들에 대해 프로퍼티로

값을 읽어오는걸 봐서..


java.util.properties 는 내 예상보다 우월한 클래스였다.

테스트 고고 

아.. 그나저나 컨테이너간의 형 변환이 아주 쉽다. 프로퍼티는 해쉬셋 형태인데.. 요걸 list구조에
쉽게 넣을수 있다. addAll() 메서드 대박!

java.util.concurrent 요 패키지 어제 살짝 훑어봣는데.. 대박임 (스레드 관련해서)

load(Reader) / store(Writer, String) 메소드는, 문자 베이스의 스트림에 대한 프로퍼티의 로드와 포함을, 후술 하는 단순한 행 지향 형식에서 실시합니다. load(InputStream) / store(OutputStream, String) 메소드는 load(Reader) /store(Writer, String) 페어와 같이 동작합니다만, 입력/출력 스트림이 ISO 8859-1 문자 인코딩으로 encode 되는 점만은 다릅니다. 이 인코딩으로 직접 표현할 수 없는 문자는,Unicode 이스케이프를 사용해 기술할 수 있습니다. escape sequence로 사용할 수 있는 것은, 단일의 문자 'u' 뿐입니다. native2ascii 툴을 사용하면(자), 프로퍼티 파일을 다른 문자 인코딩으로 변환하거나 그 역을 실행할 수 있습니다.

loadFromXML(InputStream) 및 storeToXML(OutputStream, String, String) 메소드는, 프로퍼티을 단순한 XML 형식으로서 로드 및 포함할 수 있습니다. 디폴트에서는 UTF-8 문자 인코딩이 사용됩니다만, 필요에 따라서 인코딩을 지정할 수 있습니다. XML 프로퍼티 문서에서는, 다음의 DOCTYPE 선언이 사용됩니다.

<! DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 
프로퍼티을 export/임포트 할 경우에, 시스템 URI (http://java.sun.com/dtd/properties.dtd)에는 액세스 하지 않습니다. 시스템 URI 는, DTD 를 일의에 식별하는 캐릭터 라인으로서 사용됩니다. 그 내용은 다음과 같습니다.
<? xml version="1.0" encoding="UTF-8"? ><! -- DTD for properties --><! ELEMENT properties ( comment?, entry* ) ><! ATTLIST properties version CDATA #FIXED "1.0"><! ELEMENT comment (#PCDATA) ><! ELEMENT entry (#PCDATA) ><! ATTLIST entry key CDATA #REQUIRED>


음.. 사용하기 엄청 간단함..
package properties;
import java.io.*;
import java.util.*;
public class main
public static void main(String[] args) 
{  
// TODO Auto-generated method stub  
//properties를 통한 xml 파일 저장,로드    
//로드 테스트  
Properties pro2 = new Properties();  
try  {   pro2.loadFromXML(new FileInputStream("park.xml"));  }  
catch (InvalidPropertiesFormatException e1)  
{   // TODO Auto-generated catch block   e1.printStackTrace();  }  
catch (FileNotFoundException e1)  
{   // TODO Auto-generated catch block   e1.printStackTrace();  }  
catch (IOException e1)  {   // TODO Auto-generated catch block   e1.printStackTrace();  }    

//테스트용 출력     
Iterator<Object> it = pro2.keySet().iterator();  
System.out.println("로드 테스트 출력");     
while(it.hasNext())     {      System.out.println(it.next());     }       

Properties pro = new Properties();  
pro.put("1", "장호1");  
pro.put("2", "장호2");  
pro.put("3", "장호3");  
pro.put("4", "장호4");  
pro.put("5", "장호5");    

try  {   pro.storeToXML(new FileOutputStream("park.xml"),"a");  }  
catch (FileNotFoundException e)  {   // TODO Auto-generated catch block   e.printStackTrace();  }  
catch (IOException e)  {   // TODO Auto-generated catch block   e.printStackTrace();  }      
}}


'자바se api > util' 카테고리의 다른 글

set,map,properties (2013/12/04)  (0) 2014.01.01
by givingsheart 2014. 1. 1. 16:29
서비스를 할때 동시접속자 수에 대한 개념 잡기. 어플리케이션단 튜닝, 하드웨어적 튜닝, 웹서비스의 경우 네트워크 대역폭에
대한 이해, 메모리 상주하는 세션들의 관리의 중요성, db와 커넥션의 갯수, 엔터프라이즈급 서버가 아닌, 로드 밸런싱을 통한
분산 처리(l4스위치등)  등등

http://nimba.tistory.com/entry/%EB%8F%99%EC%8B%9C%EC%A0%91%EC%86%8D%EC%9E%90%EC%88%98-%EC%84%9C%EB%B2%84%EC%9A%A9%EB%9F%89-%EB%A1%9C%EB%93%9C-%EB%B0%B8%EB%9F%B0%EC%8B%B1


l4스위치를 통한 로드밸런싱(포트단위= 독립 프로세스에서의 분산처리)


by givingsheart 2014. 1. 1. 16:24


//자~ 서버 소켓 생성을 쫒아가 봅시다! 포트 번호 받는 생성자~ 

0.서버 소켓의 클래스를 대충 봐야겟네요! 오...SocketImpl ??? 이걸 멤버 필드로 갖고 있네요? 뭘까 뭘까?
 
52 public class ServerSocket implements java.io.Closeable {

56     private boolean created = false;
57     private boolean bound = false;
58     private boolean closed = false;
59     private Object closeLock = new Object();

64     private SocketImpl impl;

69     private boolean oldImpl = false;

}

1.우리가 자주쓰는 포트번호 받는 생성자는 자신의 매개변수 3개짜리 생성자를 호출하는군요?
127    public ServerSocket(int port) throws IOException {
128        this(port, 50, null);
129    }

2.오호~  눈에 띄는게 setImpl()입니다? 추가로 포트 번호, 백로그가 먼진 몰라도 일단 50으로 세팅, 
  저기 237번 라인의 bind()를 잊지 맙시다!!!! 나~중에 다시 봅니다.
229    public More ...ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
230        setImpl();
231        if (port < 0 || port > 0xFFFF)
232            throw new IllegalArgumentException(
233                       "Port value out of range: " + port);
234        if (backlog < 1)
235          backlog = 50;
236        try {
237            bind(new InetSocketAddress(bindAddr, port), backlog);
238        } catch(SecurityException e) {
239            close();
240            throw e;
241        } catch(IOException e) {
242            close();
243            throw e;
244        }
245    }

3.이건 내부 초기화 메서드니까 접근자가 private군요? 
   3.1하여간 팩토리란 객체한테.. createSocketImpl(); 해달라는군요? 
   3.2팩토리 객체 없으면 SockSocketImpl() 객체를 생성하는군요? 소켓소켓? 이름도 희안하네 ㅋㅋㅋ
   3.3위에서 하여간 구현객체가 생성이 되었으니.. 초기화를 해주는군요? impl.setServerSocket(this); 
      일단 메서드 이름대로라면.. 서버소켓을 세팅하는데 매개변수로 자기 자신이 들어갑니다.
282    private void More ...setImpl() {
283        if (factory != null) {
284            impl = factory.createSocketImpl();
285            checkOldImpl();
286        } else {
287            // No need to do a checkOldImpl() here, we know it's an up to date
288            // SocketImpl!
289            impl = new SocksSocketImpl();
290        }
291        if (impl != null)
292            impl.setServerSocket(this);
293    }


4.팩토리는 무시하고 SocksSocketImpl()을 추적해봤습니다. 헐,.. 서버 소켓 생성 했습니다. 휴~


42  class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
43      private String server = null;
44      private int serverPort = DEFAULT_PORT;
45      private InetSocketAddress external_address;
46      private boolean useV4 = false;
47      private Socket cmdsock = null;
48      private InputStream cmdIn = null;  //오오 많이 보던 인풋스트림 노드계열 클래스! 현재는 비어있지만.. 반갑습니다.
49      private OutputStream cmdOut = null;  //오오 많이 보던 아웃풋스트림 노드계열 클래스!
50      /* true if the Proxy has been set programatically */
51      private boolean applicationSetProxy;  /* false */
52  
53  
54      SocksSocketImpl() {              //하여튼 저러한 필드 + 상위 클래스 필드를 포함한 소켓구현 객체 생성
55          // Nothing needed
56      }


289    void setServerSocket(ServerSocket soc) {
290        this.serverSocket = soc;         //휴~ 이제야 자신의 서버소켓에 세팅하네 -_- ㅎㄷㄷ
291    }


5.자~ 저 위에 2번에서 서버 소켓 생성을 하였으니.. 
 bind(new InetSocketAddress(bindAddr, port), backlog); 이놈을 추적해 봅니다. 좀 깁니다. 정신 단단히 붙잡고 gogo

358    public void More ...bind(SocketAddress endpoint, int backlog) throws IOException {
359        if (isClosed())
360            throw new SocketException("Socket is closed");
361        if (!oldImpl && isBound())
362            throw new SocketException("Already bound");
363        if (endpoint == null)
364            endpoint = new InetSocketAddress(0);
365        if (!(endpoint instanceof InetSocketAddress))
366            throw new IllegalArgumentException("Unsupported address type");
367        InetSocketAddress epoint = (InetSocketAddress) endpoint;
368        if (epoint.isUnresolved())
369            throw new SocketException("Unresolved address");
370        if (backlog < 1)
371          backlog = 50;

5.1자.. 위에까진 매개변수 유효성 처리였습니다. 아래의 시큐리티 매니저는 접속인증등 사용권한을 체크해주고 관리해줍니다.
중요한 메서드는 getImpl().bind() , getImpl().listen() 입니다.  독특한게.. 자신이 아까 생성한 구현체에 일을 떠맡기고
있습니다. (이게 인터페이스 클래스와 구현 클래스의 구분 목적입니다. = 추상화)

구현 객체의 bind() , listen() 을 추적하러 갑니다. 화이팅!! gogo 
참고로 구현객체 클래스는 4번에서 찾아봤지요..! 그때는 멤버 필드와 생성자만 봤었지만!

372        try {
373            SecurityManager security = System.getSecurityManager();
374            if (security != null)
375                security.checkListen(epoint.getPort());
376            getImpl().bind(epoint.getAddress(), epoint.getPort());
377            getImpl().listen(backlog);
378            bound = true;
379        } catch(SecurityException e) {
380            bound = false;
381            throw e;
382        } catch(IOException e) {
383            bound = false;
384            throw e;
385        }
386    }


6. 정신줄 놓지 않기!!! 
여기서 중요한게.. 소켓소켓임플 클래스의 상속 구조입니다. 확인! 
 class SocksSocketImpl extends PlainSocketImpl implements SocksConsts ... PlainSocketImpl을 상속 받습니다. 이름도 평범한 plain입니다.

자,.. 5번에서 추적하려던 소켓소켓임플 클래스의 bind()를 자세히 보면 매개변수가 2개 입니다.
매개변수가 2개인 bind()는 PlainSocketImpl()을 그대로 사용합니다. 그럼으로 아래의 bind()코드는 
PlainSocketImpl 클래스 파일에 정의된 메서드 입니다.

아래에서 NetHooks.beforeTcpBind(fd, address, lport); 는 파고들면 엄청 깊어짐으로 생략합니다.(sun.net 참고)
대신 애초 목적이였던 socketBind(address, lport) 를 열공 해야 합니다.


366    protected synchronized void bind(InetAddress address, int lport)
367        throws IOException
368    {
369       synchronized (fdLock) {  //멀티 스레딩을 대비해서 동기화 처리를 해주고 있습니다.
370            if (!closePending && (socket == null || !socket.isBound())) {
371                NetHooks.beforeTcpBind(fd, address, lport); //넷훅? 이름이 호기심 돋지만.. 유혹에 빠지면 안됨!
372            }
373        }
374        socketBind(address, lport); //너를 쪼개보리라!
375        if (socket != null)
376            socket.setBound();
377        if (serverSocket != null)
378            serverSocket.setBound();
379    }


7. 이런.. PlainSocketImpl 클래스에선 socketBind(매개변수 2개)를 추상 클래스로 선언했습니다. 하위클래스에
   구현이 되었겠군요?  다시 소켓소켓임플 클래스를 찾아봐야 겠습니다.
692    abstract void socketBind(InetAddress address, int port)
693        throws IOException;


****여기서 그만*****


'자바se api > net' 카테고리의 다른 글

네트워크 관련  (0) 2014.01.01
java.net.socket 파고들기1  (0) 2014.01.01
java.net 중 서버 소켓 -> IOCP -> NIO -> NODE JS + 팩토리 패턴  (0) 2014.01.01
by givingsheart 2014. 1. 1. 16:17
클라용 소켓 인터페이스부
서버용 소켓 인터페이스부

소켓 imple <-- 이것도 추상클래스로 빼놔서..

실제 추상화된 단계는
1.abstract class More ...AbstractPlainSocketImpl extends SocketImpl
2.class More ...PlainSocketImpl extends AbstractPlainSocketImpl
3.class More ...SocksSocketImpl extends PlainSocketImpl implements SocksConsts

하여튼.. 자신의 단계에서 가능한 메서드를 정의해두고 나머진 하위 클래스에게 맡겨버림..


1에서 볼만한건.. 클래스 멤버(static) 초기화 부분에서 먼짓을 하고 있는지!

79     static {
80         java.security.AccessController.doPrivileged(
81                   new sun.security.action.LoadLibraryAction("net"));
82     }

또한 create메서드에서 동기화 처리및 , 스트림 여부에 따라 udp 소켓 생성.. 리소스 매니저 사용..등

88     protected synchronized void More ...create(boolean stream) throws IOException {
89         fd = new FileDescriptor();
90         this.stream = stream;
91         if (!stream) {
92             ResourceManager.beforeUdpCreate();
93             try {
94                 socketCreate(false);
95             } catch (IOException ioe) {
96                 ResourceManager.afterUdpClose();
97                 fd = null;
98                 throw ioe;
99             }
100        } else {
101            socketCreate(true);
102        }
103        if (socket != null)
104            socket.setCreated();
105        if (serverSocket != null)
106            serverSocket.setCreated();
107    }

3에서 볼만한건..((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));

117     private int More ...readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
118         int len = data.length;
119         int received = 0;
120         for (int attempts = 0; received < len && attempts < 3; attempts++) {
121             int count;
122             try {
123                 count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
124             } catch (SocketTimeoutException e) {
125                 throw new SocketTimeoutException("Connect timed out");
126             }
127             if (count < 0)
128                 throw new SocketException("Malformed reply from SOCKS server");
129             received += count;
130         }
131         return received;
132     }

여튼 맞는지 모르겟지만,, 브릿지 패턴같음 


51 public
52 class More ...ServerSocket implements java.io.Closeable {
    

55 
56     private boolean created = false;
57     private boolean bound = false;
58     private boolean closed = false;
59     private Object closeLock = new Object();

    
63 
64     private SocketImpl impl;

   
68 
69     private boolean oldImpl = false;

    
75     More ...ServerSocket(SocketImpl impl) {
76         this.impl = impl;
77         impl.setServerSocket(this);
78     }

    

85 
86     public More ...ServerSocket() throws IOException {
87         setImpl();
88     }

    
//팩토리 클래스에서 실제 소켓 구현 클래스 얻고.. 추상 팩토리 패턴;;;
//시큐리티 매니저도.. 아.. 모르겠다..
SocketImpl
SocketImplFactory.createSocketImpl()
setSocketFactory(java.net.SocketImplFactory)
java.lang.SecurityManager.checkListen(int)
126
127    public More ...ServerSocket(int port) throws IOException {
128        this(port, 50, null);
129    }

    

180    public More ...ServerSocket(int port, int backlog) throws IOException {
181        this(port, backlog, null);
182    }


228
229    public More ...ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
230        setImpl();
231        if (port < 0 || port > 0xFFFF)
232            throw new IllegalArgumentException(
233                       "Port value out of range: " + port);
234        if (backlog < 1)
235          backlog = 50;
236        try {
237            bind(new InetSocketAddress(bindAddr, port), backlog);
238        } catch(SecurityException e) {
239            close();
240            throw e;
241        } catch(IOException e) {
242            close();
243            throw e;
244        }
245    }

    

//아래의 AccessController.doPrivileged .. 내가 awt 분석하면서 많이본 코드 조각.. 
//특별한 권한을 부여한다는 건데..  아래보면 reflect를 통해 소켓구현 클래스에..
//정의된 connect메서드를 얻는다.  하여간.. 이코드의 존재 의미를 명확히 모르겠다..

254
255    SocketImpl More ...getImpl() throws SocketException {
256        if (!created)
257            createImpl();
258        return impl;
259    }
260
261    private void More ...checkOldImpl() {
262        if (impl == null)
263            return;
264        // SocketImpl.connect() is a protected method, therefore we need to use
265        // getDeclaredMethod, therefore we need permission to access the member
266        try {
267            AccessController.doPrivileged(
268                new PrivilegedExceptionAction<Void>() {
269                    public Void More ...run() throws NoSuchMethodException {
270                        Class[] cl = new Class[2];
271                        cl[0] = SocketAddress.class;
272                        cl[1] = Integer.TYPE;
273                        impl.getClass().getDeclaredMethod("connect", cl);
274                        return null;
275                    }
276                });
277        } catch (java.security.PrivilegedActionException e) {
278            oldImpl = true;
279        }
280    }
281
282    private void More ...setImpl() {
283        if (factory != null) {
284            impl = factory.createSocketImpl();
285            checkOldImpl();
286        } else {
287            // No need to do a checkOldImpl() here, we know it's an up to date
288            // SocketImpl!
289            impl = new SocksSocketImpl();
290        }
291        if (impl != null)
292            impl.setServerSocket(this);
293    }

 
300
301    void More ...createImpl() throws SocketException {
302        if (impl == null)
303            setImpl();
304        try {
305            impl.create(true);
306            created = true;
307        } catch (IOException e) {
308            throw new SocketException(e.getMessage());
309        }
310    }

328
329    public void More ...bind(SocketAddress endpoint) throws IOException {
330        bind(endpoint, 50);
331    }

    
//유효한 연결인지 체크하고, 시큐리티 검사하고, 바인드 하고 , 바로 리슨을 해주는 걸 확인..

357
358    public void More ...bind(SocketAddress endpoint, int backlog) throws IOException {
359        if (isClosed())
360            throw new SocketException("Socket is closed");
361        if (!oldImpl && isBound())
362            throw new SocketException("Already bound");
363        if (endpoint == null)
364            endpoint = new InetSocketAddress(0);
365        if (!(endpoint instanceof InetSocketAddress))
366            throw new IllegalArgumentException("Unsupported address type");
367        InetSocketAddress epoint = (InetSocketAddress) endpoint;
368        if (epoint.isUnresolved())
369            throw new SocketException("Unresolved address");
370        if (backlog < 1)
371          backlog = 50;
372        try {
373            SecurityManager security = System.getSecurityManager();
374            if (security != null)
375                security.checkListen(epoint.getPort());
376            getImpl().bind(epoint.getAddress(), epoint.getPort());
377            getImpl().listen(backlog);
378            bound = true;
379        } catch(SecurityException e) {
380            bound = false;
381            throw e;
382        } catch(IOException e) {
383            bound = false;
384            throw e;
385        }
386    }

    
398    public InetAddress More ...getInetAddress() {
399        if (!isBound())
400            return null;
401        try {
402            return getImpl().getInetAddress();
403        } catch (SocketException e) {
404            // nothing
405            // If we're bound, the impl has been created
406            // so we shouldn't get here
407        }
408        return null;
409    }

    
421    public int More ...getLocalPort() {
422        if (!isBound())
423            return -1;
424        try {
425            return getImpl().getLocalPort();
426        } catch (SocketException e) {
427            // nothing
428            // If we're bound, the impl has been created
429            // so we shouldn't get here
430        }
431        return -1;
432    }

    
449
450    public SocketAddress More ...getLocalSocketAddress() {
451        if (!isBound())
452            return null;
453        return new InetSocketAddress(getInetAddress(), getLocalPort());
454    }

 
484    public Socket More ...accept() throws IOException {
485        if (isClosed())
486            throw new SocketException("Socket is closed");
487        if (!isBound())
488            throw new SocketException("Socket is not bound yet");
489        Socket s = new Socket((SocketImpl) null);
490        implAccept(s);
491        return s;
492    }

//시큐리티 매니저의 역할에 대해 생각해볼것! (즉 외부인 네트워크를 통한 스트림 연결에대해 인증및, 권한 설정등의 보안 작업)
509
510    protected final void More ...implAccept(Socket s) throws IOException {
511        SocketImpl si = null;
512        try {
513            if (s.impl == null)
514              s.setImpl();
515            else {
516                s.impl.reset();
517            }
518            si = s.impl;
519            s.impl = null;
520            si.address = new InetAddress();
521            si.fd = new FileDescriptor();
522            getImpl().accept(si);
523
524            SecurityManager security = System.getSecurityManager();
525            if (security != null) {
526                security.checkAccept(si.getInetAddress().getHostAddress(),
527                                     si.getPort());
528            }
529        } catch (IOException e) {
530            if (si != null)
531                si.reset();
532            s.impl = si;
533            throw e;
534        } catch (SecurityException e) {
535            if (si != null)
536                si.reset();
537            s.impl = si;
538            throw e;
539        }
540        s.impl = si;
541        s.postAccept();
542    }

556
557    public void More ...close() throws IOException {
558        synchronized(closeLock) {
559            if (isClosed())
560                return;
561            if (created)
562                impl.close();
563            closed = true;
564        }
565    }


582
583    public ServerSocketChannel More ...getChannel() {
584        return null;
585    }

592
593    public boolean More ...isBound() {
594        // Before 1.3 ServerSockets were always bound during creation
595        return bound || oldImpl;
596    }

    

603
604    public boolean More ...isClosed() {
605        synchronized(closeLock) {
606            return closed;
607        }
608    }


625
626    public synchronized void More ...setSoTimeout(int timeout) throws SocketException {
627        if (isClosed())
628            throw new SocketException("Socket is closed");
629        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
630    }

    
639
640    public synchronized int More ...getSoTimeout() throws IOException {
641        if (isClosed())
642            throw new SocketException("Socket is closed");
643        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
644        /* extra type safety */
645        if (o instanceof Integer) {
646            return ((Integer) o).intValue();
647        } else {
648            return 0;
649        }
650    }


687
688    public void More ...setReuseAddress(boolean on) throws SocketException {
689        if (isClosed())
690            throw new SocketException("Socket is closed");
691        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
692    }

    
702
703    public boolean More ...getReuseAddress() throws SocketException {
704        if (isClosed())
705            throw new SocketException("Socket is closed");
706        return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
707    }


714
715    public String More ...toString() {
716        if (!isBound())
717            return "ServerSocket[unbound]";
718        return "ServerSocket[addr=" + impl.getInetAddress() +
719                ",port=" + impl.getPort() +
720                ",localport=" + impl.getLocalPort()  + "]";
721    }
722
723    void More ...setBound() {
724        bound = true;
725    }
726
727    void More ...setCreated() {
728        created = true;
729    }

    
The factory for all server sockets.
733
734    private static SocketImplFactory factory = null;


760
761    public static synchronized void More ...setSocketFactory(SocketImplFactory fac) throws IOException {
762        if (factory != null) {
763            throw new SocketException("factory already defined");
764        }
765        SecurityManager security = System.getSecurityManager();
766        if (security != null) {
767            security.checkSetFactory();
768        }
769        factory = fac;
770    }


806
807     public synchronized void More ...setReceiveBufferSize (int size) throws SocketException {
808        if (!(size > 0)) {
809            throw new IllegalArgumentException("negative receive size");
810        }
811        if (isClosed())
812            throw new SocketException("Socket is closed");
813        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
814    }

828
829    public synchronized int More ...getReceiveBufferSize()
830    throws SocketException{
831        if (isClosed())
832            throw new SocketException("Socket is closed");
833        int result = 0;
834        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
835        if (o instanceof Integer) {
836            result = ((Integer)o).intValue();
837        }
838        return result;
839    }


878
879    public void More ...setPerformancePreferences(int connectionTime,
880                                          int latency,
881                                          int bandwidth)
882    {
883        /* Not implemented yet */
884    }
885
886}


'자바se api > net' 카테고리의 다른 글

네트워크 관련  (0) 2014.01.01
java.net.socket 파고들기2  (0) 2014.01.01
java.net 중 서버 소켓 -> IOCP -> NIO -> NODE JS + 팩토리 패턴  (0) 2014.01.01
by givingsheart 2014. 1. 1. 16:16


java.net.serversocket 

이 클래스는 서버 소켓을 구현합니다. 서버 소켓은, 네트워크 경유로 요구가 보내져 오는 것을 기다립니다. 이것은, 그 요구에 근거해 몇개의 조작을 실행합니다. 그 후, 경우에 따라서는 요구 바탕으로 결과를 돌려줍니다.  

서버 소켓의 실제의 처리는,SocketImpl 클래스의 인스턴스에 의해 실행됩니다. 어플리케이션은, 소켓 구현을 작성하는 소켓 팩토리를 변경하는 것으로, 로컬 방화벽(fire wall)에 적절한 소켓을 작성하도록(듯이) 어플리케이션 자체를 구성할 수가 있습니다.

도입된 버젼:
JDK1. 0
관련 항목:
SocketImpl , setSocketFactory(java.net.SocketImplFactory) , ServerSocketChannel

=>서버 소켓의 accecpt() 메서드는 인터페이스 클래스(상위 클래스) 구현 클래스(하위클래스)
로 구성되었다(왜냐묜.. 소스코드 로직 유출 막을라고;; 사실 클라가 알 필요도 없고.. 추상화)

imple 클래스 선언부만 보면 아주 심플함.. 서버 소켓도 될수 있고, 일반 소켓도 될수
있고.. 게다가 인터페이스(메서드)의 경우.. 초 단순.. create , connect, accept , bind,
listen, getInputStream, getOutputStream, close .. 물론 다른 메서드도 있지만.. 초심플
아닌가??  


44 public abstract class More ...SocketImpl implements SocketOptions {
    
The actual Socket object.
47 
48     Socket socket = null;
49     ServerSocket serverSocket = null;

54     protected FileDescriptor fd;

59     protected InetAddress address;


64     protected int port;

69     protected int localport;


79     protected abstract void More ...create(boolean stream) throws IOException;

89     protected abstract void More ...connect(String host, int port) throws IOException;

99     protected abstract void More ...connect(InetAddress address, int port) throws IOException;

112    protected abstract void More ...connect(SocketAddress address, int timeout) throws IOException;

121    protected abstract void More ...bind(InetAddress host, int port) throws IOException;

132    protected abstract void More ...listen(int backlog) throws IOException;

141    protected abstract void More ...accept(SocketImpl s) throws IOException;

150    protected abstract InputStream More ...getInputStream() throws IOException;

159    protected abstract OutputStream More ...getOutputStream() throws IOException;

170    protected abstract int More ...available() throws IOException;

177    protected abstract void More ...close() throws IOException;

194    protected void More ...shutdownInput() throws IOException {
195      throw new IOException("Method not implemented!");
196    }

214    protected void More ...shutdownOutput() throws IOException {
215      throw new IOException("Method not implemented!");
216    }

224    protected FileDescriptor More ...getFileDescriptor() {
225        return fd;
226    }

234    protected InetAddress More ...getInetAddress() {
235        return address;
236    }

244    protected int More ...getPort() {
245        return port;
246    }

257    protected boolean More ...supportsUrgentData () {
258        return false; // must be overridden in sub-class
259    }

269    protected abstract void More ...sendUrgentData (int data) throws IOException;

277    protected int More ...getLocalPort() {
278        return localport;
279    }
280
281    void More ...setSocket(Socket soc) {
282        this.socket = soc;
283    }
284
285    Socket More ...getSocket() {
286        return socket;
287    }
288
289    void More ...setServerSocket(ServerSocket soc) {
290        this.serverSocket = soc;
291    }
292
293    ServerSocket More ...getServerSocket() {
294        return serverSocket;
295    }

302    public String More ...toString() {
303        return "Socket[addr=" + getInetAddress() +
304            ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
305    }
306
307    void More ...reset() throws IOException {
308        address = null;
309        port = 0;
310        localport = 0;
311    }

350
351    protected void More ...setPerformancePreferences(int connectionTime,
352                                          int latency,
353                                          int bandwidth)
354    {
355        /* Not implemented yet */
356    }
357}


***************************************************************

소켓의 인풋스트림에 뭔가 데이터가 들어왔을때.. 통지 해주는 객체와 내가 리스너(콜백메서드)
를 정의해서 붙여주는 처리는 아닌가? 
그냥 while()문에서 0.001초마다 메세지 들어와있나 확인해야 하나?

그리고 iocp개념, non blocking 통신은.. 아..................


iocp 관련 논의 (자바에선 어찌하는지 찾아봐야함)

http://www.gamecodi.com/board/zboard-id-GAMECODI_Talkdev-no-1607-z-14.htm

(추가)
다중 접속 처리를 위해 -> 소켓당 여러 프로세스 배정 -> 조금 더 가벼운 멀티 스레드 할당 ->
스레드 풀의 개념(스레드 생성,소멸 시간 절약해 재사용) -> 메모리 문제, 성능 문제등이 발생을
한다. 동기화 IO의 한계가 존재함으로.. 비동기 IO인 NIO패키지로 해결을 하며, 고속의 성능이
필요할 경운.. 자바가 아닌 C++ 등으로 구현하는 것이 현명할 것이다.

(추가)
NODE JS 를 공부하게 되었다. 싱글 스레드 서버로서 파일등 I/O의 경우는 비동기로 처리한다.(이벤트
큐와 리스너와 콜백)

NODE의 경우 싱글 스레드로서, 동기화의 문제 , 멀티스레드 문제를 극복하게 하지만, 싱글 스레드 임으로
서버 컴퓨터(멀티코어)의 능력을 제대로 쓰기 위해서는 클러스터 모듈을 사용해서 분산 처리해야 한다.
또한 서버단에서 CPU 연산이 많은 작업을 하게 되면, 비동기적 프로그래밍을 제대로 구현하지 못할 경우..
 병목 현상이 발생한다. 서버는 참으로 어렵고 크리티컬한 분야이다.


게임서버 관련 쟁점
http://cafe.naver.com/jzsdn/23094?social=1

(추가)
게임 서버는.. 다중 접속, 빠른 처리, 지역 분할과 동기화란.. 너무나 많은 이슈가 걸려있다.

서버 동작 방식 결정하게끔 생성하는 팩토리 메서드 패턴?
http://cafe.naver.com/gogoxna/934

(추가)
일단 팩토리 패턴이란.. 객체 생성 과정을 추상화 하기 위한 개념이다. GETINSTANCE ("객체 이름")
서로 다른 모듈(또는 시스템)간에는 서로를 구체적으로 몰라야 유연성(루즈커플링)이 높아진다.
유연성이 높아야, 변경에 취약하지가 않게 된다.


'자바se api > net' 카테고리의 다른 글

네트워크 관련  (0) 2014.01.01
java.net.socket 파고들기2  (0) 2014.01.01
java.net.socket 파고들기1  (0) 2014.01.01
by givingsheart 2014. 1. 1. 16:14
| 1 2 |