KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > jdnc > markup > elem > ElementProxy


1 /*
2  * $Id: ElementProxy.java,v 1.5 2005/01/28 16:34:20 bino_george Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8 package org.jdesktop.jdnc.markup.elem;
9
10 /**
11  * Copyright (c) 2001-2003 eNode, Inc. All rights reserved.
12  */

13
14 import java.beans.Beans JavaDoc;
15 import java.beans.Expression JavaDoc;
16 import java.beans.Statement JavaDoc;
17
18 import java.net.URL JavaDoc;
19 import java.net.MalformedURLException JavaDoc;
20
21 import java.util.Map JavaDoc;
22 import java.util.Date JavaDoc;
23
24 import java.util.logging.Level JavaDoc;
25 import java.util.logging.Logger JavaDoc;
26
27 import org.w3c.dom.*;
28
29 import net.openmarkup.AttributeHandler;
30 import net.openmarkup.Attributes;
31 import net.openmarkup.ElementAssimilator;
32 import net.openmarkup.ElementHandler;
33 import net.openmarkup.ElementType;
34 import net.openmarkup.Env;
35 import net.openmarkup.ObjectRealizer;
36 import net.openmarkup.Realizable;
37 import net.openmarkup.Scribe;
38
39 // Exceptions and error handling stuff
40
import net.openmarkup.AssimilatorException;
41 import net.openmarkup.ApplierException;
42
43 import org.jdesktop.jdnc.markup.Namespace;
44 import org.jdesktop.jdnc.markup.RealizationUtils;
45
46 /**
47  * Represents an element node in a DOM without requiring the DOM implementation
48  * to be subclassed. This is important for JAXP version 1.2 and earlier, which
49  * effectively disables DOM subclassing in sandboxed code by not providing any
50  * way for such code to override the default document builder factory.
51  *
52  * @author Ramesh Gupta
53  * @author ???
54  */

