KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > debugger > DebuggerManager


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.debugger;
21
22 import java.beans.*;
23 import java.util.*;
24 import java.util.HashMap JavaDoc;
25
26 import org.openide.util.Cancellable;
27 import org.openide.util.Task;
28
29 import org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider;
30 import org.netbeans.spi.debugger.DelegatingSessionProvider;
31 import org.netbeans.spi.debugger.DebuggerEngineProvider;
32 import org.netbeans.spi.debugger.SessionProvider;
33
34
35 /**
36  * The root class of Debugger APIs. DebuggerManager manages list of
37  * {@link org.netbeans.api.debugger.Session}s,
38  * {@link org.netbeans.api.debugger.Breakpoint}s and
39  * {@link org.netbeans.api.debugger.Watch}es.
40  *
41  *
42  * <p><br><table border="1" cellpadding="3" cellspacing="0" width="100%">
43  * <tbody><tr bgcolor="#ccccff">
44  * <td colspan="2"><font size="+2"><b>Description </b></font></td>
45  * </tr><tr><td align="left" valign="top" width="1%"><font size="+1">
46  * <b>Functionality</b></font></td><td>
47  *
48  * <b>Start & finish debugging:</b>
49  * DebuggerManager manages a process of starting a new debugging (
50  * {@link #startDebugging}). It cooperates with all installed
51  * {@link org.netbeans.spi.debugger.DebuggerEngineProvider}s to create a new
52  * {@link org.netbeans.api.debugger.Session} (or Sessions) and a new
53  * {@link org.netbeans.api.debugger.DebuggerEngine} (or Engines).
54  * It supports kill all sessions too ({@link #finishAllSessions}).
55  *
56  * <br><br>
57  * <b>Sessions management:</b>
58  * DebuggerManager keeps list of all
59  * {@link org.netbeans.api.debugger.Session}s ({@link #getSessions}),
60  * and manages current session ({@link #getCurrentSession},
61  * {@link #setCurrentSession}).
62  *
63  * <br><br>
64  * <b>Engine management:</b>
65  * DebuggerManager provides current engine ({@link #getCurrentEngine}).
66  * Current engine is derivated from current session. So,
67  * <i>
68  * debuggerManager.getCurrentEngine () == debuggerManager.
69  * getCurrentSession.getCurrentEngine ()
70  * </i>
71  * should be always true.
72  *
73  * <br><br>
74  * <b>Breakpoints management:</b>
75  * DebuggerManager keeps list of all shared breakpoints
76  * ({@link #getBreakpoints}).
77  * Breakpoint can be added ({@link #addBreakpoint}) and removed
78  * ({@link #removeBreakpoint}).
79  *
80  * <br><br>
81  * <b>Watches management:</b>
82  * DebuggerManager keeps list of all shared watches ({@link #getWatches}).
83  * Watch can be created & added ({@link #createWatch}).
84  *
85  * <br><br>
86  * <b>Support for listening:</b>
87  * DebuggerManager propagates all changes to two type of listeners - general
88  * {@link java.beans.PropertyChangeListener} and specific
89  * {@link org.netbeans.api.debugger.DebuggerManagerListener}.
90  *
91  * <br>
92  * </td></tr><tr><td align="left" valign="top" width="1%"><font size="+1">
93  * <b>Clinents / Providers</b></font></td><td>
94  *
95  * DebuggerCore module should be the only one provider of this abstract class.
96  * This class should be called from debugger plug-in modules and from debugger
97  * UI modules.
98  *
99  * <br>
100  * </td></tr><tr><td align="left" valign="top" width="1%"><font size="+1">
101  * <b>Lifecycle</b></font></td><td>
102  *
103  * The only one instance of DebuggerManager should exist, and it should be
104  * created in {@link #getDebuggerManager} method.
105  *
106  * </td></tr><tr><td align="left" valign="top" width="1%"><font size="+1">
107  * <b>Evolution</b></font></td><td>
108  *
109  * No method should be removed from this class, but some functionality can
110  * be added.
111  *
112  * </td></tr></tbody></table>
113  *
114  * @author Jan Jancura
115  */

