KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > core > comp > AbstractBComponent


1 /*
2  * Copyright (C) 2003 Christian Cryder [christianc@granitepeaks.com]
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: AbstractBComponent.java,v 1.32 2004/02/01 05:16:27 christianc Exp $
19  */

20 package org.enhydra.barracuda.core.comp;
21
22 import java.io.*;
23 import java.util.*;
24 import org.w3c.dom.*;
25 import org.w3c.dom.html.*;
26
27 import org.apache.log4j.*;
28
29 import org.enhydra.barracuda.core.util.dom.*;
30 import org.enhydra.barracuda.core.view.*;
31 import org.enhydra.barracuda.core.comp.renderer.*;
32 import org.enhydra.barracuda.plankton.*;
33 import org.enhydra.barracuda.plankton.data.*;
34
35 /**
36  * This class provides the abstract implementation for BComponent.
37  * Typically, however, you would extend from BComponent, not this class.
38  */

39 public abstract class AbstractBComponent implements BContainer, StateMap {
40
41     //public constants
42
protected static final Logger logger = Logger.getLogger(AbstractBComponent.class.getName());
43
44     //private constants
45
private static byte[] sep = System.getProperty("line.separator").getBytes();
46     private static Map rfCompMap = new HashMap();
47 // private static Map rfCompMap = new TreeMap();
48

49     //private vars
50
protected BContainer parent = null;
51     protected List children = new ArrayList();
52     protected List stepChildren = null;
53     protected boolean isStepChild = false;
54     protected List views = new ArrayList();
55     protected List tempViews = null;
56     protected Object JavaDoc dvc = null; //default view context (opt)
57

58     protected boolean validated = false;
59     protected StateMap statemap = new DefaultStateMap();
60
61
62     //--------------- AbstractBComponent -------------------------
63
public abstract void setName(String JavaDoc iname);
64     public abstract String JavaDoc getName();
65     public abstract void setVisible(boolean val);
66     public abstract void setVisible(boolean val, boolean recurse);
67     public abstract boolean isVisible();
68     public abstract void setEnabled(boolean val);
69     public abstract void setEnabled(boolean val, boolean recurse);
70     public abstract boolean isEnabled();
71     public abstract void setView(View view);
72     public abstract void addView(View view);
73     public abstract boolean removeView(View view);
74     public abstract void removeAllViews();
75     public abstract List getViews();
76     public abstract void setAttr(Object JavaDoc attr, Object JavaDoc val);
77     public abstract Object JavaDoc getAttr(Object JavaDoc attr);
78     public abstract Map getAttrMap();
79     public abstract void render(ViewContext vc) throws RenderException;
80     public abstract boolean supports(ViewContext vc);
81
82     /**
83      * Set the default ViewContext.
84      *
85      * @param idvc the default ViewContext
86      */

87     public void setDefaultViewContext(ViewContext idvc) {
88         dvc = idvc;
89     }
90
91     /**
92      * Get the default ViewContext.
93      *
94      * @return the default ViewContext
95      */

96     public ViewContext getDefaultViewContext() {
97         return (ViewContext) dvc;
98     }
99
100     public AbstractBComponent getRootComponent() {
101         if (parent!=null && parent instanceof AbstractBComponent) {
102             return ((AbstractBComponent) parent).getRootComponent();
103         } else {
104             return this;
105         }
106     }
107
108
109     //--------------- Renderer -----------------------------------
110
/**
111      * This allows developers to install custom renderers for specific
112      * classes of components. This should generally be done at startup.
113      *
114      * @param rf the RendererFactory to be registered
115      * @param compCl the target document class
116      * @param domCl the target dom class
117      */

118     public static void installRendererFactory(RendererFactory rf, Class JavaDoc compCl, Class JavaDoc domCl) {
119         if (logger.isInfoEnabled()) logger.info("Installing renderer factory for comp:"+compCl+" for dom:"+domCl);
120         synchronized (rfCompMap) {
121             Map rfDomMap = (Map) rfCompMap.get(compCl);
122             if (rfDomMap==null) {
123                 rfDomMap = new HashMap();
124 // rfDomMap = new TreeMap();
125
rfCompMap.put(compCl, rfDomMap);
126             }
127             synchronized (rfDomMap) {
128                 rfDomMap.put(domCl, rf);
129             }
130         }
131     }
132
133     /**
134      * This method allows a component to get a reference to the appropriate
135      * renderer. If an exact match does not exist, it will automatically
136      * look for renderers registered on parent classes.
137      */

138     public Renderer getRenderer(View view) throws NoSuitableRendererException {
139         Node node = view.getNode();
140         Class JavaDoc domCl = node.getClass();
141         return getRenderer(domCl);
142     }
143     
144     public Renderer getRenderer(Class JavaDoc domCl) throws NoSuitableRendererException {
145         Class JavaDoc cl = this.getClass();
146         boolean registered = true;
147         if (logger.isInfoEnabled()) logger.info("Looking up renderer factory for comp:"+cl+" for dom:"+domCl);
148         
149         //first try and find the dom map class
150
Map rfDomMap = (Map) rfCompMap.get(cl);
151         //..if it can't be located, look for the interfaces it implements
152
if (rfDomMap==null) {
153             List list = Classes.getAllInterfaces(domCl);
154             Iterator it = list.iterator();
155             while (it.hasNext()) {
156                 Class JavaDoc clint = (Class JavaDoc) it.next();
157                 if (logger.isDebugEnabled()) logger.debug("Looking for comp map interfaces:"+clint);
158                 rfDomMap = (Map) rfCompMap.get(clint);
159                 if (rfDomMap!=null) break;
160             }
161             registered = false;
162         }
163         //..if we still can't find it, look for parent classes
164
if (rfDomMap==null) {
165             if (logger.isDebugEnabled()) logger.debug("Looking for comp map superclass:"+cl.getSuperclass());
166             rfDomMap = findComponentMap(cl.getSuperclass());
167         }
168         if (rfDomMap==null) throw new NoSuitableRendererException("No renderer available for this component:"+cl);
169
170         //now look for the actual factory
171
RendererFactory rf = (RendererFactory) rfDomMap.get(domCl);
172         //..if it can't be located, look for the interfaces it implements
173
if (rf==null) {
174             List list = Classes.getAllInterfaces(domCl);
175             Iterator it = list.iterator();
176             while (it.hasNext()) {
177                 Class JavaDoc clint = (Class JavaDoc) it.next();
178                 if (logger.isDebugEnabled()) logger.debug("Looking for dom map interfaces:"+clint);
179                 rf = (RendererFactory) rfDomMap.get(clint);
180                 if (rf!=null) break;
181             }
182             registered = false;
183         }
184         //..if we still can't find it, look for parent classes
185
if (rf==null) {
186             if (logger.isDebugEnabled()) logger.debug("Looking for dom map superclass:"+domCl.getSuperclass());
187             rf = findRendererFactory(domCl.getSuperclass(), rfDomMap);
188         }
189         if (rf==null) throw new NoSuitableRendererException("No renderer available for this markup:"+domCl);
190
191         //if the particular combination was not registered, register it now
192
//so that the next time we look it up it'll be faster
193
if (!registered) installRendererFactory(rf, cl, domCl);
194
195         //return the renderer
196
return rf.getInstance();
197     }
198
199     /**
200      * Look for a factory that can render either this class or its parent
201      * class.
202      */

203     protected Map findComponentMap(Class JavaDoc cl) {
204         Map rfDomMap = (Map) rfCompMap.get(cl);
205         if (rfDomMap==null && cl.getSuperclass()!=null) {
206             rfDomMap = findComponentMap(cl.getSuperclass());
207         }
208         return rfDomMap;
209     }
210     
211     /**
212      * Look for a factory that can render either this class or its parent
213      * class.
214      */

215     protected RendererFactory findRendererFactory(Class JavaDoc cl, Map domMap) {
216         RendererFactory rf = (RendererFactory) domMap.get(cl);
217         if (rf==null && cl.getSuperclass()!=null) {
218             rf = findRendererFactory(cl.getSuperclass(), domMap);
219         }
220         return rf;
221     }
222
223     //--------------- Lifecycle ----------------------------------
224
/**
225      * Initialize cycle. The component should use this
226      * to perform any initialization. Note that the component
227      * should be added to the overall component hierarchy before
228      * you invoke this method.
229      */

230     public void initCycle() {
231         //initialize self
232

233         //initialize all children
234
if (children==null) children = new ArrayList();
235         Iterator it = children.iterator();
236         while (it.hasNext()) {
237             Object JavaDoc child = it.next();
238             if (child instanceof AbstractBComponent) ((AbstractBComponent) child).initCycle();
239         }
240     }
241     
242     /**
243      * Destroy cycle. The component should use this cycle to
244      * perform any special cleanup.
245      */

246     public void destroyCycle() {
247         //cleanup all children
248
if (children!=null) { //csc_031202.1 - added condition: only do this if children!=null
249
Iterator it = children.iterator();
250             while (it.hasNext()) {
251                 Object JavaDoc child = it.next();
252                 if (child instanceof AbstractBComponent) ((AbstractBComponent) child).destroyCycle();
253             }
254         }
255                     
256         //cleanup self
257
parent = null;
258         children = null;
259         views = null;
260         statemap = null; //csc_041202.1 - seems like this should be getting cleared too...
261
}
262
263
264
265
266     //--------------- BContainer ---------------------------------
267
/**
268      * Set the parent container. Null indicates its the root.
269      *
270      * @param iparent the parent container
271      */

272     public void setParent(BContainer iparent) {
273         parent = iparent;
274     }
275     
276     /**
277      * Get the parent container. Returns null if it's the root.
278      *
279      * @return the parent container
280      */

281     public BContainer getParent() {
282         return parent;
283     }
284     
285     /**
286      * Add a child container to this one
287      *
288      * @param child the child container to be added
289      */

290     public void addChild(BContainer child) {
291         //jrk_20021018.1 - added null check for children
292
if ((child==null) ||
293             (children!=null && children.contains(child))) return;
294         //jrk_20021018.2 - unnecessary code since this case was already checked.
295
/*if (children.contains(child)) {
296             if (logger.isDebugEnabled()) logger.debug(this.toRef()+": skipping addChild since child is already added");
297             return;
298         }*/

299         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding "+child);
300         //jrk_20021018.3 - added null check for children
301
if (children==null) children = new ArrayList();
302         children.add(child);
303         child.setParent(this);
304         invalidate();
305     }
306     
307     /**
308      * Get a child container at a given index
309      *
310      * @param index the index of the child container
311      */

312     public BContainer getChild(int index) {
313         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": getting idx:"+index);
314         return (BContainer) children.get(index);
315     }
316     
317     /**
318      * Remove a child container from this one
319      *
320      * @param child the a child container to be removed
321      * @return the child container that was removed
322      */

