KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > debug > impl > RmiDebuggerService


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.debug.impl;
54
55 import java.io.Serializable JavaDoc;
56 import java.lang.ref.ReferenceQueue JavaDoc;
57 import java.lang.ref.WeakReference JavaDoc;
58 import java.rmi.RemoteException JavaDoc;
59 import java.rmi.server.RemoteObject JavaDoc;
60 import java.util.ArrayList JavaDoc;
61 import java.util.Collection JavaDoc;
62 import java.util.Collections JavaDoc;
63 import java.util.Enumeration JavaDoc;
64 import java.util.HashMap JavaDoc;
65 import java.util.HashSet JavaDoc;
66 import java.util.Iterator JavaDoc;
67 import java.util.List JavaDoc;
68 import java.util.Map JavaDoc;
69
70 import freemarker.core.DebugBreak;
71 import freemarker.core.Environment;
72 import freemarker.core.TemplateElement;
73 import freemarker.debug.Breakpoint;
74 import freemarker.debug.DebuggerListener;
75 import freemarker.debug.EnvironmentSuspendedEvent;
76 import freemarker.template.Template;
77 import freemarker.template.utility.UndeclaredThrowableException;
78
79 /**
80  * @author Attila Szegedi
81  * @version $Id
82  */

83 class RmiDebuggerService
84 extends
85     DebuggerService
86 {
87     private final Map JavaDoc templateDebugInfos = new HashMap JavaDoc();
88     private final HashSet JavaDoc suspendedEnvironments = new HashSet JavaDoc();
89     private final Map JavaDoc listeners = new HashMap JavaDoc();
90     private final ReferenceQueue JavaDoc refQueue = new ReferenceQueue JavaDoc();
91      
92     RmiDebuggerService()
93     {
94         try
95         {
96             new DebuggerServer((Serializable JavaDoc)RemoteObject.toStub(new RmiDebuggerImpl(this))).start();
97         }
98         catch(RemoteException JavaDoc e)
99         {
100             throw new UndeclaredThrowableException(e);
101         }
102     }
103     
104     List JavaDoc getBreakpointsSpi(String JavaDoc templateName)
105     {
106         synchronized(templateDebugInfos)
107         {
108             TemplateDebugInfo tdi = findTemplateDebugInfo(templateName);
109             return tdi == null ? Collections.EMPTY_LIST : tdi.breakpoints;
110         }
111     }
112
113     List JavaDoc getBreakpointsSpi()
114     {
115         List JavaDoc sumlist = new ArrayList JavaDoc();
116         synchronized(templateDebugInfos)
117         {
118             for (Iterator JavaDoc iter = templateDebugInfos.values().iterator(); iter.hasNext();)
119             {
120                 sumlist.addAll(((TemplateDebugInfo) iter.next()).breakpoints);
121             }
122         }
123         Collections.sort(sumlist);
124         return sumlist;
125     }
126
127     boolean suspendEnvironmentSpi(Environment env, int line)
128     throws
129         RemoteException JavaDoc
130     {
131         RmiDebuggedEnvironmentImpl denv =
132             (RmiDebuggedEnvironmentImpl)
133                 RmiDebuggedEnvironmentImpl.getCachedWrapperFor(env);
134                 
135         synchronized(suspendedEnvironments)
136         {
137             suspendedEnvironments.add(denv);
138         }
139         try
140         {
141             EnvironmentSuspendedEvent breakpointEvent =
142                 new EnvironmentSuspendedEvent(this, line, denv);
143     
144             synchronized(listeners)
145             {
146                 for (Iterator JavaDoc iter = listeners.values().iterator(); iter.hasNext();)
147                 {
148                     DebuggerListener listener = (DebuggerListener) iter.next();
149                     listener.environmentSuspended(breakpointEvent);
150                 }
151             }
152             synchronized(denv)
153             {
154                 try
155                 {
156                     denv.wait();
157                 }
158                 catch(InterruptedException JavaDoc e)
159                 {
160                     ;// Intentionally ignored
161
}
162             }
163             return denv.isStopped();
164         }
165         finally
166         {
167             synchronized(suspendedEnvironments)
168             {
169                 suspendedEnvironments.remove(denv);
170             }
171         }
172     }
173     
174     void registerTemplateSpi(Template template)
175     {
176         String JavaDoc templateName = template.getName();
177         synchronized(templateDebugInfos)
178         {
179             TemplateDebugInfo tdi = createTemplateDebugInfo(templateName);
180             tdi.templates.add(new TemplateReference(templateName, template, refQueue));
181             // Inject already defined breakpoints into the template
182
for (Iterator JavaDoc iter = tdi.breakpoints.iterator(); iter.hasNext();)
183             {
184                 Breakpoint breakpoint = (Breakpoint) iter.next();
185                 insertDebugBreak(template, breakpoint);
186             }
187         }
188     }
189     
190     Collection JavaDoc getSuspendedEnvironments()
191     {
192         return (Collection JavaDoc)suspendedEnvironments.clone();
193     }
194
195     Object JavaDoc addDebuggerListener(DebuggerListener listener)
196     {
197         Object JavaDoc id;
198         synchronized(listeners)
199         {
200             id = new Long JavaDoc(System.currentTimeMillis());
201             listeners.put(id, listener);
202         }
203         return id;
204     }
205     
206     void removeDebuggerListener(Object JavaDoc id)
207     {
208         synchronized(listeners)
209         {
210             listeners.remove(id);
211         }
212     }
213
214     void addBreakpoint(Breakpoint breakpoint)
215     {
216         String JavaDoc templateName = breakpoint.getTemplateName();
217         synchronized(templateDebugInfos)
218         {
219             TemplateDebugInfo tdi = createTemplateDebugInfo(templateName);
220             List JavaDoc breakpoints = tdi.breakpoints;
221             int pos = Collections.binarySearch(breakpoints, breakpoint);
222             if(pos < 0)
223             {
224                 // Add to the list of breakpoints
225
breakpoints.add(-pos - 1, breakpoint);
226                 // Inject the breakpoint into all templates with this name
227
for (Iterator JavaDoc iter = tdi.templates.iterator(); iter.hasNext();)
228                 {
229                     TemplateReference ref = (TemplateReference) iter.next();
230                     Template t = ref.getTemplate();
231                     if(t == null)
232                     {
233                         iter.remove();
234                     }
235                     else
236                     {
237                         insertDebugBreak(t, breakpoint);
238                     }
239                 }
240             }
241         }
242     }
243
244     private static void insertDebugBreak(Template t, Breakpoint breakpoint)
245     {
246         TemplateElement te = findTemplateElement(t.getRootTreeNode(), breakpoint.getLine());
247         if(te == null)
248         {
249             return;
250         }
251         TemplateElement parent = (TemplateElement)te.getParent();
252         DebugBreak db = new DebugBreak(te);
253         // TODO: Ensure there always is a parent by making sure
254
// that the root element in the template is always a MixedContent
255
// Also make sure it doesn't conflict with anyone's code.
256
parent.setChildAt(parent.getIndex(te), db);
257     }
258
259     private static TemplateElement findTemplateElement(TemplateElement te, int line)
260     {
261         if(te.getBeginLine() > line || te.getEndLine() < line)
262         {
263             return null;
264         }
265         // Find the narrowest match
266
for(Enumeration JavaDoc children = te.children(); children.hasMoreElements();)
267         {
268             TemplateElement child = (TemplateElement)children.nextElement();
269             TemplateElement childmatch = findTemplateElement(child, line);
270             if(childmatch != null)
271             {
272                 return childmatch;
273             }
274         }
275         // If no child provides narrower match, return this
276
return te;
277     }
278     
279     private TemplateDebugInfo findTemplateDebugInfo(String JavaDoc templateName)
280     {
281         processRefQueue();
282         return (TemplateDebugInfo)templateDebugInfos.get(templateName);
283     }
284     
285     private TemplateDebugInfo createTemplateDebugInfo(String JavaDoc templateName)
286     {
287         TemplateDebugInfo tdi = findTemplateDebugInfo(templateName);
288         if(tdi == null)
289         {
290             tdi = new TemplateDebugInfo();
291             templateDebugInfos.put(templateName, tdi);
292         }
293         return tdi;
294     }
295     
296     void removeBreakpoint(Breakpoint breakpoint)
297     {
298         String JavaDoc templateName = breakpoint.getTemplateName();
299         synchronized(templateDebugInfos)
300         {
301             TemplateDebugInfo tdi = findTemplateDebugInfo(templateName);
302             if(tdi != null)
303             {
304                 List JavaDoc breakpoints = tdi.breakpoints;
305                 int pos = Collections.binarySearch(breakpoints, breakpoint);
306                 if(pos >= 0)
307                 {
308                     breakpoints.remove(pos);
309                     for (Iterator JavaDoc iter = tdi.templates.iterator(); iter.hasNext();)
310                     {
311                         TemplateReference ref = (TemplateReference) iter.next();
312                         Template t = ref.getTemplate();
313                         if(t == null)
314                         {
315                             iter.remove();
316                         }
317                         else
318                         {
319                             removeDebugBreak(t, breakpoint);
320                         }
321                     }
322                 }
323                 if(tdi.isEmpty())
324                 {
325                     templateDebugInfos.remove(templateName);
326                 }
327             }
328         }
329     }
330
331     private void removeDebugBreak(Template t, Breakpoint breakpoint)
332     {
333         TemplateElement te = findTemplateElement(t.getRootTreeNode(), breakpoint.getLine());
334         if(te == null)
335         {
336             return;
337         }
338         DebugBreak db = null;
339         while(te != null)
340         {
341             if(te instanceof DebugBreak)
342             {
343                 db = (DebugBreak)te;
344                 break;
345             }
346             te = (TemplateElement)te.getParent();
347         }
348         if(db == null)
349         {
350             return;
351         }
352         TemplateElement parent = (TemplateElement)db.getParent();
353         parent.setChildAt(parent.getIndex(db), (TemplateElement)db.getChildAt(0));
354     }
355     
356     void removeBreakpoints(String JavaDoc templateName)
357     {
358         synchronized(templateDebugInfos)
359         {
360             TemplateDebugInfo tdi = findTemplateDebugInfo(templateName);
361             if(tdi != null)
362             {
363                 removeBreakpoints(tdi);
364                 if(tdi.isEmpty())
365                 {
366                     templateDebugInfos.remove(templateName);
367                 }
368             }
369         }
370     }
371
372     void removeBreakpoints()
373     {
374         synchronized(templateDebugInfos)
375         {
376             for (Iterator JavaDoc iter = templateDebugInfos.values().iterator(); iter.hasNext();)
377             {
378                 TemplateDebugInfo tdi = (TemplateDebugInfo) iter.next();
379                 removeBreakpoints(tdi);
380                 if(tdi.isEmpty())
381                 {
382                     iter.remove();
383                 }
384             }
385         }
386     }
387
388     private void removeBreakpoints(TemplateDebugInfo tdi)
389     {
390         tdi.breakpoints.clear();
391         for (Iterator JavaDoc iter = tdi.templates.iterator(); iter.hasNext();)
392         {
393             TemplateReference ref = (TemplateReference) iter.next();
394             Template t = ref.getTemplate();
395             if(t == null)
396             {
397                 iter.remove();
398             }
399             else
400             {
401                 removeDebugBreaks(t.getRootTreeNode());
402             }
403         }
404     }
405     
406     private void removeDebugBreaks(TemplateElement te)
407     {
408         int count = te.getChildCount();
409         for(int i = 0; i < count; ++i)
410         {
411             TemplateElement child = (TemplateElement)te.getChildAt(i);
412             while(child instanceof DebugBreak)
413             {
414                 TemplateElement dbchild = (TemplateElement)child.getChildAt(0);
415                 te.setChildAt(i, dbchild);
416                 child = dbchild;
417             }
418             removeDebugBreaks(child);
419         }
420     }
421     
422     private static final class TemplateDebugInfo
423     {
424         final List JavaDoc templates = new ArrayList JavaDoc();
425         final List JavaDoc breakpoints = new ArrayList JavaDoc();
426         
427         boolean isEmpty()
428         {
429             return templates.isEmpty() && breakpoints.isEmpty();
430         }
431     }
432     
433     private static final class TemplateReference extends WeakReference JavaDoc
434     {
435         final String JavaDoc templateName;
436          
437         TemplateReference(String JavaDoc templateName, Template template, ReferenceQueue JavaDoc queue)
438         {
439             super(template, queue);
440             this.templateName = templateName;
441         }
442         
443         Template getTemplate()
444         {
445             return (Template)get();
446         }
447     }
448     
449     private void processRefQueue()
450     {
451         for(;;)
452         {
453             TemplateReference ref = (TemplateReference)refQueue.poll();
454             if(ref == null)
455             {
456                 break;
457             }
458             TemplateDebugInfo tdi = findTemplateDebugInfo(ref.templateName);
459             if(tdi != null)
460             {
461                 tdi.templates.remove(ref);
462                 if(tdi.isEmpty())
463                 {
464                     templateDebugInfos.remove(ref.templateName);
465                 }
466             }
467         }
468     }
469 }
470
Popular Tags