KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > BridgeContext


1 /*
2
3    Copyright 2000-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.Cursor JavaDoc;
21 import java.awt.geom.Dimension2D JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InterruptedIOException JavaDoc;
24 import java.lang.ref.SoftReference JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedList JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.ListIterator JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36
37 import org.apache.batik.bridge.svg12.SVG12BridgeExtension;
38 import org.apache.batik.css.engine.CSSContext;
39 import org.apache.batik.css.engine.CSSEngine;
40 import org.apache.batik.css.engine.CSSEngineEvent;
41 import org.apache.batik.css.engine.CSSEngineListener;
42 import org.apache.batik.css.engine.CSSEngineUserAgent;
43 import org.apache.batik.css.engine.SVGCSSEngine;
44 import org.apache.batik.css.engine.SystemColorSupport;
45 import org.apache.batik.css.engine.value.Value;
46 import org.apache.batik.dom.svg.SVGContext;
47 import org.apache.batik.dom.svg.SVGDOMImplementation;
48 import org.apache.batik.dom.svg.SVGOMDocument;
49 import org.apache.batik.dom.svg.SVGOMElement;
50 import org.apache.batik.dom.svg.SVGStylableElement;
51 import org.apache.batik.gvt.CompositeGraphicsNode;
52 import org.apache.batik.gvt.GraphicsNode;
53 import org.apache.batik.gvt.TextPainter;
54 import org.apache.batik.script.Interpreter;
55 import org.apache.batik.script.InterpreterPool;
56 import org.apache.batik.util.CSSConstants;
57 import org.apache.batik.util.CleanerThread;
58 import org.apache.batik.util.ParsedURL;
59 import org.apache.batik.util.SVGConstants;
60 import org.apache.batik.util.Service;
61
62 import org.w3c.dom.Document JavaDoc;
63 import org.w3c.dom.Element JavaDoc;
64 import org.w3c.dom.Node JavaDoc;
65 import org.w3c.dom.events.Event JavaDoc;
66 import org.w3c.dom.events.EventListener JavaDoc;
67 import org.w3c.dom.events.EventTarget JavaDoc;
68 import org.w3c.dom.events.MouseEvent JavaDoc;
69 import org.w3c.dom.events.MutationEvent JavaDoc;
70 import org.w3c.dom.svg.SVGDocument;
71
72 /**
73  * This class represents a context used by the various bridges and the
74  * builder. A bridge context is associated to a particular document
75  * and cannot be reused.
76  *
77  * The context encapsulates the dynamic bindings between DOM elements
78  * and GVT nodes, graphic contexts such as a <tt>GraphicsNodeRenderContext</tt>,
79  * and the different objects required by the GVT builder to interpret
80  * a SVG DOM tree such as the current viewport or the user agent.
81  *
82  * @author <a HREF="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
83  * @version $Id: BridgeContext.java,v 1.83 2005/03/29 10:48:02 deweese Exp $
84  */