323     public BContainer removeChild(BContainer child) {
324         if (child==null) return null;
325         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": removing "+child);
326         return removeChild(children.indexOf(child));
327     }
328
329     /**
330      * Remove a child container for a given index
331      *
332      * @param index of the child container to be removed
333      * @return the child container that was removed
334      */

335     public BContainer removeChild(int index) {
336         if (index<0) return null;
337         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": removing idx:"+index);
338         BContainer child = (BContainer) children.remove(index);
339         child.setParent(null);
340         invalidate();
341         return child;
342     }
343
344     /**
345      * Remove all child containers from this one
346      */

347     public void removeAll() {
348         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": removing all children");
349         if (children!=null) children.clear();
350         invalidate();
351     }
352     
353     /**
354      * Determine whether this container has any children
355      *
356      * @return true if the container has child containers
357      */

358     public boolean hasChildren() {
359         return (children!=null && children.size()>0);
360     }
361
362     /**
363      * Gets a list of all child BContainers. Note, this method
364      * returns a copy of the underlying child list
365      *
366      * @return a list of all child components.
367      */

368     public List getChildren() {
369         return new ArrayList(children);
370     }
371
372     /**
373      * Determine whether this component is a step child
374      *
375      * @return true if this component is a step child
376      */

377     public boolean isStepChild() {
378         return isStepChild;
379     }
380     
381     /**
382      * Add a step child; step children are automatically removed after
383      * each render.
384      *
385      * @param child the step child container to be added
386      */

