001: package org.obe.xpdl.model.data;
002:
003: import org.obe.XMLException;
004: import org.obe.util.AbstractBean;
005: import org.obe.util.W3CNames;
006: import org.w3c.dom.Document;
007: import org.w3c.dom.Element;
008: import org.w3c.dom.NamedNodeMap;
009: import org.w3c.dom.Node;
010: import org.xml.sax.InputSource;
011: import org.xml.sax.SAXException;
012:
013: import javax.xml.parsers.DocumentBuilder;
014: import javax.xml.parsers.DocumentBuilderFactory;
015: import javax.xml.parsers.ParserConfigurationException;
016: import javax.xml.transform.Transformer;
017: import javax.xml.transform.TransformerConfigurationException;
018: import javax.xml.transform.TransformerException;
019: import javax.xml.transform.TransformerFactory;
020: import javax.xml.transform.dom.DOMSource;
021: import javax.xml.transform.stream.StreamResult;
022: import java.io.IOException;
023: import java.io.StringReader;
024: import java.io.StringWriter;
025:
026: /**
027: * An abstract class that represents a fragment of an XML document.
028: *
029: * @author Adrian Price
030: */
031: public abstract class XMLFragment extends AbstractBean {
032: private static final long serialVersionUID = 3754638228659834894L;
033: public static final int MAX_TOSTRING_TEXT_LEN = 50;
034: private static final ThreadLocal _builderFactory = new ThreadLocal();
035:
036: private String _text;
037: private transient Document _document;
038:
039: private static DocumentBuilder getDocumentBuilder()
040: throws ParserConfigurationException {
041:
042: DocumentBuilderFactory dbf = (DocumentBuilderFactory) _builderFactory
043: .get();
044: if (dbf == null) {
045: dbf = DocumentBuilderFactory.newInstance();
046: _builderFactory.set(dbf);
047: }
048: return dbf.newDocumentBuilder();
049: }
050:
051: private static Transformer getTransformer()
052: throws TransformerConfigurationException {
053:
054: return TransformerFactory.newInstance().newTransformer();
055: }
056:
057: protected XMLFragment() {
058: }
059:
060: protected XMLFragment(String text) throws XMLException {
061: setText(text);
062: }
063:
064: protected XMLFragment(Document document) throws XMLException {
065: setDocument(document);
066: }
067:
068: /**
069: * Returns the unqualified name of the required document element.
070: *
071: * @return Unqualified element name.
072: */
073: protected abstract String getDocumentElementName();
074:
075: /**
076: * Returns the required document element namespace URI.
077: *
078: * @return Required namespace URI.
079: */
080: protected abstract String getDocumentElementNamespaceURI();
081:
082: public final String getText() {
083: return _text;
084: }
085:
086: public final void setText(String text) throws XMLException {
087: _text = text;
088: _document = null;
089: try {
090: getDocument();
091: checkDocument(_document);
092: } catch (XMLException e) {
093: _text = null;
094: _document = null;
095: throw e;
096: }
097: }
098:
099: public final Document getDocument() throws XMLException {
100: if (_document == null && _text != null) {
101: try {
102: _document = getDocumentBuilder().parse(
103: new InputSource(new StringReader(_text)));
104: } catch (ParserConfigurationException e) {
105: throw new XMLException(e);
106: } catch (SAXException e) {
107: throw new XMLException(e);
108: } catch (IOException e) {
109: throw new XMLException(e);
110: }
111: }
112: return _document;
113: }
114:
115: public final void setDocument(Document document)
116: throws XMLException {
117: try {
118: checkDocument(document);
119: if (document == null) {
120: _text = null;
121: } else {
122: StringWriter out = new StringWriter();
123: getTransformer().transform(new DOMSource(document),
124: new StreamResult(out));
125: _text = out.toString();
126: }
127: _document = document;
128: } catch (TransformerConfigurationException e) {
129: throw new XMLException(e);
130: } catch (TransformerException e) {
131: throw new XMLException(e);
132: }
133: }
134:
135: // Basic check that document element is correctly named.
136: private void checkDocument(Document document) throws XMLException {
137: if (document == null)
138: return;
139:
140: // Get actual document element name.
141: Element docElem = document.getDocumentElement();
142: String actName = docElem.getNodeName();
143:
144: // Get required document element name and namespace URI.
145: String reqNSURI = getDocumentElementNamespaceURI();
146: String reqName = getDocumentElementName();
147:
148: // Search namespace attributes for the required URI.
149: NamedNodeMap attrs = docElem.getAttributes();
150: for (int i = 0, n = attrs.getLength(); i < n; i++) {
151: Node attr = attrs.item(i);
152: // If this is the required URI...
153: if (attr.getNodeValue().equals(reqNSURI)) {
154: String attrName = attr.getNodeName();
155: // and it really is a namespace attribute...
156: if (attrName.startsWith(W3CNames.XMLNS_NS_PREFIX)) {
157: // extract the NS prefix (if any) and check doc. elem. name.
158: // (Use region matching to avoid object allocations.)
159: int index = attrName.length() - 6;
160: if (index == -1
161: && actName.equals(reqName)
162: || actName.regionMatches(0, attrName, 6,
163: index)
164: && actName.charAt(index) == ':'
165: && actName.regionMatches(index + 1,
166: reqName, 0, reqName.length())) {
167:
168: return;
169: }
170: }
171: }
172: }
173: throw new XMLException(new IllegalArgumentException(
174: "Document element must be '" + reqName
175: + "', in the namespace URI: " + reqNSURI));
176: }
177:
178: public boolean equals(Object obj) {
179: if (this == obj)
180: return true;
181: if (!(obj instanceof XMLFragment))
182: return false;
183:
184: XMLFragment xmlFragment = (XMLFragment) obj;
185: return !(_text != null ? !_text.equals(xmlFragment._text)
186: : xmlFragment._text != null);
187: }
188:
189: public int hashCode() {
190: return _text != null ? _text.hashCode() : 0;
191: }
192:
193: public final String toString() {
194: String className = getClass().getName();
195: return className.substring(className.lastIndexOf('.') + 1);
196: }
197: }
|