116 public final class DebuggerManager {
117     
118     // TODO: deprecate all these properties. They are useless, since there are
119
// dedicated methods in DebuggerManagerListener
120

121     // OR: Remove DebuggerManagerListener and use just the properties.
122
// - probably not possible because of initBreakpoints() method.
123

124     /** Name of property for the set of breakpoints in the system. */
125     public static final String JavaDoc PROP_BREAKPOINTS_INIT = "breakpointsInit"; // NOI18N
126

127     /** Name of property for the set of breakpoints in the system. */
128     public static final String JavaDoc PROP_BREAKPOINTS = "breakpoints"; // NOI18N
129

130     /** Name of property for current debugger engine. */
131     public static final String JavaDoc PROP_CURRENT_ENGINE = "currentEngine";
132
133     /** Name of property for current debugger session. */
134     public static final String JavaDoc PROP_CURRENT_SESSION = "currentSession";
135     
136     /** Name of property for set of running debugger sessions. */
137     public static final String JavaDoc PROP_SESSIONS = "sessions";
138     
139     /** Name of property for set of running debugger engines. */
140     public static final String JavaDoc PROP_DEBUGGER_ENGINES = "debuggerEngines";
141
142     /** Name of property for the set of watches in the system. */
143     public static final String JavaDoc PROP_WATCHES = "watches"; // NOI18N
144

145     /** Name of property for the set of watches in the system. */
146     public static final String JavaDoc PROP_WATCHES_INIT = "watchesInit"; // NOI18N
147

148     
149     private static DebuggerManager debuggerManager;
150     private Session currentSession;
151     private DebuggerEngine currentEngine;
152     private List sessions = new ArrayList();
153     private Set engines = new HashSet ();
154     private Vector breakpoints = new Vector ();
155     private boolean breakpointsInitializing = false;
156     private boolean breakpointsInitialized = false;
157     private Vector watches = new Vector ();
158     private boolean watchesInitialized = false;
159     private SessionListener sessionListener = new SessionListener ();
160     private Vector listeners = new Vector ();
161     private HashMap JavaDoc listenersMap = new HashMap JavaDoc ();
162     private ActionsManager actionsManager = null;
163     
164     private Lookup lookup = new Lookup.MetaInf (null);
165     
166     
167     /**
168      * Returns default instance of DebuggerManager.
169      *
170      * @return default instance of DebuggerManager
171      */

172     public static synchronized DebuggerManager getDebuggerManager () {
173         if (debuggerManager == null)
174             debuggerManager = new DebuggerManager ();
175         return debuggerManager;
176     }
177
178     /**
179      * Creates a new instance of DebuggerManager.
180      * It's called from a synchronized block, do not call any foreign code from here.
181      */

182     private DebuggerManager () {
183     }
184
185
186     public synchronized ActionsManager getActionsManager () {
187         if (actionsManager == null)
188             actionsManager = new ActionsManager (lookup);
189         return actionsManager;
190     }
191     
192     
193     // lookup management .............................................
194

195     /**
196      * Returns list of services of given type from given folder.
197      *
198      * @param service a type of service to look for
199      * @return list of services of given type
200      */

201     public List lookup (String JavaDoc folder, Class JavaDoc service) {
202         return lookup.lookup (folder, service);
203     }
204     
205     /**
206      * Returns one service of given type from given folder.
207      *
208      * @param service a type of service to look for
209      * @return ne service of given type
210      */

211     public Object JavaDoc lookupFirst (String JavaDoc folder, Class JavaDoc service) {
212         return lookup.lookupFirst (folder, service);
213     }
214     
215     
216     // session / engine management .............................................
217

218     /**
219      * Start a new debugging for given
220      * {@link org.netbeans.api.debugger.DebuggerInfo}. DebuggerInfo provides
221      * information needed to start new debugging. DebuggerManager finds
222      * all {@link org.netbeans.spi.debugger.SessionProvider}s and
223      * {@link org.netbeans.spi.debugger.DelegatingSessionProvider}s
224      * installed for given DebuggerInfo, and creates a new
225      * {@link Session}(s).
226      * After that it looks for all
227      * {@link org.netbeans.spi.debugger.DebuggerEngineProvider}s and
228      * {@link org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider}s
229      * installed for Session, and crates a new
230      * {@link DebuggerEngine}(s).
231      * <br>
232      * If the implementation of ACTION_START providers support cancellation (implements {@link Cancellable}),
233      * this startup sequence can be canceled via Thread.interrupt() while
234      * startDebugging() method is waiting for the action providers.
235      *
236      * @param info debugger startup info
237      * @return DebuggerEngines started for given info
238      */

239     public DebuggerEngine[] startDebugging (DebuggerInfo info) {
240         //S ystem.out.println("@StartDebugging info: " + info);
241

242         // init sessions
243
ArrayList sessionProviders = new ArrayList ();
244         ArrayList engines = new ArrayList ();
245         Lookup l = info.getLookup ();
246         Lookup l2 = info.getLookup ();
247         sessionProviders.addAll (
248             l.lookup (
249                 null,
250                 SessionProvider.class
251             )
252         );
253         sessionProviders.addAll (
254             l.lookup (
255                 null,
256                 DelegatingSessionProvider.class
257             )
258         );
259         Session sessionToStart = null;
260         int i, k = sessionProviders.size ();
261         for (i = 0; i < k; i++) {
262             Session s = null;
263             if (sessionProviders.get (i) instanceof DelegatingSessionProvider) {
264                 s = ((DelegatingSessionProvider) sessionProviders.get (i)).
265                     getSession (info);
266                 l = new Lookup.Compound (
267                     l,
268                     s.privateLookup
269                 );
270                 //S ystem.out.println("@ StartDebugging DelegaingSession: " + s);
271
} else {
272                 SessionProvider sp = (SessionProvider) sessionProviders.get (i);
273                 s = new Session (
274                     sp.getSessionName (),
275                     sp.getLocationName (),
276                     sp.getTypeID (),
277                     sp.getServices (),
278                     l
279                 );
280                 sessionToStart = s;
281                 l = s.getLookup ();
282                 l2 = s.getLookup ();
283                 addSession (s);
284                 //S ystem.out.println("@ StartDebugging new Session: " + s);
285
}
286             
287             // init DebuggerEngines
288
ArrayList engineProviders = new ArrayList ();
289             engineProviders.addAll (
290                 l2.lookup (null, DebuggerEngineProvider.class)
291             );
292             engineProviders.addAll (
293                 l2.lookup (null, DelegatingDebuggerEngineProvider.class)
294             );
295             int j, jj = engineProviders.size ();
296             for (j = 0; j < jj; j++) {
297                 DebuggerEngine engine = null;
298                 String JavaDoc[] languages = null;
299                 if (engineProviders.get (j) instanceof DebuggerEngineProvider) {
300                     DebuggerEngineProvider ep = (DebuggerEngineProvider)
301                         engineProviders.get (j);
302                     Object JavaDoc[] services = ep.getServices ();
303                     engine = new DebuggerEngine (
304                         ((DebuggerEngineProvider) engineProviders.get (j)).
305                             getEngineTypeID (),
306                         s,
307                         services,
308                         l
309                     );
310                     languages = ep.getLanguages ();
311                     ep.setDestructor (engine.new Destructor ());
312                     engines.add (engine);
313                     //S ystem.out.println("@ StartDebugging new Engine: " + engine);
314
} else {
315                     DelegatingDebuggerEngineProvider dep =
316                         (DelegatingDebuggerEngineProvider)
317                         engineProviders.get (j);
318                     languages = dep.getLanguages ();
319                     engine = dep.getEngine ();
320                     dep.setDestructor (engine.new Destructor ());
321                     //S ystem.out.println("@ StartDebugging DelegatingEngine: " + engine);
322
}
323                 int w, ww = languages.length;
324                 for (w = 0; w < ww; w++)
325                     s.addLanguage (languages [w], engine);
326             }
327         }
328         
329         k = engines.size ();
330         for (i = 0; i < k; i++) {
331             if (Thread.interrupted()) {
332                 break;
333             }
334             Task task = ((DebuggerEngine) engines.get (i)).getActionsManager ().postAction
335                 (ActionsManager.ACTION_START);
336             if (task instanceof Cancellable) {
337                 try {
338                     task.waitFinished(0);
339                 } catch (InterruptedException JavaDoc iex) {
340                     if (((Cancellable) task).cancel()) {
341                         break;
342                     } else {
343                         task.waitFinished();
344                     }
345                 }
346             } else {
347                 task.waitFinished();
348             }
349         }
350         if (i < k) { // It was canceled
351
int n = i + 1;
352             for (i = 0; i < k; i++) {
353                 ActionsManager am = ((DebuggerEngine) engines.get (i)).getActionsManager();
354                 if (i < (n - 1)) am.postAction(ActionsManager.ACTION_KILL); // kill the started engines
355
am.destroy();
356             }
357             return new DebuggerEngine[] {};
358         }
359         
360         if (sessionToStart != null)
361             setCurrentSession (sessionToStart);
362         
363         DebuggerEngine[] des = new DebuggerEngine [engines.size ()];
364         return (DebuggerEngine[]) engines.toArray (des);
365     }
366
367     /**
368      * Kills all {@link org.netbeans.api.debugger.Session}s and
369      * {@link org.netbeans.api.debugger.DebuggerEngine}s.
370      */

371     public void finishAllSessions () {
372         Session[] ds = getSessions ();
373         
374         if (ds.length == 0) return;
375
376         // finish all non persistent sessions
377
int i, k = ds.length;
378         for (i = 0; i < k; i++)
379             ds [i].getCurrentEngine ().getActionsManager ().
380                 doAction (ActionsManager.ACTION_KILL);
381     }
382     
383     /**
384      * Returns current debugger session or <code>null</code>.
385      *
386      * @return current debugger session or <code>null</code>
387      */

388     public Session getCurrentSession () {
389         return currentSession;
390     }
391
392     /**
393      * Sets current debugger session.
394      *
395      * @param session a session to be current
396      */

397     public void setCurrentSession (Session session) {
398         Session oldSession;
399         Session newSession;
400         DebuggerEngine oldEngine;
401         DebuggerEngine newEngine;
402         synchronized (sessions) {
403             // 1) check if the session is registerred
404
if (session != null) {
405                 int i, k = sessions.size();
406                 for (i = 0; i < k; i++)
407                     if (session == sessions.get(i)) break;
408                 if (i == k)
409                     return;
410             }
411             
412             // fire all changes
413
oldSession = getCurrentSession ();
414             if (session == oldSession) return;
415             currentSession = newSession = session;
416             
417             oldEngine = currentEngine;
418             newEngine = null;
419             if (getCurrentSession () != null)
420                 newEngine = getCurrentSession ().getCurrentEngine ();
421             currentEngine = newEngine;
422         }
423         if (oldEngine != newEngine) {
424             firePropertyChange (PROP_CURRENT_ENGINE, oldEngine, newEngine);
425         }
426         firePropertyChange (PROP_CURRENT_SESSION, oldSession, newSession);
427     }
428
429     /**
430      * Returns set of running debugger sessions.
431      *
432      * @return set of running debugger sessions
433      */

434     public Session[] getSessions () {
435         synchronized (sessions) {
436             return (Session[]) sessions.toArray(new Session[0]);
437         }
438     }
439
440     /**
441      * Returns set of running debugger engines.
442      *
443      * @return set of running debugger engines
444      */

445     public DebuggerEngine[] getDebuggerEngines () {
446         synchronized (engines) {
447             return (DebuggerEngine[]) engines.toArray (new DebuggerEngine [engines.size ()]);
448         }
449     }
450     
451     /**
452      * Returns current debugger engine or <code>null</code>.
453      *
454      * @return current debugger engine or <code>null</code>
455      */

456     public DebuggerEngine getCurrentEngine () {
457         return currentEngine;
458     }
459
460     
461     // breakpoints management ..................................................
462

463     /**
464      * Adds a new breakpoint.
465      *
466      * @param breakpoint a new breakpoint
467      */

468     public void addBreakpoint (
469         Breakpoint breakpoint
470     ) {
471         if (initBreakpoints (breakpoint)) {
472             breakpoints.addElement (breakpoint);
473             fireBreakpointCreated (breakpoint, null);
474         }
475     }
476     
477     /**
478      * Removes breakpoint.
479      *
480      * @param breakpoint a breakpoint to be removed
481      */

482     public void removeBreakpoint (
483         Breakpoint breakpoint
484     ) {
485         initBreakpoints ();
486         breakpoints.removeElement (breakpoint);
487         breakpoint.disposeOut ();
488         fireBreakpointRemoved (breakpoint);
489     }
490
491     /**
492      * Gets all registered breakpoints.
493      *
494      * @return all breakpoints
495      */

496     public Breakpoint[] getBreakpoints () {
497         initBreakpoints ();
498         return (Breakpoint[]) breakpoints.toArray(new Breakpoint[0]);
499     }
500
501     
502     // watches management ......................................................
503

504     /**
505      * Creates a watch with its expression set to an initial value.
506      * Also allows creation of a hidden watch (not presented to the user),
507      * for example for internal use in the editor to obtain values of variables
508      * under the mouse pointer.
509      *
510      * @param expr expression to watch for (the format is the responsibility
511      * of the debugger plug-in implementation, but it is typically
512      * a variable name).
513      * @return the new watch
514      */

515     public Watch createWatch (String JavaDoc expr) {
516         initWatches ();
517         Watch w = new Watch (expr);
518         watches.addElement (w);
519         fireWatchCreated (w);
520         return w;
521     }
522
523     /**
524     * Gets all shared watches in the system.
525     *
526     * @return all watches
527     */

528     public Watch[] getWatches () {
529         initWatches ();
530         return (Watch[]) watches.toArray(new Watch[0]);
531     }
532
533     /**
534      * Removes all watches from the system.
535      */

536     public void removeAllWatches () {
537         initWatches ();
538         Vector v = (Vector) watches.clone ();
539         int i, k = v.size ();
540         for (i = k - 1; i >= 0; i--)
541             ((Watch) v.elementAt (i)).remove ();
542     }
543
544     /**
545     * Removes watch.
546     *
547     * @param w watch to be removed
548     */

549     void removeWatch (Watch w) {
550         initWatches ();
551         watches.removeElement (w);
552         fireWatchRemoved (w);
553     }
554
555     
556     // listenersMap ...............................................................
557

558     
559     /**
560     * Fires property change.
561     */

562     private void firePropertyChange (String JavaDoc name, Object JavaDoc o, Object JavaDoc n) {
563         initDebuggerManagerListeners ();
564         Vector l = (Vector) listeners.clone ();
565         Vector l1;
566         synchronized (listenersMap) {
567             l1 = (Vector) listenersMap.get (name);
568             if (l1 != null)
569                 l1 = (Vector) l1.clone ();
570         }
571         PropertyChangeEvent ev = new PropertyChangeEvent (
572             this, name, o, n
573         );
574         int i, k = l.size ();
575         for (i = 0; i < k; i++)
576             ((DebuggerManagerListener)l.elementAt (i)).propertyChange (ev);
577         if (l1 != null) {
578             k = l1.size ();
579             for (i = 0; i < k; i++)
580                 ((DebuggerManagerListener)l1.elementAt (i)).propertyChange (ev);
581         }
582     }
583
584     /**
585     * This listener notificates about changes of breakpoints, watches and threads.
586     *
587     * @param l listener object.
588     */

589     public void addDebuggerListener (DebuggerManagerListener l) {
590         listeners.addElement (l);
591     }
592
593     /**
594     * Removes debugger listener.
595     *
596     * @param l listener object.
597     */

598     public void removeDebuggerListener (DebuggerManagerListener l) {
599         listeners.removeElement (l);
600     }
601
602     /**
603      * Add a debuggerManager listener to changes of watches and breakpoints.
604      *
605      * @param propertyName a name of property to listen on
606      * @param l the debuggerManager listener to add
607      */

608     public void addDebuggerListener (
609         String JavaDoc propertyName,
610         DebuggerManagerListener l
611     ) {
612         synchronized (listenersMap) {
613             Vector listeners = (Vector) listenersMap.get (propertyName);
614             if (listeners == null) {
615                 listeners = new Vector ();
616                 listenersMap.put (propertyName, listeners);
617             }
618             listeners.addElement (l);
619         }
620     }
621
622     /**
623      * Remove a debuggerManager listener to changes of watches and breakpoints.
624      *
625      * @param propertyName a name of property to listen on
626      * @param l the debuggerManager listener to remove
627      */

628     public void removeDebuggerListener (
629         String JavaDoc propertyName,
630         DebuggerManagerListener l
631     ) {
632         synchronized (listenersMap) {
633             Vector listeners = (Vector) listenersMap.get (propertyName);
634             if (listeners == null) return;
635             listeners.removeElement (l);
636             if (listeners.size () == 0)
637                 listenersMap.remove (propertyName);
638         }
639     }
640
641     /**
642      * Notifies registered listeners about a change.
643      * Notifies {@link #listeners registered listeners} that a breakpoint
644      * {@link DebuggerManagerListener#breakpointAdded was added}
645      * and its properties
646      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
647      * were changed.
648      *
649      * @param breakpoint a breakpoint that was created
650      */

651     private void fireBreakpointCreated (final Breakpoint breakpoint, final DebuggerManagerListener originatingListener) {
652         initDebuggerManagerListeners ();
653         PropertyChangeEvent ev = new PropertyChangeEvent (
654             this, PROP_BREAKPOINTS, null, null
655         );
656         
657         Vector l = (Vector) listeners.clone ();
658         int i, k = l.size ();
659         for (i = 0; i < k; i++) {
660             DebuggerManagerListener dl = (DebuggerManagerListener) l.elementAt (i);
661             if (dl != originatingListener) {
662                 dl.breakpointAdded (breakpoint);
663                 dl.propertyChange (ev);
664             }
665         }
666         
667         Vector l1;
668         synchronized (listenersMap) {
669             l1 = (Vector) listenersMap.get (PROP_BREAKPOINTS);
670             if (l1 != null) {
671                 l1 = (Vector) l1.clone ();
672             }
673         }
674         if (l1 != null) {
675             k = l1.size ();
676             for (i = 0; i < k; i++) {
677                 DebuggerManagerListener dl = (DebuggerManagerListener) l1.elementAt (i);
678                 if (dl != originatingListener) {
679                     dl.breakpointAdded (breakpoint);
680                     dl.propertyChange (ev);
681                 }
682             }
683         }
684     }
685
686     /**
687      * Notifies registered listenersMap about a change.
688      * Notifies {@link #listeners registered listenersMap} that a breakpoint
689      * {@link DebuggerManagerListener#breakpointRemoved was removed}
690      * and its properties
691      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
692      * were changed.
693      *
694      * @param breakpoint a breakpoint that was removed
695      */

696     private void fireBreakpointRemoved (final Breakpoint breakpoint) {
697         initDebuggerManagerListeners ();
698         PropertyChangeEvent ev = new PropertyChangeEvent (
699             this, PROP_BREAKPOINTS, null, null
700         );
701
702         Vector l = (Vector) listeners.clone ();
703         int i, k = l.size ();
704         for (i = 0; i < k; i++) {
705             ((DebuggerManagerListener) l.elementAt (i)).breakpointRemoved
706                 (breakpoint);
707             ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
708         }
709         
710         Vector l1;
711         synchronized (listenersMap) {
712             l1 = (Vector) listenersMap.get (PROP_BREAKPOINTS);
713             if (l1 != null) {
714                 l1 = (Vector) l1.clone ();
715             }
716         }
717         if (l1 != null) {
718             k = l1.size ();
719             for (i = 0; i < k; i++) {
720                 ((DebuggerManagerListener) l1.elementAt (i)).breakpointRemoved
721                     (breakpoint);
722                 ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
723             }
724         }
725     }
726
727     private void initBreakpoints () {
728         initBreakpoints(null);
729     }
730     
731     private List createdBreakpoints;
732     
733     /**
734      * @param newBreakpoint a breakpoint that is to be added if the breakpoints are not yet initialized.
735      * @return true if the breakpoints were successfully initialized.
736      */

737     private boolean initBreakpoints(Breakpoint newBreakpoint) {
738         // All is under the lock, including DebuggerManagerListener.initBreakpoints()
739
// and DebuggerManagerListener.propertyChange(..PROP_BREAKPOINTS_INIT..) calls.
740
// Clients should return the breakpoints via that listener, not add them
741
// directly. Therefore this should not lead to deadlock...
742
Map JavaDoc originatingListeners;
743         synchronized (breakpoints) {
744             if (breakpointsInitialized) return true;
745             if (breakpointsInitializing) {
746                 if (newBreakpoint != null) {
747                     // Someone is trying to add new breakpoints during initialization process.
748
// We must permit that doue to historical reasons - see web/jspdebug/src/org/netbeans/modules/web/debug/breakpoints/JspLineBreakpoint.java
749
createdBreakpoints.add(newBreakpoint);
750                     return false;
751                 }
752                 throw new IllegalStateException JavaDoc("Breakpoints not yet initialized and tried to initialize again...");
753             }
754             breakpointsInitializing = true;
755             try {
756                 initDebuggerManagerListeners ();
757
758                 createdBreakpoints = new ArrayList();
759                 originatingListeners = new HashMap JavaDoc();
760
761                 Vector l = (Vector) listeners.clone ();
762                 int i, k = l.size ();
763                 for (i = 0; i < k; i++) {
764                     DebuggerManagerListener dl = (DebuggerManagerListener) l.elementAt (i);
765                     Breakpoint[] breakpoints = dl.initBreakpoints();
766                     createdBreakpoints.addAll (Arrays.asList (breakpoints));
767                     for (int j = 0; j < breakpoints.length; j++) {
768                         originatingListeners.put(breakpoints[j], dl);
769                     }
770                 }
771
772                 Vector l1;
773                 synchronized (listenersMap) {
774                     l1 = (Vector) listenersMap.get (PROP_BREAKPOINTS_INIT);
775                     if (l1 != null) {
776                         l1 = (Vector) l1.clone ();
777                     }
778                 }
779                 if (l1 != null) {
780                     k = l1.size ();
781                     for (i = 0; i < k; i++) {
782                         DebuggerManagerListener dl = (DebuggerManagerListener) l1.elementAt (i);
783                         Breakpoint[] breakpoints = dl.initBreakpoints();
784                         createdBreakpoints.addAll (Arrays.asList (breakpoints));
785                         for (int j = 0; j < breakpoints.length; j++) {
786                             originatingListeners.put(breakpoints[j], dl);
787                         }
788                     }
789                 }
790
791                 breakpoints.addAll(createdBreakpoints);
792             } finally {
793                 breakpointsInitializing = false;
794             }
795             breakpointsInitialized = true;
796         }
797         int k = createdBreakpoints.size ();
798         for (int i = 0; i < k; i++) {
799             Breakpoint bp = (Breakpoint) createdBreakpoints.get (i);
800             fireBreakpointCreated (bp, (DebuggerManagerListener) originatingListeners.get(bp));
801         }
802         createdBreakpoints = null;
803         return true;
804     }
805
806     /**
807      * Notifies registered listeners about a change.
808      * Notifies {@link #listeners registered listeners} that a watch
809      * {@link DebuggerManagerListener#watchAdded was added}
810      * and its properties
811      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
812      * were changed.
813      *
814      * @param watch a watch that was created
815      */

816     private void fireWatchCreated (final Watch watch) {
817         initDebuggerManagerListeners ();
818         PropertyChangeEvent ev = new PropertyChangeEvent (
819             this, PROP_WATCHES, null, null
820         );
821
822         Vector l = (Vector) listeners.clone ();
823         int i, k = l.size ();
824         for (i = 0; i < k; i++) {
825             ((DebuggerManagerListener) l.elementAt (i)).watchAdded
826                 (watch);
827             ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
828         }
829
830         Vector l1;
831         synchronized (listenersMap) {
832             l1 = (Vector) listenersMap.get (PROP_WATCHES);
833             if (l1 != null) {
834                 l1 = (Vector) l1.clone ();
835             }
836         }
837         if (l1 != null) {
838             k = l1.size ();
839             for (i = 0; i < k; i++) {
840                 ((DebuggerManagerListener) l1.elementAt (i)).watchAdded
841                     (watch);
842                 ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
843             }
844         }
845     }
846
847     /**
848      * Notifies registered listeners about a change.
849      * Notifies {@link #listeners registered listeners} that a watch
850      * {@link DebuggerManagerListener#watchRemoved was removed}
851      * and its properties
852      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
853      * were changed.
854      *
855      * @param watch a watch that was removed
856      */

857     private void fireWatchRemoved (final Watch watch) {
858         initDebuggerManagerListeners ();
859         PropertyChangeEvent ev = new PropertyChangeEvent (
860             this, PROP_WATCHES, null, null
861         );
862
863         Vector l = (Vector) listeners.clone ();
864         int i, k = l.size ();
865         for (i = 0; i < k; i++) {
866             ((DebuggerManagerListener) l.elementAt (i)).watchRemoved
867                 (watch);
868             // TODO: fix nonsense double firing
869
((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
870         }
871
872         Vector l1;
873         synchronized (listenersMap) {
874             l1 = (Vector) listenersMap.get (PROP_WATCHES);
875             if (l1 != null) {
876                 l1 = (Vector) l1.clone ();
877             }
878         }
879         if (l1 != null) {
880             k = l1.size ();
881             for (i = 0; i < k; i++) {
882                 ((DebuggerManagerListener) l1.elementAt (i)).watchRemoved
883                     (watch);
884                 // TODO: fix nonsense double firing
885
((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
886             }
887         }
888     }
889
890     private void initWatches () {
891         synchronized (watches) {
892             if (watchesInitialized) return ;
893             watchesInitialized = true;
894         }
895         // The rest must not be synchronized, since initWatches() does call createWatch()
896
PropertyChangeEvent ev = new PropertyChangeEvent (
897             this, PROP_WATCHES_INIT, null, null
898         );
899         
900         Vector l = (Vector) listeners.clone ();
901         int i, k = l.size ();
902         for (i = 0; i < k; i++) {
903             ((DebuggerManagerListener) l.elementAt (i)).initWatches ();
904             ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
905         }
906
907         Vector l1;
908         synchronized (listenersMap) {
909             l1 = (Vector) listenersMap.get (PROP_WATCHES_INIT);
910             if (l1 != null) {
911                 l1 = (Vector) l1.clone ();
912             }
913         }
914         if (l1 != null) {
915             k = l1.size ();
916             for (i = 0; i < k; i++) {
917                 ((DebuggerManagerListener) l1.elementAt (i)).initWatches ();
918                 ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
919             }
920         }
921     }
922
923     /**
924      * Notifies registered listeners about a change.
925      * Notifies {@link #listeners registered listeners} that a session
926      * {@link DebuggerManagerListener#sessionAdded was added}
927      * and its properties
928      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
929      * were changed.
930      *
931      * @param session a session that was created
932      */

933     private void fireSessionAdded (
934         final Session session,
935         final Session[] old,
936         final Session[] ne
937     ) {
938         initDebuggerManagerListeners ();
939         PropertyChangeEvent ev = new PropertyChangeEvent (
940             this, PROP_SESSIONS, old, ne
941         );
942         
943         Vector l = (Vector) listeners.clone ();
944         int i, k = l.size ();
945         for (i = 0; i < k; i++) {
946             ((DebuggerManagerListener) l.elementAt (i)).sessionAdded
947                 (session);
948             ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
949         }
950         
951         Vector l1;
952         synchronized (listenersMap) {
953             l1 = (Vector) listenersMap.get (PROP_SESSIONS);
954             if (l1 != null) {
955                 l1 = (Vector) l1.clone ();
956             }
957         }
958         if (l1 != null) {
959             k = l1.size ();
960             for (i = 0; i < k; i++) {
961                 ((DebuggerManagerListener) l1.elementAt (i)).sessionAdded
962                     (session);
963                 ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
964             }
965         }
966     }
967
968     /**
969      * Notifies registered listeners about a change.
970      * Notifies {@link #listeners registered listeners} that a session
971      * {@link DebuggerManagerListener#sessionRemoved was removed}
972      * and its properties
973      * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
974      * were changed.
975      *
976      * @param session a session that was removed
977      */

978     private void fireSessionRemoved (
979         final Session session,
980         final Session[] old,
981         final Session[] ne
982     ) {
983         initDebuggerManagerListeners ();
984         PropertyChangeEvent ev = new PropertyChangeEvent (
985             this, PROP_SESSIONS, old, ne
986         );
987
988         Vector l = (Vector) listeners.clone ();
989         int i, k = l.size ();
990         for (i = 0; i < k; i++) {
991             ((DebuggerManagerListener) l.elementAt (i)).sessionRemoved
992                 (session);
993             ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
994         }
995
996         Vector l1;
997         synchronized (listenersMap) {
998             l1 = (Vector) listenersMap.get (PROP_SESSIONS);
999             if (l1 != null) {
1000                l1 = (Vector) l1.clone ();
1001            }
1002        }
1003        if (l1 != null) {
1004            k = l1.size ();
1005            for (i = 0; i < k; i++) {
1006                ((DebuggerManagerListener) l1.elementAt (i)).sessionRemoved
1007                    (session);
1008                ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
1009            }
1010        }
1011    }
1012
1013    /**
1014     * Notifies registered listeners about a change.
1015     * Notifies {@link #listeners registered listeners} that a engine
1016     * {@link DebuggerManagerListener#engineAdded was added}
1017     * and its properties
1018     * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
1019     * were changed.
1020     *
1021     * @param engine a engine that was created
1022     */

1023    private void fireEngineAdded (
1024        final DebuggerEngine engine,
1025        final DebuggerEngine[] old,
1026        final DebuggerEngine[] ne
1027    ) {
1028        initDebuggerManagerListeners ();
1029        PropertyChangeEvent ev = new PropertyChangeEvent (
1030            this, PROP_DEBUGGER_ENGINES, old, ne
1031        );
1032        
1033        Vector l = (Vector) listeners.clone ();
1034        int i, k = l.size ();
1035        for (i = 0; i < k; i++) {
1036            ((DebuggerManagerListener) l.elementAt (i)).engineAdded
1037                (engine);
1038            ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
1039        }
1040        
1041        Vector l1;
1042        synchronized (listenersMap) {
1043            l1 = (Vector) listenersMap.get (PROP_DEBUGGER_ENGINES);
1044            if (l1 != null) {
1045                l1 = (Vector) l1.clone ();
1046            }
1047        }
1048        if (l1 != null) {
1049            k = l1.size ();
1050            for (i = 0; i < k; i++) {
1051                ((DebuggerManagerListener) l1.elementAt (i)).engineAdded
1052                    (engine);
1053                ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
1054            }
1055        }
1056    }
1057
1058    /**
1059     * Notifies registered listeners about a change.
1060     * Notifies {@link #listeners registered listeners} that a engine
1061     * {@link DebuggerManagerListener#engineRemoved was removed}
1062     * and its properties
1063     * {@link PropertyChangeSupport#firePropertyChange(PropertyChangeEvent)}
1064     * were changed.
1065     *
1066     * @param engine a engine that was removed
1067     */

1068    private void fireEngineRemoved (
1069        final DebuggerEngine engine,
1070        final DebuggerEngine[] old,
1071        final DebuggerEngine[] ne
1072    ) {
1073        initDebuggerManagerListeners ();
1074        PropertyChangeEvent ev = new PropertyChangeEvent (
1075            this, PROP_DEBUGGER_ENGINES, old, ne
1076        );
1077
1078        Vector l = (Vector) listeners.clone ();
1079        int i, k = l.size ();
1080        for (i = 0; i < k; i++) {
1081            ((DebuggerManagerListener) l.elementAt (i)).engineRemoved
1082                (engine);
1083            ((DebuggerManagerListener) l.elementAt (i)).propertyChange (ev);
1084        }
1085
1086        Vector l1;
1087        synchronized (listenersMap) {
1088            l1 = (Vector) listenersMap.get (PROP_DEBUGGER_ENGINES);
1089            if (l1 != null) {
1090                l1 = (Vector) l1.clone ();
1091            }
1092        }
1093        if (l1 != null) {
1094            k = l1.size ();
1095            for (i = 0; i < k; i++) {
1096                ((DebuggerManagerListener) l1.elementAt (i)).engineRemoved
1097                    (engine);
1098                ((DebuggerManagerListener) l1.elementAt (i)).propertyChange (ev);
1099            }
1100        }
1101    }
1102
1103    
1104    // helper methods ....................................................
1105

1106    private boolean listerersLoaded = false;
1107    
1108    private void initDebuggerManagerListeners () {
1109        synchronized (listenersMap) {
1110            if (listerersLoaded) return;
1111            listerersLoaded = true;
1112            List listenersMap = lookup.lookup (null, LazyDebuggerManagerListener.class);
1113            int i, k = listenersMap.size ();
1114            for (i = 0; i < k; i++) {
1115                LazyDebuggerManagerListener l = (LazyDebuggerManagerListener)
1116                    listenersMap.get (i);
1117                String JavaDoc[] props = l.getProperties ();
1118                if ((props == null) || (props.length == 0)) {
1119                    addDebuggerListener (l);
1120                    continue;
1121                }
1122                int j, jj = props.length;
1123                for (j = 0; j < jj; j++) {
1124                    addDebuggerListener (props [j], l);
1125                }
1126            }
1127        }
1128    }
1129    
1130    private void addSession (Session session) {
1131        Session[] oldSessions;
1132        Session[] newSessions;
1133        synchronized (sessions) {
1134            oldSessions = getSessions();
1135            int i, k = oldSessions.length;
1136            for (i = 0; i < k; i++)
1137                if (session == oldSessions[i]) return;
1138
1139            newSessions = new Session [oldSessions.length + 1];
1140            System.arraycopy (oldSessions, 0, newSessions, 0, oldSessions.length);
1141            newSessions[oldSessions.length] = session;
1142            this.sessions.add(session);
1143
1144            session.addPropertyChangeListener (sessionListener);
1145        }
1146        fireSessionAdded (session, oldSessions, newSessions);
1147    }
1148    
1149    private void removeSession (Session session) {
1150        Session[] oldSessions;
1151        Session[] newSessions;
1152        Session nCurrentSesson = null;
1153        synchronized (sessions) {
1154            oldSessions = getSessions();
1155            // find index of given debugger and new instance of currentDebugger
1156
int i, k = oldSessions.length;
1157            for (i = 0; i < k; i++) {
1158                if (oldSessions[i] == session) {
1159                    break;
1160                } else if (nCurrentSesson == null) {
1161                    nCurrentSesson = oldSessions[i];
1162                }
1163            }
1164            if (i == k) return; // this debugger is not registered
1165

1166            // set new current debugger session
1167
if (session == getCurrentSession ()) {
1168                if ((nCurrentSesson == null) && (k > 1))
1169                    nCurrentSesson = oldSessions[1];
1170            } else {
1171                nCurrentSesson = getCurrentSession();
1172            }
1173            
1174            newSessions = new Session [oldSessions.length - 1];
1175            System.arraycopy (oldSessions, 0, newSessions, 0, i);
1176            if ((oldSessions.length - i) > 1)
1177                System.arraycopy (
1178                    oldSessions, i + 1, newSessions, i, oldSessions.length - i - 1
1179                );
1180            sessions.remove(i);
1181            
1182            session.removePropertyChangeListener (sessionListener);
1183            // The current engine is set in setCurrentSession().
1184
}
1185        setCurrentSession (nCurrentSesson);
1186        fireSessionRemoved (session, oldSessions, newSessions);
1187    }
1188    
1189    void addEngine (DebuggerEngine engine) {
1190        DebuggerEngine[] old;
1191        DebuggerEngine[] ne;
1192        synchronized (engines) {
1193            if (engines.contains (engine)) return;
1194            old = (DebuggerEngine[]) engines.toArray (new DebuggerEngine [engines.size ()]);
1195            engines.add (engine);
1196            ne = (DebuggerEngine[]) engines.toArray (new DebuggerEngine [engines.size ()]);
1197        }
1198        fireEngineAdded (engine, old, ne);
1199    }
1200    
1201    void removeEngine (DebuggerEngine engine) {
1202        DebuggerEngine[] old;
1203        DebuggerEngine[] ne;
1204        synchronized (engines) {
1205            if (!engines.contains (engine)) return;
1206            old = (DebuggerEngine[]) engines.toArray (new DebuggerEngine [engines.size ()]);
1207            engines.remove (engine);
1208            ne = (DebuggerEngine[]) engines.toArray (new DebuggerEngine [engines.size ()]);
1209        }
1210        fireEngineRemoved (engine, old, ne);
1211    }
1212    
1213
1214    
1215    // innerclasses ............................................................
1216

1217    /**
1218     * Listens on all engines and sessions for:
1219     * current thread changes
1220     * start / finish of engines
1221     * last action
1222     * current engine
1223     */

1224    private class SessionListener implements PropertyChangeListener {
1225        public void propertyChange (PropertyChangeEvent e) {
1226            if (e.getSource () instanceof Session) {
1227                if ( (!e.getPropertyName ().equals
1228                      (Session.PROP_CURRENT_LANGUAGE)) &&
1229                     (!e.getPropertyName ().equals
1230                      (Session.PROP_SUPPORTED_LANGUAGES))
1231                ) return;
1232                // update the current engine
1233
DebuggerEngine oldEngine;
1234                DebuggerEngine newEngine;
1235                synchronized (sessions) {
1236                    oldEngine = currentEngine;
1237                    newEngine = null;
1238                    if (getCurrentSession () != null)
1239                        newEngine = getCurrentSession ().getCurrentEngine ();
1240                    currentEngine = newEngine;
1241                }
1242                if (newEngine != oldEngine) {
1243                    firePropertyChange (PROP_CURRENT_ENGINE, oldEngine, newEngine);
1244                }
1245                Session s = (Session) e.getSource ();
1246                if (s.getSupportedLanguages ().length == 0)
1247                    removeSession (s);
1248            }
1249        }
1250    }
1251}
1252
1253
Popular Tags