387     public void addStepChild(BContainer child) {
388         addStepChild(child, false);
389     }
390     
391     /**
392      * Add a step child; step children are automatically removed after
393      * each render.
394      *
395      * @param child the step child container to be added
396      * @param inheritParentAttrs true if we want the step child to
397      * inherit the parent's settings for visibility/enabled
398      */

399     public void addStepChild(BContainer child, boolean inheritParentAttrs) {
400         //jrk_20021018.4 - added null check for children
401
if ((child==null) ||
402             (stepChildren!=null && stepChildren.contains(child)) ||
403             (children!=null && children.contains(child))) return;
404         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding stepchild "+child);
405         this.addChild(child);
406         if (stepChildren==null) stepChildren = new ArrayList();
407         stepChildren.add(child);
408         
409         //csc_090501_start - the purpose of this fix is simple. When you add
410
//a step child, its almost always because you're delegating behaviour
411
//to a sub component. In these cases, that child's visibility/enabled
412
//characteristics should generally match the parent (so if the parent
413
//is disabled the child will be too).
414
if (child instanceof BComponent) {
415             BComponent chComp = (BComponent) child;
416             chComp.isStepChild = true;
417             if (inheritParentAttrs) {
418                 chComp.setVisible(this.isVisible());
419                 chComp.setEnabled(this.isEnabled());
420             }
421         }
422         //csc_090501_finish
423

424         //csc_041403.2 - added
425
//if the child being added has no views, add in any views/temp views
426
//associated with the parent
427
if (inheritParentAttrs && child instanceof BComponent) {
428             BComponent bchild = (BComponent) child;
429             if (!bchild.hasViews()) {
430                 Iterator it = getViews().iterator();
431                 while (it.hasNext()) {
432                     View v = (View) it.next();
433                     bchild.addView(v);
434                     if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding view to stepchild "+child);
435                 }
436                 if (tempViews!=null) {
437                     it = tempViews.iterator();
438                     while (it.hasNext()) {
439                         View v = (View) it.next();
440                         bchild.addTempView(v);
441                         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding tempview to stepchild "+child);
442                     }
443                 }
444             }
445         }
446     }
447     
448     /**
449      * Remove all step children
450      */