85 public class BridgeContext implements ErrorConstants, CSSContext {
86
87     /**
88      * The document is bridge context is dedicated to.
89      */

90     protected Document document;
91
92     /**
93      * The GVT builder that might be used to create a GVT subtree.
94      */

95     protected GVTBuilder gvtBuilder;
96
97     /**
98      * The interpreter cache per document.
99      * key is the language -
100      * value is a Interpreter
101      */

102     protected Map JavaDoc interpreterMap = new HashMap JavaDoc(7);
103
104     /**
105      * A Map of all the font families already matched. This is
106      * to reduce the number of instances of GVTFontFamilies and to
107      * hopefully reduce the time taken to search for a matching SVG font.
108      */

109     private Map JavaDoc fontFamilyMap;
110
111     /**
112      * The viewports.
113      * key is an Element -
114      * value is a Viewport
115      */

116     protected Map JavaDoc viewportMap = new WeakHashMap JavaDoc();
117
118     /**
119      * The viewport stack. Used in building time.
120      */

121     protected List JavaDoc viewportStack = new LinkedList JavaDoc();
122
123     /**
124      * The user agent.
125      */

126     protected UserAgent userAgent;
127
128     /**
129      * Binding Map:
130      * key is an SVG Element -
131      * value is a GraphicsNode
132      */

133     protected Map JavaDoc elementNodeMap;
134
135     /**
136      * Binding Map:
137      * key is GraphicsNode -
138      * value is a SVG Element.
139      */

140     protected Map JavaDoc nodeElementMap;
141
142     /**
143      * Bridge Map:
144      * Keys are namespace URI - values are HashMap (with keys are local
145      * name and values are a Bridge instance).
146      */

147     protected Map JavaDoc namespaceURIMap;
148
149     /**
150      * Element Data Map:
151      * This is a general location for elements to 'cache'
152      * data. Such as the graphics tree for a pattern or
153      * the Gradient arrays.
154      *
155      * This is a weak hash map and the data is referenced
156      * by SoftReference so both must be referenced elsewhere
157      * to stay live.
158      */

159     protected Map JavaDoc elementDataMap;
160
161
162     /**
163      * The interpreter pool used to handle scripts.
164      */

165     protected InterpreterPool interpreterPool;
166
167     /**
168      * The document loader used to load/create Document.
169      */

170     protected DocumentLoader documentLoader;
171
172     /**
173      * The size of the document.
174      */

175     protected Dimension2D JavaDoc documentSize;
176
177     /**
178      * The text painter to use. Typically, you can specify the text painter that
179      * will be used be text nodes.
180      */

181     protected TextPainter textPainter;
182
183     /**
184      * Indicates that no DOM listeners should be registered. In this
185      * case the generated GVT tree should be totally independent of
186      * the DOM tree (in practice text holds references to the source
187      * text elements for font resolution).
188      */

189     public final static int STATIC = 0;
190     /**
191      * Indicates that DOM listeners should be registered to support,
192      * 'interactivity' this includes anchors and cursors, but does not
193      * include support for DOM modifications.
194      */

195     public final static int INTERACTIVE = 1;
196
197     /**
198      * Indicates that all DOM listeners should be registered. This supports
199      * 'interactivity' (anchors and cursors), as well as DOM modifications
200      * listeners to update the GVT rendering tree.
201      */

202     public final static int DYNAMIC = 2;
203
204     /**
205      * Whether the bridge should support dynamic, or interactive features.
206      */

207     protected int dynamicStatus = STATIC;
208
209     /**
210      * The update manager.
211      */

212     protected UpdateManager updateManager;
213
214     /**
215      * Constructs a new empty bridge context.
216      */

217     protected BridgeContext() {}
218
219     /**
220      * By default we share a unique instance of InterpreterPool.
221      */

222     private static InterpreterPool sharedPool = new InterpreterPool();
223
224     /**
225      * Constructs a new bridge context.
226      * @param userAgent the user agent
227      */

228     public BridgeContext(UserAgent userAgent) {
229         this(userAgent,
230              sharedPool,
231              new DocumentLoader(userAgent));
232     }
233
234     /**
235      * Constructs a new bridge context.
236      * @param userAgent the user agent
237      * @param loader document loader
238      */

239     public BridgeContext(UserAgent userAgent,
240                          DocumentLoader loader) {
241         this(userAgent, sharedPool, loader);
242     }
243
244     /**
245      * Constructs a new bridge context.
246      * @param userAgent the user agent
247      * @param interpreterPool the interpreter pool
248      * @param documentLoader document loader
249      */

250     public BridgeContext(UserAgent userAgent,
251                          InterpreterPool interpreterPool,
252                          DocumentLoader documentLoader) {
253         this.userAgent = userAgent;
254         this.viewportMap.put(userAgent, new UserAgentViewport(userAgent));
255         this.interpreterPool = interpreterPool;
256         this.documentLoader = documentLoader;
257     }
258
259     /**
260      * Initializes the given document.
261      */

262     protected void initializeDocument(Document document) {
263         SVGOMDocument doc = (SVGOMDocument)document;
264         CSSEngine eng = doc.getCSSEngine();
265         if (eng == null) {
266             SVGDOMImplementation impl;
267             impl = (SVGDOMImplementation)doc.getImplementation();
268             eng = impl.createCSSEngine(doc, this);
269             eng.setCSSEngineUserAgent(new CSSEngineUserAgentWrapper(userAgent));
270             doc.setCSSEngine(eng);
271             eng.setMedia(userAgent.getMedia());
272             String JavaDoc uri = userAgent.getUserStyleSheetURI();
273             if (uri != null) {
274                 try {
275                     URL JavaDoc url = new URL JavaDoc(uri);
276                     eng.setUserAgentStyleSheet
277                         (eng.parseStyleSheet(url, "all"));
278                 } catch (MalformedURLException JavaDoc e) {
279                     userAgent.displayError(e);
280                 }
281             }
282             eng.setAlternateStyleSheet(userAgent.getAlternateStyleSheet());
283         }
284     }
285
286     /**
287      * Returns the CSS engine associated with given element.
288      */

289     public CSSEngine getCSSEngineForElement(Element e) {
290         SVGOMDocument doc = (SVGOMDocument)e.getOwnerDocument();
291         return doc.getCSSEngine();
292     }
293
294     // properties ////////////////////////////////////////////////////////////
295

296     /**
297      * Sets the text painter that will be used by text nodes. This attributes
298      * might be used by bridges (especially SVGTextElementBridge) to set the
299      * text painter of each TextNode.
300      *
301      * @param textPainter the text painter for text nodes
302      */

303     public void setTextPainter(TextPainter textPainter) {
304     this.textPainter = textPainter;
305     }
306
307     /**
308      * Returns the text painter that will be used be text nodes.
309      */

310     public TextPainter getTextPainter() {
311     return textPainter;
312     }
313
314     /**
315      * Returns the document this bridge context is dedicated to.
316      */

317     public Document getDocument() {
318         return document;
319     }
320
321     /**
322      * Sets the document this bridge context is dedicated to, to the
323      * specified document.
324      * @param document the document
325      */

326     protected void setDocument(Document document) {
327         if (this.document != document){
328             fontFamilyMap = null;
329         }
330         this.document = document;
331         registerSVGBridges();
332     }
333
334     /**
335      * Returns the map of font families
336      */

337     public Map JavaDoc getFontFamilyMap(){
338         if (fontFamilyMap == null){
339             fontFamilyMap = new HashMap JavaDoc();
340         }
341         return fontFamilyMap;
342     }
343
344     /**
345      * Sets the map of font families to the specified value.
346      *
347      *@param fontFamilyMap the map of font families
348      */

349     protected void setFontFamilyMap(Map JavaDoc fontFamilyMap) {
350         this.fontFamilyMap = fontFamilyMap;
351     }
352
353     /**
354      * Set Element Data.
355      * Associates data object with element so it can be
356      * retrieved later.
357      */

358     public void setElementData(Node n, Object JavaDoc data) {
359         if (elementDataMap == null)
360             elementDataMap = new WeakHashMap JavaDoc();
361         elementDataMap.put(n, new SoftReference JavaDoc(data));
362     }
363
364     /**
365      * Set Element Data.
366      * Associates data object with element so it can be
367      * retrieved later.
368      */

369     public Object JavaDoc getElementData(Node n) {
370         if (elementDataMap == null)
371             return null;
372         Object JavaDoc o = elementDataMap.get(n);
373         if (o == null) return null;
374         SoftReference JavaDoc sr = (SoftReference JavaDoc)o;
375         o = sr.get();
376         if (o == null) {
377             elementDataMap.remove(n);
378         }
379         return o;
380     }
381
382     /**
383      * Returns the user agent of this bridge context.
384      */

385     public UserAgent getUserAgent() {
386         return userAgent;
387     }
388
389     /**
390      * Sets the user agent to the specified user agent.
391      * @param userAgent the user agent
392      */

393     protected void setUserAgent(UserAgent userAgent) {
394         this.userAgent = userAgent;
395     }
396
397     /**
398      * Returns the GVT builder that is currently used to build the GVT tree.
399      */

400     public GVTBuilder getGVTBuilder() {
401         return gvtBuilder;
402     }
403
404     /**
405      * Sets the GVT builder that uses this context.
406      */

407     protected void setGVTBuilder(GVTBuilder gvtBuilder) {
408         this.gvtBuilder = gvtBuilder;
409     }
410
411     /**
412      * Returns the interpreter pool used to handle scripts.
413      */

414     public InterpreterPool getInterpreterPool() {
415         return interpreterPool;
416     }
417
418     /**
419      * Returns the focus manager.
420      */

421     public FocusManager getFocusManager() {
422         return focusManager;
423     }
424
425     /**
426      * Returns the cursor manager
427      */

428     public CursorManager getCursorManager() {
429         return cursorManager;
430     }
431
432     /**
433      * Sets the interpreter pool used to handle scripts to the
434      * specified interpreter pool.
435      * @param interpreterPool the interpreter pool
436      */

437     protected void setInterpreterPool(InterpreterPool interpreterPool) {
438         this.interpreterPool = interpreterPool;
439     }
440
441     /**
442      * Returns a Interpreter for the specified language.
443      *
444      * @param language the scripting language
445      */

446     public Interpreter getInterpreter(String JavaDoc language) {
447         if (document == null) {
448             throw new RuntimeException JavaDoc("Unknown document");
449         }
450         Interpreter interpreter = (Interpreter)interpreterMap.get(language);
451         if (interpreter == null) {
452             try {
453                 interpreter = interpreterPool.createInterpreter(document, language);
454                 interpreterMap.put(language, interpreter);
455             } catch (Exception JavaDoc e) {
456                 if (userAgent != null) {
457                     userAgent.displayError(e);
458                     return null;
459                 }
460             }
461         }
462
463         if (interpreter == null) {
464             if (userAgent != null) {
465                 userAgent.displayError(new Exception JavaDoc("Unknown language: " + language));
466             }
467         }
468
469         return interpreter;
470     }
471
472     /**
473      * Returns the document loader used to load external documents.
474      */

475     public DocumentLoader getDocumentLoader() {
476         return documentLoader;
477     }
478
479     /**
480      * Sets the document loader used to load external documents.
481      * @param newDocumentLoader the new document loader
482      */

483     protected void setDocumentLoader(DocumentLoader newDocumentLoader) {
484         this.documentLoader = newDocumentLoader;
485     }
486
487     /**
488      * Returns the actual size of the document or null if the document
489      * has not been built yet.
490      */

491     public Dimension2D JavaDoc getDocumentSize() {
492         return documentSize;
493     }
494
495     /**
496      * Sets the size of the document to the specified dimension.
497      *
498      * @param d the actual size of the SVG document
499      */

500     protected void setDocumentSize(Dimension2D JavaDoc d) {
501         this.documentSize = d;
502     }
503
504     /**
505      * Returns true if the document is dynamic, false otherwise.
506      */

507     public boolean isDynamic() {
508         return (dynamicStatus == DYNAMIC);
509     }
510
511     /**
512      * Returns true if the document is interactive, false otherwise.
513      */

514     public boolean isInteractive() {
515         return (dynamicStatus != STATIC);
516     }
517
518     /**
519      * Sets the document as a STATIC, INTERACTIVE or DYNAMIC document.
520      * Call this method before the build phase
521      * (ie. before <tt>gvtBuilder.build(...)</tt>)
522      * otherwise, that will have no effect.
523      *
524      *@param status the document dynamicStatus
525      */

526     public void setDynamicState(int status) {
527         dynamicStatus = status;
528     }
529
530     /**
531      * Sets the document as DYNAMIC if <tt>dynamic</tt> is true
532      * STATIC otherwise.
533      */

534     public void setDynamic(boolean dynamic) {
535         if (dynamic)
536             setDynamicState(DYNAMIC);
537         else
538             setDynamicState(STATIC);
539     }
540
541     /**
542      * Sets the document as INTERACTIVE if <tt>interactive</tt> is
543      * true STATIC otherwise.
544      */

545     public void setInteractive(boolean interactive) {
546         if (interactive)
547             setDynamicState(INTERACTIVE);
548         else
549             setDynamicState(STATIC);
550     }
551
552
553     /**
554      * Returns the update manager, if the bridge supports dynamic features.
555      */

556     public UpdateManager getUpdateManager() {
557         return updateManager;
558     }
559
560     /**
561      * Sets the update manager.
562      */

563     protected void setUpdateManager(UpdateManager um) {
564         updateManager = um;
565     }
566
567     // reference management //////////////////////////////////////////////////
568

569     /**
570      * Returns the element referenced by the specified element by the
571      * specified uri. The referenced element can not be a Document.
572      *
573      * @param e the element referencing
574      * @param uri the uri of the referenced element
575      */

576     public Element getReferencedElement(Element e, String JavaDoc uri) {
577         try {
578             SVGDocument document = (SVGDocument)e.getOwnerDocument();
579             URIResolver ur = new URIResolver(document, documentLoader);
580             Element ref = ur.getElement(uri, e);
581             if (ref == null) {
582                 throw new BridgeException(e, ERR_URI_BAD_TARGET,
583                                           new Object JavaDoc[] {uri});
584             } else {
585                 SVGOMDocument refDoc = (SVGOMDocument)ref.getOwnerDocument();
586                 // This is new rather than attaching this BridgeContext
587
// with the new document we now create a whole new
588
// BridgeContext to go with the new document.
589
// This means that the new document has it's own
590
// world of stuff and it should avoid memory leaks
591
// since the new document isn't 'tied into' this
592
// bridge context.
593
if (refDoc != document) {
594                     CSSEngine eng = refDoc.getCSSEngine();
595                     if (eng == null) {
596                         BridgeContext subCtx;
597                         subCtx = new BridgeContext(getUserAgent(),
598                                                    getDocumentLoader());
599                         subCtx.setGVTBuilder(getGVTBuilder());
600                         subCtx.setDocument(refDoc);
601                         subCtx.initializeDocument(refDoc);
602                     }
603                 }
604                 return ref;
605             }
606         } catch (MalformedURLException JavaDoc ex) {
607             throw new BridgeException(e, ERR_URI_MALFORMED,
608                                       new Object JavaDoc[] {uri});
609         } catch (InterruptedIOException JavaDoc ex) {
610             throw new InterruptedBridgeException();
611         } catch (IOException JavaDoc ex) {
612             throw new BridgeException(e, ERR_URI_IO,
613                                       new Object JavaDoc[] {uri});
614         } catch (IllegalArgumentException JavaDoc ex) {
615             throw new BridgeException(e, ERR_URI_REFERENCE_A_DOCUMENT,
616                                       new Object JavaDoc[] {uri});
617         } catch (SecurityException JavaDoc ex) {
618             throw new BridgeException(e, ERR_URI_UNSECURE,
619                                       new Object JavaDoc[] {uri});
620         }
621     }
622
623     // Viewport //////////////////////////////////////////////////////////////
624

625     /**
626      * Returns the viewport of the specified element.
627      *
628      * @param e the element interested in its viewport
629      */

630     public Viewport getViewport(Element e) {
631         if (viewportStack != null) {
632             // building time
633
if (viewportStack.size() == 0) {
634                 // outermost svg element
635
return (Viewport)viewportMap.get(userAgent);
636             } else {
637                 // current viewport
638
return (Viewport)viewportStack.get(0);
639             }
640         } else {
641             // search the first parent which has defined a viewport
642
e = SVGUtilities.getParentElement(e);
643             while (e != null) {
644                 Viewport viewport = (Viewport)viewportMap.get(e);
645                 if (viewport != null) {
646                     return viewport;
647                 }
648                 e = SVGUtilities.getParentElement(e);
649             }
650             return (Viewport)viewportMap.get(userAgent);
651         }
652     }
653
654     /**
655      * Starts a new viewport from the specified element.
656      *
657      * @param e the element that defines a new viewport
658      * @param viewport the viewport of the element
659      */

660     public void openViewport(Element e, Viewport viewport) {
661         viewportMap.put(e, viewport);
662         if (viewportStack == null) {
663             viewportStack = new LinkedList JavaDoc();
664         }
665         viewportStack.add(0, viewport);
666     }
667
668     public void removeViewport(Element e) {
669         viewportMap.remove(e);
670     }
671
672     /**
673      * Closes the viewport associated to the specified element.
674      * @param e the element that closes its viewport
675      */

676     public void closeViewport(Element e) {
677         //viewportMap.remove(e); FIXME: potential memory leak
678
viewportStack.remove(0);
679         if (viewportStack.size() == 0) {
680             viewportStack = null;
681         }
682     }
683
684     // Bindings //////////////////////////////////////////////////////////////
685

686     /**
687      * Binds the specified GraphicsNode to the specified Element. This method
688      * automatically bind the graphics node to the element and the element to
689      * the graphics node.
690      *
691      * @param element the element to bind to the specified graphics node
692      * @param node the graphics node to bind to the specified element
693      */

694     public void bind(Element element, GraphicsNode node) {
695         if (elementNodeMap == null) {
696             elementNodeMap = new WeakHashMap JavaDoc();
697             nodeElementMap = new WeakHashMap JavaDoc();
698         }
699         elementNodeMap.put(element, new SoftReference JavaDoc(node));
700         nodeElementMap.put(node, new SoftReference JavaDoc(element));
701     }
702
703     /**
704      * Removes the binding of the specified Element.
705      *
706      * @param element the element to unbind
707      */

708     public void unbind(Element element) {
709         if (elementNodeMap == null) {
710             return;
711         }
712         GraphicsNode node = null;
713         SoftReference JavaDoc sr = (SoftReference JavaDoc)elementNodeMap.get(element);
714         if (sr != null)
715             node = (GraphicsNode)sr.get();
716         elementNodeMap.remove(element);
717         if (node != null)
718             nodeElementMap.remove(node);
719     }
720
721     /**
722      * Returns the GraphicsNode associated to the specified Element or
723      * null if any.
724      *
725      * @param element the element associated to the graphics node to return
726      */

727     public GraphicsNode getGraphicsNode(Element element) {
728         if (elementNodeMap != null) {
729             SoftReference JavaDoc sr = (SoftReference JavaDoc)elementNodeMap.get(element);
730             if (sr != null)
731                 return (GraphicsNode)sr.get();
732         }
733         return null;
734     }
735
736     /**
737      * Returns the Element associated to the specified GraphicsNode or
738      * null if any.
739      *
740      * @param node the graphics node associated to the element to return
741      */

742     public Element getElement(GraphicsNode node) {
743         if (nodeElementMap != null) {
744             SoftReference JavaDoc sr = (SoftReference JavaDoc)nodeElementMap.get(node);
745             if (sr != null)
746                 return (Element)sr.get();
747         }
748         return null;
749     }
750
751     // Bridge management /////////////////////////////////////////////////////
752

753     /**
754      * Returns true if the specified element has a GraphicsNodeBridge
755      * associated to it, false otherwise.
756      *
757      * @param element the element
758      */

759     public boolean hasGraphicsNodeBridge(Element element) {
760         if (namespaceURIMap == null || element == null) {
761             return false;
762         }
763         String JavaDoc localName = element.getLocalName();
764         String JavaDoc namespaceURI = element.getNamespaceURI();
765         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
766         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
767         if (localNameMap == null) {
768             return false;
769         }
770         return (localNameMap.get(localName) instanceof GraphicsNodeBridge);
771     }
772
773     /**
774      * Returns the bridge associated with the specified element.
775      *
776      * @param element the element
777      */

778     public Bridge getBridge(Element element) {
779         if (namespaceURIMap == null || element == null) {
780             return null;
781         }
782         String JavaDoc localName = element.getLocalName();
783         String JavaDoc namespaceURI = element.getNamespaceURI();
784         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
785         return getBridge(namespaceURI, localName);
786     }
787
788     /**
789      * Returns the bridge associated with the element type
790      *
791      * @param namespaceURI namespace of the requested element
792      * @param localName element's local name
793      *
794      */

795     public Bridge getBridge(String JavaDoc namespaceURI, String JavaDoc localName) {
796         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
797         if (localNameMap == null) {
798             return null;
799         }
800         Bridge bridge = (Bridge)localNameMap.get(localName);
801         if (isDynamic()) {
802             return bridge == null ? null : bridge.getInstance();
803         } else {
804             return bridge;
805         }
806     }
807
808     /**
809      * Associates the specified <tt>Bridge</tt> object with the specified
810      * namespace URI and local name.
811      * @param namespaceURI the namespace URI
812      * @param localName the local name
813      * @param bridge the bridge that manages the element
814      */

815     public void putBridge(String JavaDoc namespaceURI, String JavaDoc localName, Bridge bridge) {
816         // start assert
817
if (!(namespaceURI.equals(bridge.getNamespaceURI())
818               && localName.equals(bridge.getLocalName()))) {
819             throw new Error JavaDoc("Invalid Bridge: "+
820                             namespaceURI+"/"+bridge.getNamespaceURI()+" "+
821                             localName+"/"+bridge.getLocalName()+" "+
822                             bridge.getClass());
823         }
824         // end assert
825
if (namespaceURIMap == null) {
826             namespaceURIMap = new HashMap JavaDoc();
827         }
828         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
829         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
830         if (localNameMap == null) {
831             localNameMap = new HashMap JavaDoc();
832             namespaceURIMap.put(namespaceURI, localNameMap);
833         }
834         localNameMap.put(localName, bridge);
835     }
836
837     /**
838      * Associates the specified <tt>Bridge</tt> object with it's
839      * namespace URI and local name.
840      *
841      * @param bridge the bridge that manages the element
842      */

843     public void putBridge(Bridge bridge) {
844         putBridge(bridge.getNamespaceURI(), bridge.getLocalName(), bridge);
845     }
846
847     /**
848      * Removes the <tt>Bridge</tt> object associated to the specified
849      * namespace URI and local name.
850      *
851      * @param namespaceURI the namespace URI
852      * @param localName the local name
853      */

854     public void removeBr