KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > xom > XOMObjectModel


1 package net.sf.saxon.xom;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.event.PipelineConfiguration;
5 import net.sf.saxon.event.Receiver;
6 import net.sf.saxon.expr.XPathContext;
7 import net.sf.saxon.om.*;
8 import net.sf.saxon.trans.DynamicError;
9 import net.sf.saxon.trans.XPathException;
10 import net.sf.saxon.value.Value;
11 import net.sf.saxon.value.SingletonNode;
12 import net.sf.saxon.value.SequenceExtent;
13 import nu.xom.Document;
14 import nu.xom.Node;
15
16 import javax.xml.transform.Result JavaDoc;
17 import javax.xml.transform.Source JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.HashSet JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.WeakHashMap JavaDoc;
22 import java.lang.reflect.Array JavaDoc;
23 import java.io.Serializable JavaDoc;
24
25
26
27 /**
28  * This interface must be implemented by any third-party object model that can
29  * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface).
30  * This implementation of the interface supports wrapping of JDOM Documents.
31  */

32
33 public class XOMObjectModel implements ExternalObjectModel, Serializable JavaDoc {
34
35     private transient WeakHashMap JavaDoc documentMap = new WeakHashMap JavaDoc(20);
36
37     public XOMObjectModel() {}
38
39      /**
40      * Test whether this object model recognizes a given node as one of its own
41      */

42
43     public boolean isRecognizedNode(Object JavaDoc object) {
44         return (object instanceof nu.xom.Node);
45     }
46
47     /**
48      * Test whether this object model recognizes a given class as representing a
49      * node in that object model. This method will generally be called at compile time.
50      *
51      * @param nodeClass A class that possibly represents nodes
52      * @return true if the class is used to represent nodes in this object model
53      */

54
55     public boolean isRecognizedNodeClass(Class JavaDoc nodeClass) {
56         return nu.xom.Node.class.isAssignableFrom(nodeClass);
57     }
58
59     /**
60      * Test whether this object model recognizes a given class as representing a
61      * list of nodes in that object model. This method will generally be called at compile time.
62      *
63      * @param nodeClass A class that possibly represents nodes
64      * @return true if the class is used to represent nodes in this object model
65      */

66
67     public boolean isRecognizedNodeListClass(Class JavaDoc nodeClass) {
68         return false;
69     }
70
71     /**
72      * Test whether this object model recognizes a particular kind of JAXP Result object,
73      * and if it does, return a Receiver that builds an instance of this data model from
74      * a sequence of events. If the Result is not recognised, return null.
75      */

76
77     public Receiver getDocumentBuilder(Result JavaDoc result) {
78         return null; //To change body of implemented methods use File | Settings | File Templates.
79
}
80
81     /**
82      * Test whether this object model recognizes a particular kind of JAXP Source object,
83      * and if it does, send the contents of the document to a supplied Receiver, and return true.
84      * Otherwise, return false.
85      */

86
87     public boolean sendSource(Source JavaDoc source, Receiver receiver, PipelineConfiguration pipe) throws XPathException {
88         return false; //To change body of implemented methods use File | Settings | File Templates.
89
}
90
91     /**
92      * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied
93      * source does not belong to this object model, return null
94      */

95
96     public NodeInfo unravel(Source JavaDoc source, Configuration config) {
97         return null; //To change body of implemented methods use File | Settings | File Templates.
98
}
99
100     /**
101      * Convert a Java object to an XPath value. If the supplied object is recognized as a representation
102      * of a value using this object model, the object model should convert the value to an XPath value
103      * and return this as the result. If not, it should return null. If the object is recognized but cannot
104      * be converted, an exception should be thrown
105      */

106
107     public Value convertObjectToXPathValue(Object JavaDoc object, Configuration config) throws XPathException {
108         if (object instanceof Node) {
109             return new SingletonNode(wrapNode((Node)object, config));
110         } else if (object instanceof Node[]) {
111             NodeInfo[] nodes = new NodeInfo[((Node[])object).length];
112             for (int i=0; i<nodes.length; i++) {
113                 nodes[i] = wrapNode(((Node[])object)[i], config);
114             }
115             return new SequenceExtent(nodes);
116         } else {
117             return null;
118         }
119     }
120
121     private synchronized NodeInfo wrapNode(Node node, Configuration config) {
122         if (documentMap == null) {
123             // happens after deserialization
124
documentMap = new WeakHashMap JavaDoc(20);
125         }
126         Document root = node.getDocument();
127         VirtualNode wrapper = (VirtualNode)documentMap.get(root);
128         if (wrapper == null) {
129             wrapper = new DocumentWrapper(root, "", config);
130             addToDocumentMap(root, (DocumentWrapper)wrapper);
131         }
132         return (((DocumentWrapper)wrapper).wrap(node));
133     }
134
135     /**
136      * Register a mapping from a XOM node to its wrapper. This is done only for the root node of a tree.
137      */

138
139     public synchronized void addToDocumentMap(Document doc, DocumentWrapper wrapper) {
140         if (documentMap == null) {
141             // happens after deserialization
142
documentMap = new WeakHashMap JavaDoc(20);
143         }
144         documentMap.put(doc, wrapper);
145     }
146
147     /**
148      * Convert an XPath value to an object in this object model. If the supplied value can be converted
149      * to an object in this model, of the specified class, then the conversion should be done and the
150      * resulting object returned. If the value cannot be converted, the method should return null. Note
151      * that the supplied class might be a List, in which case the method should inspect the contents of the
152      * Value to see whether they belong to this object model.
153      */

154
155     public Object JavaDoc convertXPathValueToObject(Value value, Class JavaDoc targetClass, XPathContext context)
156     throws XPathException {
157         // We accept the object if (a) the target class is Node or Node[],
158
// or (b) the supplied object is a node, or sequence of nodes, that wrap XOM nodes,
159
// provided that the target class is Object or a collection class
160
boolean requireXOM =
161                 (Node.class.isAssignableFrom(targetClass) ||
162                 (targetClass.isArray() && Node.class.isAssignableFrom(targetClass.getComponentType())));
163
164         // Note: we allow the declared type of the method argument to be a subclass of Node. If the actual
165
// node supplied is the wrong kind of node, this will result in a Java exception.
166

167         boolean allowXOM =
168                 (targetClass == Object JavaDoc.class || targetClass.isAssignableFrom(ArrayList JavaDoc.class) ||
169                 targetClass.isAssignableFrom(HashSet JavaDoc.class) ||
170                 (targetClass.isArray() && targetClass.getComponentType() == Object JavaDoc.class));
171         if (!(requireXOM || allowXOM)) {
172             return null;
173         }
174         List JavaDoc nodes = new ArrayList JavaDoc(20);
175
176         SequenceIterator iter = value.iterate(context);
177         while (true) {
178             Item item = iter.next();
179             if (item == null) {
180                 break;
181             }
182             if (item instanceof VirtualNode) {
183                 Object JavaDoc o = ((VirtualNode)item).getUnderlyingNode();
184                 if (o instanceof Node) {
185                     nodes.add(o);
186                 } else {
187                     if (requireXOM) {
188                         DynamicError err = new DynamicError("Extension function required class " + targetClass.getName() +
189                                 "; supplied value of class " + item.getClass().getName() +
190                                 " could not be converted");
191                         throw err;
192                     };
193                 }
194             } else if (requireXOM) {
195                 DynamicError err = new DynamicError("Extension function required class " + targetClass.getName() +
196                             "; supplied value of class " + item.getClass().getName() +
197                             " could not be converted");
198                 throw err;
199             } else {
200                 return null; // DOM Nodes are not actually required; let someone else try the conversion
201
}
202         }
203
204         if (nodes.size() == 0 && !requireXOM) {
205             return null; // empty sequence supplied - try a different mapping
206
}
207         if (Node.class.isAssignableFrom(targetClass)) {
208             if (nodes.size() != 1) {
209                 DynamicError err = new DynamicError("Extension function requires a single XOM Node" +
210                                 "; supplied value contains " + nodes.size() + " nodes");
211                 throw err;
212             }
213             return nodes.get(0);
214         } else if (targetClass.isArray() && Node.class.isAssignableFrom(targetClass.getComponentType())) {
215             Node[] array = (Node[])Array.newInstance(targetClass.getComponentType(), nodes.size());
216             nodes.toArray(array);
217             return array;
218         } else if (targetClass.isAssignableFrom(ArrayList JavaDoc.class)) {
219             return nodes;
220         } else if (targetClass.isAssignableFrom(HashSet JavaDoc.class)) {
221             return new HashSet JavaDoc(nodes);
222         } else {
223             // after all this work, give up
224
return null;
225         }
226     }
227
228     /**
229      * Wrap a document node in the external object model in a document wrapper that implements
230      * the Saxon DocumentInfo interface
231      * @param node a node (any node) in the third party document
232      * @param baseURI the base URI of the node (supply "" if unknown)
233      * @param config the Saxon configuration (which among other things provides access to the NamePool)
234      * @return the wrapper, which must implement DocumentInfo
235      */

236
237     public DocumentInfo wrapDocument(Object JavaDoc node, String JavaDoc baseURI, Configuration config) {
238         Document documentNode = ((Node)node).getDocument();
239         return new DocumentWrapper(documentNode, baseURI, config);
240     }
241
242     /**
243      * Wrap a node within the external object model in a node wrapper that implements the Saxon
244      * VirtualNode interface (which is an extension of NodeInfo)
245      * @param document the document wrapper, as a DocumentInfo object
246      * @param node the node to be wrapped. This must be a node within the document wrapped by the
247      * DocumentInfo provided in the first argument
248      * @return the wrapper for the node, as an instance of VirtualNode
249      */

250
251     public NodeInfo wrapNode(DocumentInfo document, Object JavaDoc node) {
252         if (!(node instanceof Node)) {
253             throw new IllegalArgumentException JavaDoc("Object to be wrapped is not a XOM Node: " + node.getClass());
254         }
255         return ((DocumentWrapper)document).wrap((Node)node);
256     }
257
258     /**
259      * Convert a sequence of values to a NODELIST, as defined in the JAXP XPath API spec. This method
260      * is used when the evaluate() request specifies the return type as NODELIST, regardless of the
261      * actual results of the expression. If the sequence contains things other than nodes, the fallback
262      * is to return the sequence as a Java List object. The method can return null to invoke fallback
263      * behaviour.
264      */

265
266     public Object JavaDoc convertToNodeList(SequenceExtent extent) {
267         return null;
268     }
269
270 }
271
272
273 //
274
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
275
// you may not use this file except in compliance with the License. You may obtain a copy of the
276
// License at http://www.mozilla.org/MPL/
277
//
278
// Software distributed under the License is distributed on an "AS IS" basis,
279
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
280
// See the License for the specific language governing rights and limitations under the License.
281
//
282
// The Original Code is: all this file.
283
//
284
// The Initial Developer of the Original Code is Michael H. Kay.
285
//
286
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
287
//
288
// Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping
289
// of extensions and mapping of null to empty sequence).
290
//
291
Popular Tags