451     public void removeAllStepChildren() {
452         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": removing stepchildren");
453         if (stepChildren!=null) {
454             Iterator it = stepChildren.iterator();
455             while (it.hasNext()) {
456                 BContainer tempChild = (BContainer) it.next();
457                 if (logger.isDebugEnabled()) logger.debug(this.toRef()+": removing stepchild "+tempChild);
458                 
459                 //csc_030802.1 - if we are removing a temp child make sure we destroy it
460
//so that memory can get freed up. This bug reared its ugly head when I
461
//was using a BTemplateViewHandler that was declared as an inner class, and which
462
//used a model which itself was declared as an inner class of the view handler.
463
//After the BTemplate renders, when it goes to remove its step children, it
464
//must invoke destroyCycle on those or else they retain a reference to the
465
//BTemplate which prevents it from getting gc'd which in turn prevents the
466
//handler from getting gc'd which in turn runs you out of memory real fast on a
467
//big result set. Nasty nasty nasty!
468
if (tempChild instanceof BComponent) {
469                     ((BComponent) tempChild).destroyCycle();
470                 }
471                 
472 //csc_102401.1 - oh was this a brutal typo...caused all kinds of problems when
473
//you have a component hierarchy that was getting reused because the
474
//temp child was never getting removed.
475
// this.removeState(tempChild);
476
this.removeChild(tempChild);
477             }
478         }
479         stepChildren = null;
480     }
481     
482     /**
483      * Add a temporary view; temp views are automatically removed after
484      * each render
485      *
486      * @param tview the temp view to be added
487      */

488     public void addTempView(View tview) {
489         //jrk_20021018.5 - added null check for views
490
if ((tview==null) ||
491             (tempViews!=null && tempViews.contains(tview)) ||
492             (views!=null && views.contains(tview))) return;
493         if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding tempview "+tview);
494         if (tempViews==null) tempViews = new ArrayList();
495         tempViews.add(tview);
496         
497         //csc_041403.2 - added
498
//in addition, when we add a temp view, add it to any step children
499
//that do not have a view. This makes it MUCH easier for a template model
500
//to return nested components none of which may have a view yet...when
501
//TemplateHelper assigns a temp view, it will stick to step children as well
502
if (stepChildren!=null) {
503             Iterator it = stepChildren.iterator();
504             while (it.hasNext()) {
505                 BComponent tempChild = (BComponent) it.next();
506                 if (!tempChild.hasViews()) {
507                     if (logger.isDebugEnabled()) logger.debug(this.toRef()+": adding tempview to stepchild");
508                     tempChild.addTempView(tview);
509                 }
510             }
511         }
512     }
513     
514     /**
515      * Determine whether the component has any views (either regular or temp)
516      *
517      * @return true if the component has any views
518      */