55 public abstract class ElementProxy implements Realizable {
56
57     public static Realizable getRealizable(Element element) {
58     return RealizationUtils.getRealizable(element);
59     }
60
61     public static int getIndexWithinParent(Element element) {
62         Element parent = (Element) element.getParentNode();
63         NodeList siblings = parent.getChildNodes();
64         int elementIndex = -1;
65         int count = 0;
66         for (int i = 0; i < siblings.getLength(); i++) {
67             Node sibling = siblings.item(i);
68             if (sibling.getNodeType() == Node.ELEMENT_NODE) {
69                 if (element == sibling) {
70                     elementIndex = count;
71                     break;
72                 }
73                 count++;
74             }
75         }
76         return elementIndex;
77      }
78
79     /**
80      * Convenience method for getting a stored value on the ObjectRealizer.
81      */

82     public Object JavaDoc getORValue(Object JavaDoc key) {
83     // For Sun Object Realizer:
84
ObjectRealizer or = getObjectRealizer();
85     Object JavaDoc value = null;
86     try {
87         value = (new Expression JavaDoc(or, "getValue",
88                     new Object JavaDoc[] { key })).getValue();
89     } catch (Exception JavaDoc ex) {
90         throw new RuntimeException JavaDoc("Error getValue from ObjectRealizer " + key.toString(), ex);
91     }
92     return value;
93     }
94
95
96     /**
97      * Convenience method for setting a stored value on the ObjectRealizer.
98      */

99     public void putORValue(Object JavaDoc key, Object JavaDoc value) {
100     // For Sun Object Realizer:
101
ObjectRealizer or = getObjectRealizer();
102     try {
103         (new Statement JavaDoc(or, "putValue", new Object JavaDoc[] { key, value })).execute();
104     } catch (Exception JavaDoc ex) {
105         throw new RuntimeException JavaDoc("Error putValue from ObjectRealizer " + key.toString(), ex);
106     }
107     }
108
109     public ElementProxy(Element element, ElementType elementType) {
110         // Binding between the DOM element and this ElementRepresentation is
111
// immutable. Structural changes to the DOM, if any, must happen at the
112
// dom element level, not at the element representation level.
113
this.element = element; // immutable
114
this.elementType = elementType; // immutable
115

116         registerAttributeHandlers();
117         registerElementHandlers();
118     }
119
120     public ElementType getElementType() {
121         return elementType;
122     }
123
124     public ElementHandler getElementHandler(String JavaDoc namespaceURI, String JavaDoc elementName) {
125         Map JavaDoc handlerMap = getElementHandlerMap();
126         return handlerMap == null ? null : (ElementHandler) handlerMap.get(namespaceURI + ":" + elementName);
127     }
128
129     public AttributeHandler getAttributeHandler(String JavaDoc namespaceURI, String JavaDoc attrName) {
130         Map JavaDoc handlerMap = getAttributeHandlerMap();
131         return handlerMap == null ? null : (AttributeHandler) handlerMap.get(namespaceURI + ":" + attrName);
132     }
133
134     public Object JavaDoc getObject() {
135         if (object == null) {
136             // instantiate the object for this element
137
object = instantiate();
138             if (object != null) {
139                 Scribe.getLogger().fine("Object instantiated: " +
140                                         object.getClass().getName());
141             }
142             checkAttributes();
143
144             applyAttributesBefore();
145             assimilateChildren();
146             applyAttributesAfter();
147
148             if (object != null) {
149                 Scribe.getLogger().fine("Object Realized: " +
150                                         object.getClass().toString());
151             }
152         }
153         return object;
154     }
155
156     public String JavaDoc getObjectClassName() {
157         if (objectClassName == null) {
158             // Always call getDOMElement() instead of referring to element directly
159
Element domElement = getDOMElement();
160             // First try to get object class name from markup attribute
161
String JavaDoc name = domElement.getAttributeNS(Namespace.JDNC, Attributes.CLASS);
162             if (name.length() == 0) {
163                 // Try without namespace prefix
164
name = domElement.getAttribute(Attributes.CLASS);
165                 if (name.length() == 0) {
166                     // Couldn't find "class" attribute with or without namespace
167
name = getElementType().getObjectClassName();
168                 }
169             }
170             objectClassName = name;
171         }
172         return objectClassName;
173     }
174
175     protected Object JavaDoc instantiate() {
176         String JavaDoc className = elementType.getObjectClassName();
177         Object JavaDoc obj = null;
178         if (className != null) {
179             try {
180                 obj = Beans.instantiate(Env.getClassLoader(), className);
181             }
182             catch (Exception JavaDoc ex) {
183         logException("Error instantiatiating: " + className, ex);
184             }
185         }
186         return obj;
187     }
188
189     public Realizable getDelegate() {
190         return this; // place to plug-in external helper objects
191
}
192
193     public URL JavaDoc getResolvedURL(String JavaDoc uri) {
194     Document doc = getOwnerDocument();
195     if (doc instanceof net.openmarkup.Document) {
196         return ((net.openmarkup.Document)doc).getResolvedURL(uri);
197     }
198     return RealizationUtils.getResolvedURL(this, uri);
199     }
200
201     public ObjectRealizer getObjectRealizer() {
202     Document doc = getOwnerDocument();
203     if (doc instanceof net.openmarkup.Document) {
204         return ((net.openmarkup.Document)doc).getObjectRealizer();
205     }
206     return RealizationUtils.getObjectRealizer();
207     }
208
209     public Element getDOMElement() {
210         // Always access element through this method, even in this class.
211
// That keeps the door open for DOM element to be created lazily.
212
return element;
213     }
214
215     protected Map JavaDoc registerAttributeHandlers() {
216         // Nothing to register in base class; simply return the empty map
217
return getAttributeHandlerMap();
218     }
219
220     protected Map JavaDoc registerElementHandlers() {
221         // Nothing to register in base class; simply return the empty map
222
return getElementHandlerMap();
223     }
224
225     /**
226      * Checks the all the attributes on the current element to see
227      * if there are attribute handlers.
228      * Send a WARNING to the logger if any are missing.
229      */

230     protected void checkAttributes() {
231         if (hasAttributes() == false || getAttributes() == null) {
232             return;
233         }
234         NamedNodeMap map = getAttributes();
235         String JavaDoc localName;
236         for (int i = 0, length = map.getLength(); i < length; i++) {
237             Node node = map.item(i);
238             if (node != null) {
239                 localName = node.getLocalName();
240                 // xml:id should never produce a warning
241
// currently some documents do not declare usage of XML namespace,
242
// so we'll be forgiving for now and not check the namespace
243
if (!(localName.equals("id") /*&& /getNamespaceURI().equals(Namespace.XML)*/) &&
244                        (getAttributeHandler(getNamespaceURI(), localName) == null)) {
245                     StringBuffer JavaDoc details = new StringBuffer JavaDoc("\"");
246                     // RG: Fix for J2SE 5.0; Can't cascade append() calls because
247
// return type in StringBuffer and AbstractStringBuilder are different
248
try {
249                     details.append(localName);
250                     details.append('=');
251                     details.append(node.getNodeValue());
252                     details.append("\" on \"");
253                     details.append(getLocalName());
254                     details.append('"');
255                     }
256                     catch (Exception JavaDoc ex) { // RG: append(char) throws IOException in J2SE 5.0
257
Scribe.getLogger().warning("Unsupported attribute : " +
258                                                    details + "; DETAILS MIGHT BE INCOMPLETE.");
259                     }
260                     Scribe.getLogger().warning("Unsupported attribute : " +
261                                                details);
262                 }
263             }
264         }
265     }
266
267     /**
268      * Overriden in the subclass to apply attributes <i>before</i> the child
269      * elements are assimilated.
270      */

271     protected void applyAttributesBefore() {
272     }
273
274     /**
275      * Overriden in the subclass to apply attributes <i>after</i> the child
276      * elements are assimilated.
277      */

278     protected void applyAttributesAfter() {
279     }
280
281     protected void assimilateChildren() {
282         NodeList children = getChildNodes();
283         for (int i = 0; i < children.getLength(); i++) {
284             Node child = children.item(i);
285             if (child.getNodeType() == Node.ELEMENT_NODE) {
286                 Realizable realizableChild =
287                     ElementProxy.getRealizable( (Element) child);
288
289                 if (realizableChild != null) {
290                     realizableChild.getObject(); // get object before assimilating
291

292                     StringBuffer JavaDoc details = new StringBuffer JavaDoc("\"");
293                     // RG: Fix for J2SE 5.0; Can't cascade append() calls because
294
// return type in StringBuffer and AbstractStringBuilder are different
295
details.append(realizableChild.getLocalName());
296                     details.append("\" into \"");
297                     details.append(getLocalName());
298                     details.append("\"");
299
300                     try {
301                         // get the appropriate assimilator:
302
String JavaDoc nsURI = child.getNamespaceURI();
303                         String JavaDoc localName = child.getLocalName();
304                         ElementHandler handler = getElementHandler(nsURI,
305                             localName);
306                         if (handler != null) {
307                             ElementAssimilator assimilator = handler.
308                                 getElementAssimilator();
309                             assimilator.assimilate(this, realizableChild);
310
311                             Scribe.getLogger().fine("Element assimilated: " +
312                                 details);
313                         }
314                         else {
315                             Scribe.getLogger().warning(
316                                 "Element assimilator not found: " + details);
317                         }
318                     }
319                     catch (AssimilatorException ex) {
320                         logException(
321                             "AssimilatorException assimilating element: " +
322                             details, ex);
323                     }
324                     catch (Exception JavaDoc ex2) {
325                         logException("Exception assimilating element: " +
326                                      details, ex2);
327                     }
328                 }
329             }
330         }
331     }
332
333     protected void applyAttribute(String JavaDoc namespaceURI, String JavaDoc localName) {
334         String JavaDoc attrValue = getAttributeNSOptional(namespaceURI, localName);
335         if (attrValue.length() == 0) {
336             attrValue = getAttribute(localName); // Try without namespace prefix
337
}
338
339         if (attrValue.length() != 0) {
340             // Use both namespaceURI and localName when looking up handler!
341
AttributeHandler handler = getAttributeHandler(namespaceURI,
342                 localName);
343
344             StringBuffer JavaDoc details = new StringBuffer JavaDoc("\"");
345             // RG: Fix for J2SE 5.0; Can't cascade append() calls because
346
// return type in StringBuffer and AbstractStringBuilder are different
347
try {
348             details.append(localName);
349             details.append('=');
350             details.append(attrValue);
351             details.append("\" on \"");
352             details.append(getLocalName());
353             details.append('"');
354         }
355         catch (Exception JavaDoc ex) { // RG: append(char) throws IOException in J2SE 5.0
356
Scribe.getLogger().warning("Unsupported attribute : " +
357                                        details + "; DETAILS MIGHT BE INCOMPLETE.");
358         }
359
360             if (handler != null) {
361                 try {
362                     handler.getApplier().apply(this, namespaceURI, localName,
363                                                attrValue);
364
365                     Scribe.getLogger().fine("Attribute applied: " + details);
366                 }
367                 catch (ApplierException ex) {
368                     RealizationUtils.logException(
369                         "ApplierException applying attribute: " + details, ex);
370                 }
371                 catch (Exception JavaDoc ex2) {
372                     RealizationUtils.logException(
373                         "Exception applying attribute: " + details, ex2);
374                 }
375             }
376             else {
377                 Scribe.getLogger().warning("Unsupported attribute : " +
378                                            details);
379             }
380         }
381     }
382
383     /**
384      * Handles all exception information. This belongs in some sort of Utility class
385      * @throws RuntimeException if the exception represents an Error
386      */

387     protected void logException(String JavaDoc message, Exception JavaDoc ex) {
388         RealizationUtils.logException(message, ex);
389     }
390
391     /**
392      * Returns attribute with lax namespace lookup if attribute is not found in
393      * the specified namespace.
394      *
395      * @param nsURI
396      * @param localName
397      * @return attribute value if the specified attribute is present in this element
398      */

399     public String JavaDoc getAttributeNSOptional(String JavaDoc nsURI, String JavaDoc localName) {
400         // Always call getDOMElement() instead of referring to element directly
401
Element element = getDOMElement();
402         String JavaDoc value = null;
403
404         try {
405             element.getAttributeNS(nsURI, localName);
406         }
407         catch (NullPointerException JavaDoc ex) {
408             // Yes it's not good to catch an NPE but there seems to be a
409
// bug in the crimson parser in 1.4.2. Pehaps this will be
410
// fixed when deployed under xerces on 1.5
411
}
412         if (value == null || value.length() == 0) {
413             value = element.getAttribute(localName);
414         }
415         return value;
416     }
417
418     protected Map JavaDoc getAttributeHandlerMap() {
419         return null;
420     }
421
422     protected Map JavaDoc getElementHandlerMap() {
423         return null;
424     }
425
426     // ======================================================================
427
// W3C DOM Methods
428
// ======================================================================
429

430     public String JavaDoc getTagName() {
431         return getDOMElement().getTagName();
432     }
433
434     public String JavaDoc getAttribute(String JavaDoc name) {
435         return getDOMElement().getAttribute(name);
436     }
437
438     public void setAttribute(String JavaDoc name, String JavaDoc value) throws DOMException {
439         getDOMElement().setAttribute(name, value);
440     }
441
442     public void removeAttribute(String JavaDoc name) throws DOMException {
443         getDOMElement().removeAttribute(name);
444     }
445
446     public Attr getAttributeNode(String JavaDoc name) {
447         return getDOMElement().getAttributeNode(name);
448     }
449
450     public Attr setAttributeNode(Attr newAttr) throws DOMException {
451         return getDOMElement().setAttributeNode(newAttr);
452     }
453
454     public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
455         return getDOMElement().removeAttributeNode(oldAttr);
456     }
457
458     public NodeList getElementsByTagName(String JavaDoc name) {
459         return getDOMElement().getElementsByTagName(name);
460     }
461
462     public String JavaDoc getAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
463         return getDOMElement().getAttributeNS(namespaceURI, localName);
464     }
465
466     public void setAttributeNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName,
467                                String JavaDoc value) throws DOMException {
468         getDOMElement().setAttributeNS(namespaceURI, qualifiedName, value);
469     }
470
471     public void removeAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) throws
472         DOMException {
473         getDOMElement().removeAttributeNS(namespaceURI, localName);
474     }
475
476     public Attr getAttributeNodeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
477         return getDOMElement().getAttributeNodeNS(namespaceURI, localName);
478     }
479
480     public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
481         return getDOMElement().setAttributeNodeNS(newAttr);
482     }
483
484     public NodeList getElementsByTagNameNS(String JavaDoc namespaceURI,
485                                            String JavaDoc localName) {
486         return getDOMElement().getElementsByTagNameNS(namespaceURI, localName);
487     }
488
489     public boolean hasAttribute(String JavaDoc name) {
490         return getDOMElement().hasAttribute(name);
491     }
492
493     public boolean hasAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
494         return getDOMElement().hasAttributeNS(namespaceURI, localName);
495     }
496
497     public String JavaDoc getNodeName() {
498         return getDOMElement().getNodeName();
499     }
500
501     public String JavaDoc getNodeValue() throws DOMException {
502         return getDOMElement().getNodeValue();
503     }
504
505     public void setNodeValue(String JavaDoc nodeValue) throws DOMException {
506         getDOMElement().setNodeValue(nodeValue);
507     }
508
509     public short getNodeType() {
510         return getDOMElement().getNodeType();
511     }
512
513     public Node getParentNode() {
514         return getDOMElement().getParentNode();
515     }
516
517     public NodeList getChildNodes() {
518         return getDOMElement().getChildNodes();
519     }
520
521     public Node getFirstChild() {
522         return getDOMElement().getFirstChild();
523     }
524
525     public Node getLastChild() {
526         return getDOMElement().getLastChild();
527     }
528
529     public Node getPreviousSibling() {
530         return getDOMElement().getPreviousSibling();
531     }
532
533     public Node getNextSibling() {
534         return getDOMElement().getNextSibling();
535     }
536
537     public NamedNodeMap getAttributes() {
538         return getDOMElement().getAttributes();
539     }
540
541     public Document getOwnerDocument() {
542         return getDOMElement().getOwnerDocument();
543     }
544
545     public Node insertBefore(Node newChild, Node refChild) throws DOMException {
546         return getDOMElement().insertBefore(newChild, refChild);
547     }
548
549     public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
550         return getDOMElement().replaceChild(newChild, oldChild);
551     }
552
553     public Node removeChild(Node oldChild) throws DOMException {
554         return getDOMElement().removeChild(oldChild);
555     }
556
557     public Node appendChild(Node newChild) throws DOMException {
558         return getDOMElement().appendChild(newChild);
559     }
560
561     public boolean hasChildNodes() {
562         return getDOMElement().hasChildNodes();
563     }
564
565     public Node cloneNode(boolean deep) {
566         if (deep) {
567             /**@todo Implement deep cloneNode() method*/
568             throw new UnsupportedOperationException JavaDoc(
569                 "Method deep cloneNode() not yet implemented.");
570         }
571
572         return getDOMElement().cloneNode(false); // shallow clone
573
}
574
575     public void normalize() {
576         getDOMElement().normalize();
577     }
578
579     public boolean isSupported(String JavaDoc feature, String JavaDoc version) {
580         return getDOMElement().isSupported(feature, version);
581     }
582
583     public String JavaDoc getNamespaceURI() {
584         return getDOMElement().getNamespaceURI();
585     }
586
587     public String JavaDoc getPrefix() {
588         return getDOMElement().getPrefix();
589     }
590
591     public void setPrefix(String JavaDoc prefix) throws DOMException {
592         getDOMElement().setPrefix(prefix);
593     }
594
595     public String JavaDoc getLocalName() {
596         return getDOMElement().getLocalName();
597     }
598
599     public boolean hasAttributes() {
600         return getDOMElement().hasAttributes();
601     }
602
603     public String JavaDoc getBaseURI() {
604         return getDOMElement().getBaseURI();
605     }
606
607     public Object JavaDoc getFeature(String JavaDoc feature,
608                   String JavaDoc version) {
609         return getDOMElement().getFeature(feature, version);
610     }
611
612     public TypeInfo getSchemaTypeInfo() {
613         return getDOMElement().getSchemaTypeInfo();
614     }
615
616     public Object JavaDoc getUserData(String JavaDoc key) {
617         return getDOMElement().getUserData(key);
618     }
619
620     public Object JavaDoc setUserData(String JavaDoc key, Object JavaDoc data, UserDataHandler handler) {
621         return getDOMElement().setUserData(key, data, handler);
622     }
623
624     public boolean isDefaultNamespace(String JavaDoc namespaceURI) {
625         return getDOMElement().isDefaultNamespace(namespaceURI);
626     }
627
628     public boolean isEqualNode(Node arg) {
629         // @todo Test this!!!
630
try {
631             return getDOMElement().isEqualNode(((ElementProxy)arg).getDOMElement());
632         }
633         catch (Exception JavaDoc ex) {
634             return false;
635         }
636     }
637
638     public boolean isSameNode(Node arg) {
639         // @todo Test this!!!
640
try {
641             // When two Node references are references to the same object,
642
// EVEN IF THROUGH A PROXY, the references may be used interchangeably
643
// In other words, even if "this" and "arg" are different objects,
644
// they would be considerd SAME if their respective DOM elements
645
// return true for isSameNode() for each other.
646
return getDOMElement().isSameNode(((ElementProxy)arg).getDOMElement());
647         }
648         catch (Exception JavaDoc ex) {
649             return false;
650         }
651     }
652
653     public short compareDocumentPosition(Node other) throws DOMException {
654         // @todo Test this!!!
655
try {
656             return getDOMElement().compareDocumentPosition(((ElementProxy)other).getDOMElement());
657         }
658         catch (Exception JavaDoc ex) {
659             return 0;
660         }
661     }
662
663     public String JavaDoc lookupNamespaceURI(String JavaDoc prefix) {
664         return getDOMElement().lookupNamespaceURI(prefix);
665     }
666
667     public String JavaDoc lookupPrefix(String JavaDoc namespaceURI) {
668         return getDOMElement().lookupPrefix(namespaceURI);
669     }
670
671     public void setIdAttribute(String JavaDoc name, boolean isId) throws DOMException {
672         getDOMElement().setIdAttribute(name, isId);
673     }
674
675     public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
676         getDOMElement().setIdAttributeNode(idAttr, isId);
677     }
678
679     public void setIdAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName, boolean isId)
680         throws DOMException {
681         getDOMElement().setIdAttributeNS(namespaceURI, localName, isId);
682     }
683
684     public String JavaDoc getTextContent() throws DOMException {
685         return getDOMElement().getTextContent();
686     }
687
688     public void setTextContent(String JavaDoc textContent) throws DOMException {
689         getDOMElement().setTextContent(textContent);
690     }
691     
692     private final org.w3c.dom.Element JavaDoc element; // immutable
693
protected final ElementType elementType; // immutable
694
protected Object JavaDoc object = null; // realized object
695
protected String JavaDoc objectClassName = null;
696 }
697
Popular Tags