스윙책에서 이벤트처리 스레드를 강조했기에 (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