519     public boolean hasViews() {
520         return ((views!=null && views.size()>0) ||
521                 (tempViews!=null && tempViews.size()>0));
522     }
523
524     /**
525      * Invalidates the container and all parent containers above it.
526      * This essentially indicates the components need to be laid out
527      * (in the server side world, this is equivalent to rendering)
528      * again. After a component has been rendered, it will be marked
529      * valid again.
530      */

531     public void invalidate() {
532         if (validated) {
533             validated = false;
534             if (getParent()!=null) getParent().invalidate();
535         }
536     }
537
538     /**
539      * Invalidates the container and all child containers below it.
540      * Calling validate on the root of a tree effectively invalidates
541      * the entire tree, forcing the whole tree to be revalidated the
542      * next time it is rendered. This call is more expensive than an
543      * invalidate because it has to hit every node in the hierarchy.
544      */

545     public void validate() {
546         validated = false;
547         Iterator it = children.iterator();
548         while (it.hasNext()) {
549             BContainer child = (BContainer) it.next();
550             child.validate();
551         }
552     }
553
554
555
556     //-------------------- StateMap ------------------------------
557
/**
558      * set a property in this StateMap
559      *
560      * @param key the state key object
561      * @param val the state value object
562      */

563     public void putState(Object JavaDoc key, Object JavaDoc val) {
564         statemap.putState(key,val);
565     }
566     
567     /**
568      * get a property in this StateMap
569      *
570      * @param key the state key object
571      * @return the value for the given key
572      */

573     public Object JavaDoc getState(Object JavaDoc key) {
574         return statemap.getState(key);
575     }
576     
577     /**
578      * remove a property in this StateMap
579      *
580      * @param key the key object
581      * @return the object which was removed
582      */

583     public Object JavaDoc removeState(Object JavaDoc key) {
584         return statemap.removeState(key);
585     }
586     
587     /**
588      * get a list of the keys for this StateMap
589      *
590      * @return a list the keys for this StateMap
591      */

592     public List getStateKeys() {
593         return statemap.getStateKeys();
594     }
595     
596     /**
597      * get a copy of the underlying Map
598      *
599      * @return a copy of the underlying state Map
600      */

601     public Map getStateValues() {
602         return statemap.getStateValues();
603     }
604
605     //csc_052803_2 - added
606
/**
607      * clear all state information
608      */

609     public void clearState() {
610         statemap.clearState();
611     }
612
613
614     //--------------- Utility Methods ----------------------------
615
/**
616      * Get the component reference
617      *
618      * @return a String representation of the component reference
619      */

620     public String JavaDoc toRef() {
621 //don't need the fully qualified class name since logger provides this
622
// return this.getClass().getName()+"@"+Integer.toHexString(this.hashCode());
623
return "[@"+Integer.toHexString(this.hashCode())+"]";
624     }
625     
626     /**
627      * Get a String representation of the component
628      *
629      * @return a String representation of the component
630      */

631     public String JavaDoc toString() {
632         return toString(getDefaultViewContext());
633     }
634     
635     /**
636      * Provide a String representation of the component. This will attempt to
637      * render the link as markup, which allows you to inline components along
638      * with text (a very useful feature!).
639      *
640      * @return a String representation of the component
641      */

642     public String JavaDoc toString(ViewContext vc) {
643         if (vc==null) {
644             String JavaDoc sname = getName();
645             if (sname==null) sname = this.getClass().getName();
646             int lpos = sname.lastIndexOf(".");
647             if (lpos>-1) sname = sname.substring(lpos);
648             return sname+" (@"+Integer.toHexString(this.hashCode())+")";
649         }
650
651         //get the format type and the doc from the view context
652
FormatType ft = vc.getViewCapabilities().getFormatType();
653         Document doc = vc.getElementFactory().getDocument();
654
655         //get any views associated with this link and then remove
656
//all views from the component
657
List linkViews = this.getViews();
658         this.removeAllViews();
659
660         try {
661             //get the appropriate renderer by looking up the
662
//DOM class associated with the given format type
663
Renderer r = this.getRenderer(ft.getDOMClass());
664
665 //csc_110501.1_start -
666
/*
667             //ask the renderer to create the default Node
668             Node n = r.createDefaultNode(doc, vc);
669             
670             //create a view on the resulting node and add it in
671             this.addTempView(new DefaultView(n));
672 */

673             //ask the renderer to create the default Node (Note that technically
674
//this is a dangerous cast, since it assumes that we are actually an
675
//instance of BComponent...in reality, its probably ok, since we are
676
//really only using AbstractBComponent for code hiding...if anyone
677
//extends Barracuda components, they should always do so by extending
678
//from BComponent, NOT by extending from AbstractBComponent. Unfortunately,
679
//there's no way to enforce this, but in practice it probably won't happen
680
//very often, if at all, and if it does, at least its well documented... ;-)
681
Node n = r.createDefaultNode(doc, (BComponent) this, vc); //csc_110501.1
682

683             //if the component still needs a default view create one for it...
684
if (!this.hasViews()) this.addTempView(new DefaultView(n));
685 //csc_110501.1_end
686

687             //invalidate the component to ensure redraw
688
this.invalidate();
689             
690             //now render the component
691
this.render(vc);
692             
693             //now render the node
694
StringWriter sw = new StringWriter(200);
695             DefaultDOMWriter ddw = new DefaultDOMWriter();
696             ddw.write(n, sw);
697             String JavaDoc linkStr = sw.toString();
698             String JavaDoc endln = System.getProperty("line.separator");
699             if (linkStr.endsWith(endln)) linkStr = linkStr.substring(0,linkStr.length()-endln.length());
700             return linkStr;
701                         
702         } catch (Exception JavaDoc e) {
703             return ("Err building component markup string: "+e);
704         } finally {
705             //add the views back in if need be (resetting component
706
//to original state)
707
if (linkViews!=null) {
708                 Iterator it = linkViews.iterator();
709                 while (it.hasNext()) {
710                     this.addView((View) it.next());
711                     if (validated) this.invalidate();
712                 }
713             }
714         }
715     }
716
717     public void printStackTrace(int depth, Logger logger) {
718         printStackTrace(depth, logger, null);
719     }
720     
721     public void printStackTrace(int depth, OutputStream out) {
722         printStackTrace(depth, null, out);
723     }
724     
725     /**
726      * For debugging purposes. Print the basic structure of the
727      * gateway.
728      */

729     protected void printStackTrace(int depth, Logger logger, OutputStream out) {
730         if (depth<0) depth = 0;
731         if (depth>25) depth = 25;
732         String JavaDoc spaces = " ";
733         String JavaDoc inset = spaces.substring(0,depth*3);
734         
735         boolean stepchild = (parent!=null &&
736                              ((AbstractBComponent) parent).stepChildren!=null &&
737                              ((AbstractBComponent) parent).stepChildren.contains(this));
738         print(logger, out, inset+this.getClass().getName() + "@" + Integer.toHexString(this.hashCode()) + (stepchild ? " (stepchild)" : ""));
739
740         //children
741
print(logger, out, inset+" children: "+(children==null ? "null" : ""));
742         int cntr = -1;
743         if (children!=null) {
744             Iterator it = children.iterator();
745             while (it.hasNext()) {
746                 BContainer cont = (BContainer) it.next();
747                 if (cont instanceof BComponent) {
748                     print(logger, out, inset+" ["+(++cntr)+"]:");
749                     ((BComponent) cont).printStackTrace(depth+2, logger, out);
750                 } else {
751                     print(logger, out, inset+" ["+(++cntr)+"]"+cont.getClass().getName()+" (details unknown)");
752                 }
753             }
754         }
755         print(logger, out, inset+" /end children");
756
757         print(logger, out, inset+"/end @" + Integer.toHexString(this.hashCode()));
758     }
759     
760     private static void print(Logger logger, OutputStream out, String JavaDoc s) {
761         if (logger!=null) {
762             logger.debug(s);
763         } else if (out!=null) {
764             try {
765                 out.write(s.getBytes());
766                 out.write(sep);
767             } catch (IOException ioe) {}
768         }
769     }
770
771
772 }
Popular Tags